Header And Logo

PostgreSQL
| The world's most advanced open source database.

pg_test_timing.c

Go to the documentation of this file.
00001 /*
00002  *  pg_test_timing.c
00003  *      tests overhead of timing calls and their monotonicity:  that
00004  *      they always move forward
00005  */
00006 
00007 #include "postgres_fe.h"
00008 
00009 #include "getopt_long.h"
00010 #include "portability/instr_time.h"
00011 
00012 static const char *progname;
00013 
00014 static int32 test_duration = 3;
00015 
00016 static void handle_args(int argc, char *argv[]);
00017 static uint64 test_timing(int32);
00018 static void output(uint64 loop_count);
00019 
00020 /* record duration in powers of 2 microseconds */
00021 int64 histogram[32];
00022 
00023 int
00024 main(int argc, char *argv[])
00025 {
00026     uint64      loop_count;
00027 
00028     progname = get_progname(argv[0]);
00029 
00030     handle_args(argc, argv);
00031 
00032     loop_count = test_timing(test_duration);
00033 
00034     output(loop_count);
00035 
00036     return 0;
00037 }
00038 
00039 static void
00040 handle_args(int argc, char *argv[])
00041 {
00042     static struct option long_options[] = {
00043         {"duration", required_argument, NULL, 'd'},
00044         {NULL, 0, NULL, 0}
00045     };
00046 
00047     int         option;         /* Command line option */
00048     int         optindex = 0;   /* used by getopt_long */
00049 
00050     if (argc > 1)
00051     {
00052         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0 ||
00053             strcmp(argv[1], "-?") == 0)
00054         {
00055             printf("Usage: %s [-d DURATION]\n", progname);
00056             exit(0);
00057         }
00058         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
00059         {
00060             puts("pg_test_timing (PostgreSQL) " PG_VERSION);
00061             exit(0);
00062         }
00063     }
00064 
00065     while ((option = getopt_long(argc, argv, "d:",
00066                                  long_options, &optindex)) != -1)
00067     {
00068         switch (option)
00069         {
00070             case 'd':
00071                 test_duration = atoi(optarg);
00072                 break;
00073 
00074             default:
00075                 fprintf(stderr, "Try \"%s --help\" for more information.\n",
00076                         progname);
00077                 exit(1);
00078                 break;
00079         }
00080     }
00081 
00082     if (argc > optind)
00083     {
00084         fprintf(stderr,
00085                 "%s: too many command-line arguments (first is \"%s\")\n",
00086                 progname, argv[optind]);
00087         fprintf(stderr, "Try \"%s --help\" for more information.\n",
00088                 progname);
00089         exit(1);
00090     }
00091 
00092     if (test_duration > 0)
00093     {
00094         printf("Testing timing overhead for %d seconds.\n", test_duration);
00095     }
00096     else
00097     {
00098         fprintf(stderr,
00099             "%s: duration must be a positive integer (duration is \"%d\")\n",
00100                 progname, test_duration);
00101         fprintf(stderr, "Try \"%s --help\" for more information.\n",
00102                 progname);
00103         exit(1);
00104     }
00105 }
00106 
00107 static uint64
00108 test_timing(int32 duration)
00109 {
00110     uint64      total_time;
00111     int64       time_elapsed = 0;
00112     uint64      loop_count = 0;
00113     uint64      prev, cur;
00114     instr_time  start_time, end_time, temp;
00115 
00116     total_time = duration > 0 ? duration * 1000000 : 0;
00117 
00118     INSTR_TIME_SET_CURRENT(start_time);
00119     cur = INSTR_TIME_GET_MICROSEC(start_time);
00120 
00121     while (time_elapsed < total_time)
00122     {
00123         int32       diff, bits = 0;
00124 
00125         prev = cur;
00126         INSTR_TIME_SET_CURRENT(temp);
00127         cur = INSTR_TIME_GET_MICROSEC(temp);
00128         diff = cur - prev;
00129 
00130         /* Did time go backwards? */
00131         if (diff < 0)
00132         {
00133             printf("Detected clock going backwards in time.\n");
00134             printf("Time warp: %d microseconds\n", diff);
00135             exit(1);
00136         }
00137 
00138         /* What is the highest bit in the time diff? */
00139         while (diff)
00140         {
00141             diff >>= 1;
00142             bits++;
00143         }
00144 
00145         /* Update appropriate duration bucket */
00146         histogram[bits]++;
00147 
00148         loop_count++;
00149         INSTR_TIME_SUBTRACT(temp, start_time);
00150         time_elapsed = INSTR_TIME_GET_MICROSEC(temp);
00151     }
00152 
00153     INSTR_TIME_SET_CURRENT(end_time);
00154 
00155     INSTR_TIME_SUBTRACT(end_time, start_time);
00156 
00157     printf("Per loop time including overhead: %0.2f nsec\n",
00158            INSTR_TIME_GET_DOUBLE(end_time) * 1e9 / loop_count);
00159 
00160     return loop_count;
00161 }
00162 
00163 static void
00164 output(uint64 loop_count)
00165 {
00166     int64       max_bit = 31, i;
00167 
00168     /* find highest bit value */
00169     while (max_bit > 0 && histogram[max_bit] == 0)
00170         max_bit--;
00171         
00172     printf("Histogram of timing durations:\n");
00173     printf("%6s   %10s %10s\n", "< usec", "% of total", "count");
00174 
00175     for (i = 0; i <= max_bit; i++)
00176     {
00177         char        buf[100];
00178 
00179         /* lame hack to work around INT64_FORMAT deficiencies */
00180         snprintf(buf, sizeof(buf), INT64_FORMAT, histogram[i]);
00181         printf("%6ld    %9.5f %10s\n", 1l << i,
00182                 (double) histogram[i] * 100 / loop_count, buf);
00183     }
00184 }