Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

PostgreSQL Source Code git master
pg_test_timing.c
Go to the documentation of this file.
1/*
2 * pg_test_timing.c
3 * tests overhead of timing calls and their monotonicity: that
4 * they always move forward
5 */
6
7#include "postgres_fe.h"
8
9#include <limits.h>
10
11#include "getopt_long.h"
12#include "port/pg_bitutils.h"
14
15static const char *progname;
16
17static unsigned int test_duration = 3;
18static double max_rprct = 99.99;
19
20/* record duration in powers of 2 nanoseconds */
21static long long int histogram[32];
22
23/* record counts of first 10K durations directly */
24#define NUM_DIRECT 10000
25static long long int direct_histogram[NUM_DIRECT];
26
27/* separately record highest observed duration */
29static long long int largest_diff_count;
30
31
32static void handle_args(int argc, char *argv[]);
33static uint64 test_timing(unsigned int duration);
34static void output(uint64 loop_count);
35
36int
37main(int argc, char *argv[])
38{
39 uint64 loop_count;
40
41 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_test_timing"));
42 progname = get_progname(argv[0]);
43
44 handle_args(argc, argv);
45
46 loop_count = test_timing(test_duration);
47
48 output(loop_count);
49
50 return 0;
51}
52
53static void
54handle_args(int argc, char *argv[])
55{
56 static struct option long_options[] = {
57 {"duration", required_argument, NULL, 'd'},
58 {"cutoff", required_argument, NULL, 'c'},
59 {NULL, 0, NULL, 0}
60 };
61
62 int option; /* Command line option */
63 int optindex = 0; /* used by getopt_long */
64 unsigned long optval; /* used for option parsing */
65 char *endptr;
66
67 if (argc > 1)
68 {
69 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
70 {
71 printf(_("Usage: %s [-d DURATION] [-c CUTOFF]\n"), progname);
72 exit(0);
73 }
74 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
75 {
76 puts("pg_test_timing (PostgreSQL) " PG_VERSION);
77 exit(0);
78 }
79 }
80
81 while ((option = getopt_long(argc, argv, "d:c:",
82 long_options, &optindex)) != -1)
83 {
84 switch (option)
85 {
86 case 'd':
87 errno = 0;
88 optval = strtoul(optarg, &endptr, 10);
89
90 if (endptr == optarg || *endptr != '\0' ||
91 errno != 0 || optval != (unsigned int) optval)
92 {
93 fprintf(stderr, _("%s: invalid argument for option %s\n"),
94 progname, "--duration");
95 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
96 exit(1);
97 }
98
99 test_duration = (unsigned int) optval;
100 if (test_duration == 0)
101 {
102 fprintf(stderr, _("%s: %s must be in range %u..%u\n"),
103 progname, "--duration", 1, UINT_MAX);
104 exit(1);
105 }
106 break;
107
108 case 'c':
109 errno = 0;
110 max_rprct = strtod(optarg, &endptr);
111
112 if (endptr == optarg || *endptr != '\0' || errno != 0)
113 {
114 fprintf(stderr, _("%s: invalid argument for option %s\n"),
115 progname, "--cutoff");
116 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
117 exit(1);
118 }
119
120 if (max_rprct < 0 || max_rprct > 100)
121 {
122 fprintf(stderr, _("%s: %s must be in range %u..%u\n"),
123 progname, "--cutoff", 0, 100);
124 exit(1);
125 }
126 break;
127
128 default:
129 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
130 progname);
131 exit(1);
132 break;
133 }
134 }
135
136 if (argc > optind)
137 {
138 fprintf(stderr,
139 _("%s: too many command-line arguments (first is \"%s\")\n"),
140 progname, argv[optind]);
141 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
142 progname);
143 exit(1);
144 }
145
146 printf(ngettext("Testing timing overhead for %u second.\n",
147 "Testing timing overhead for %u seconds.\n",
150}
151
152static uint64
154{
155 uint64 total_time;
156 int64 time_elapsed = 0;
157 uint64 loop_count = 0;
158 uint64 prev,
159 cur;
161 end_time,
162 temp;
163
164 /*
165 * Pre-zero the statistics data structures. They're already zero by
166 * default, but this helps bring them into processor cache and avoid
167 * possible timing glitches due to COW behavior.
168 */
169 memset(direct_histogram, 0, sizeof(direct_histogram));
170 memset(histogram, 0, sizeof(histogram));
171 largest_diff = 0;
173
174 total_time = duration > 0 ? duration * INT64CONST(1000000000) : 0;
175
178
179 while (time_elapsed < total_time)
180 {
181 int32 diff,
182 bits;
183
184 prev = cur;
187 diff = cur - prev;
188
189 /* Did time go backwards? */
190 if (unlikely(diff < 0))
191 {
192 fprintf(stderr, _("Detected clock going backwards in time.\n"));
193 fprintf(stderr, _("Time warp: %d ms\n"), diff);
194 exit(1);
195 }
196
197 /* What is the highest bit in the time diff? */
198 if (diff > 0)
199 bits = pg_leftmost_one_pos32(diff) + 1;
200 else
201 bits = 0;
202
203 /* Update appropriate duration bucket */
204 histogram[bits]++;
205
206 /* Update direct histogram of time diffs */
207 if (diff < NUM_DIRECT)
208 direct_histogram[diff]++;
209
210 /* Also track the largest observed duration, even if >= NUM_DIRECT */
211 if (diff > largest_diff)
212 {
213 largest_diff = diff;
215 }
216 else if (diff == largest_diff)
218
219 loop_count++;
221 time_elapsed = INSTR_TIME_GET_NANOSEC(temp);
222 }
223
225
227
228 printf(_("Average loop time including overhead: %0.2f ns\n"),
229 INSTR_TIME_GET_DOUBLE(end_time) * 1e9 / loop_count);
230
231 return loop_count;
232}
233
234static void
235output(uint64 loop_count)
236{
237 int max_bit = 31;
238 const char *header1 = _("<= ns");
239 const char *header1b = _("ns");
240 const char *header2 = /* xgettext:no-c-format */ _("% of total");
241 const char *header3 = /* xgettext:no-c-format */ _("running %");
242 const char *header4 = _("count");
243 int len1 = strlen(header1);
244 int len2 = strlen(header2);
245 int len3 = strlen(header3);
246 int len4 = strlen(header4);
247 double rprct;
248 bool stopped = false;
249
250 /* find highest bit value */
251 while (max_bit > 0 && histogram[max_bit] == 0)
252 max_bit--;
253
254 /* set minimum column widths */
255 len1 = Max(8, len1);
256 len2 = Max(10, len2);
257 len3 = Max(10, len3);
258 len4 = Max(10, len4);
259
260 printf(_("Histogram of timing durations:\n"));
261 printf("%*s %*s %*s %*s\n",
262 len1, header1,
263 len2, header2,
264 len3, header3,
265 len4, header4);
266
267 rprct = 0;
268 for (int i = 0; i <= max_bit; i++)
269 {
270 double prct = (double) histogram[i] * 100 / loop_count;
271
272 rprct += prct;
273 printf("%*ld %*.4f %*.4f %*lld\n",
274 len1, (1L << i) - 1,
275 len2, prct,
276 len3, rprct,
277 len4, histogram[i]);
278 }
279
280 printf(_("\nObserved timing durations up to %.4f%%:\n"), max_rprct);
281 printf("%*s %*s %*s %*s\n",
282 len1, header1b,
283 len2, header2,
284 len3, header3,
285 len4, header4);
286
287 rprct = 0;
288 for (int i = 0; i < NUM_DIRECT; i++)
289 {
290 if (direct_histogram[i])
291 {
292 double prct = (double) direct_histogram[i] * 100 / loop_count;
293 bool print_it = !stopped;
294
295 rprct += prct;
296
297 /* if largest diff is < NUM_DIRECT, be sure we print it */
298 if (i == largest_diff)
299 {
300 if (stopped)
301 printf("...\n");
302 print_it = true;
303 }
304
305 if (print_it)
306 printf("%*d %*.4f %*.4f %*lld\n",
307 len1, i,
308 len2, prct,
309 len3, rprct,
310 len4, direct_histogram[i]);
311 if (rprct >= max_rprct)
312 stopped = true;
313 }
314 }
315
316 /* print largest diff when it's outside the array range */
318 {
319 double prct = (double) largest_diff_count * 100 / loop_count;
320
321 printf("...\n");
322 printf("%*d %*.4f %*.4f %*lld\n",
323 len1, largest_diff,
324 len2, prct,
325 len3, 100.0,
326 len4, largest_diff_count);
327 }
328}
#define INT64CONST(x)
Definition: c.h:553
#define ngettext(s, p, n)
Definition: c.h:1181
#define Max(x, y)
Definition: c.h:998
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1214
int64_t int64
Definition: c.h:536
int32_t int32
Definition: c.h:535
uint64_t uint64
Definition: c.h:540
#define unlikely(x)
Definition: c.h:403
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:429
#define fprintf(file, fmt, msg)
Definition: cubescan.l:21
struct cursor * cur
Definition: ecpg.c:29
#define _(x)
Definition: elog.c:91
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:60
#define required_argument
Definition: getopt_long.h:26
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:122
#define INSTR_TIME_GET_NANOSEC(t)
Definition: instr_time.h:125
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:188
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:181
int i
Definition: isn.c:77
static int pg_leftmost_one_pos32(uint32 word)
Definition: pg_bitutils.h:41
static time_t start_time
Definition: pg_ctl.c:95
PGDLLIMPORT int optind
Definition: getopt.c:51
PGDLLIMPORT char * optarg
Definition: getopt.c:53
int main(int argc, char *argv[])
static void output(uint64 loop_count)
static long long int histogram[32]
static int32 largest_diff
static void handle_args(int argc, char *argv[])
static long long int largest_diff_count
static double max_rprct
#define NUM_DIRECT
static uint64 test_timing(unsigned int duration)
static const char * progname
static unsigned int test_duration
static long long int direct_histogram[NUM_DIRECT]
static int64 end_time
Definition: pgbench.c:176
static int duration
Definition: pgbench.c:175
const char * get_progname(const char *argv0)
Definition: path.c:652
#define printf(...)
Definition: port.h:245