]> granicus.if.org Git - postgresql/blob - contrib/pg_test_timing/pg_test_timing.c
Correctly handle test durations of more than 2147s in pg_test_timing.
[postgresql] / contrib / pg_test_timing / pg_test_timing.c
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 "getopt_long.h"
10 #include "portability/instr_time.h"
11
12 static const char *progname;
13
14 static int32 test_duration = 3;
15
16 static void handle_args(int argc, char *argv[]);
17 static uint64 test_timing(int32);
18 static void output(uint64 loop_count);
19
20 /* record duration in powers of 2 microseconds */
21 int64           histogram[32];
22
23 int
24 main(int argc, char *argv[])
25 {
26         uint64          loop_count;
27
28         progname = get_progname(argv[0]);
29
30         handle_args(argc, argv);
31
32         loop_count = test_timing(test_duration);
33
34         output(loop_count);
35
36         return 0;
37 }
38
39 static void
40 handle_args(int argc, char *argv[])
41 {
42         static struct option long_options[] = {
43                 {"duration", required_argument, NULL, 'd'},
44                 {NULL, 0, NULL, 0}
45         };
46
47         int                     option;                 /* Command line option */
48         int                     optindex = 0;   /* used by getopt_long */
49
50         if (argc > 1)
51         {
52                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
53                 {
54                         printf("Usage: %s [-d DURATION]\n", progname);
55                         exit(0);
56                 }
57                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
58                 {
59                         puts("pg_test_timing (PostgreSQL) " PG_VERSION);
60                         exit(0);
61                 }
62         }
63
64         while ((option = getopt_long(argc, argv, "d:",
65                                                                  long_options, &optindex)) != -1)
66         {
67                 switch (option)
68                 {
69                         case 'd':
70                                 test_duration = atoi(optarg);
71                                 break;
72
73                         default:
74                                 fprintf(stderr, "Try \"%s --help\" for more information.\n",
75                                                 progname);
76                                 exit(1);
77                                 break;
78                 }
79         }
80
81         if (argc > optind)
82         {
83                 fprintf(stderr,
84                                 "%s: too many command-line arguments (first is \"%s\")\n",
85                                 progname, argv[optind]);
86                 fprintf(stderr, "Try \"%s --help\" for more information.\n",
87                                 progname);
88                 exit(1);
89         }
90
91         if (test_duration > 0)
92         {
93                 printf("Testing timing overhead for %d seconds.\n", test_duration);
94         }
95         else
96         {
97                 fprintf(stderr,
98                         "%s: duration must be a positive integer (duration is \"%d\")\n",
99                                 progname, test_duration);
100                 fprintf(stderr, "Try \"%s --help\" for more information.\n",
101                                 progname);
102                 exit(1);
103         }
104 }
105
106 static uint64
107 test_timing(int32 duration)
108 {
109         uint64          total_time;
110         int64           time_elapsed = 0;
111         uint64          loop_count = 0;
112         uint64          prev,
113                                 cur;
114         instr_time      start_time,
115                                 end_time,
116                                 temp;
117
118         total_time = duration > 0 ? duration * INT64CONST(1000000) : 0;
119
120         INSTR_TIME_SET_CURRENT(start_time);
121         cur = INSTR_TIME_GET_MICROSEC(start_time);
122
123         while (time_elapsed < total_time)
124         {
125                 int32           diff,
126                                         bits = 0;
127
128                 prev = cur;
129                 INSTR_TIME_SET_CURRENT(temp);
130                 cur = INSTR_TIME_GET_MICROSEC(temp);
131                 diff = cur - prev;
132
133                 /* Did time go backwards? */
134                 if (diff < 0)
135                 {
136                         printf("Detected clock going backwards in time.\n");
137                         printf("Time warp: %d microseconds\n", diff);
138                         exit(1);
139                 }
140
141                 /* What is the highest bit in the time diff? */
142                 while (diff)
143                 {
144                         diff >>= 1;
145                         bits++;
146                 }
147
148                 /* Update appropriate duration bucket */
149                 histogram[bits]++;
150
151                 loop_count++;
152                 INSTR_TIME_SUBTRACT(temp, start_time);
153                 time_elapsed = INSTR_TIME_GET_MICROSEC(temp);
154         }
155
156         INSTR_TIME_SET_CURRENT(end_time);
157
158         INSTR_TIME_SUBTRACT(end_time, start_time);
159
160         printf("Per loop time including overhead: %0.2f nsec\n",
161                    INSTR_TIME_GET_DOUBLE(end_time) * 1e9 / loop_count);
162
163         return loop_count;
164 }
165
166 static void
167 output(uint64 loop_count)
168 {
169         int64           max_bit = 31,
170                                 i;
171
172         /* find highest bit value */
173         while (max_bit > 0 && histogram[max_bit] == 0)
174                 max_bit--;
175
176         printf("Histogram of timing durations:\n");
177         printf("%6s   %10s %10s\n", "< usec", "% of total", "count");
178
179         for (i = 0; i <= max_bit; i++)
180         {
181                 char            buf[100];
182
183                 /* lame hack to work around INT64_FORMAT deficiencies */
184                 snprintf(buf, sizeof(buf), INT64_FORMAT, histogram[i]);
185                 printf("%6ld    %9.5f %10s\n", 1l << i,
186                            (double) histogram[i] * 100 / loop_count, buf);
187         }
188 }