@@ -162,6 +162,7 @@ char *index_tablespace = NULL;
162
162
163
163
bool use_log ; /* log transaction latencies to a file */
164
164
bool use_quiet ; /* quiet logging onto stderr */
165
+ int agg_interval ; /* log aggregates instead of individual transactions */
165
166
bool is_connect ; /* establish connection for each transaction */
166
167
bool is_latencies ; /* report per-command latencies */
167
168
int main_pid ; /* main process id used in log filename */
@@ -257,6 +258,18 @@ typedef struct
257
258
char * argv [MAX_ARGS ]; /* command word list */
258
259
} Command ;
259
260
261
+ typedef struct
262
+ {
263
+
264
+ long start_time ; /* when does the interval start */
265
+ int cnt ; /* number of transactions */
266
+ double min_duration ; /* min/max durations */
267
+ double max_duration ;
268
+ double sum ; /* sum(duration), sum(duration^2) - for estimates */
269
+ double sum2 ;
270
+
271
+ } AggVals ;
272
+
260
273
static Command * * sql_files [MAX_FILES ]; /* SQL script files */
261
274
static int num_files ; /* number of script files */
262
275
static int num_commands = 0 ; /* total number of Command structs */
@@ -390,6 +403,8 @@ usage(void)
390
403
" -l write transaction times to log file\n"
391
404
" --sampling-rate NUM\n"
392
405
" fraction of transactions to log (e.g. 0.01 for 1%% sample)\n"
406
+ " --aggregate-interval NUM\n"
407
+ " aggregate data over NUM seconds\n"
393
408
" -M simple|extended|prepared\n"
394
409
" protocol for submitting queries to server (default: simple)\n"
395
410
" -n do not run VACUUM before tests\n"
@@ -911,9 +926,25 @@ clientDone(CState *st, bool ok)
911
926
return false; /* always false */
912
927
}
913
928
929
+ static
930
+ void agg_vals_init (AggVals * aggs , instr_time start )
931
+ {
932
+ /* basic counters */
933
+ aggs -> cnt = 0 ; /* number of transactions */
934
+ aggs -> sum = 0 ; /* SUM(duration) */
935
+ aggs -> sum2 = 0 ; /* SUM(duration*duration) */
936
+
937
+ /* min and max transaction duration */
938
+ aggs -> min_duration = 0 ;
939
+ aggs -> max_duration = 0 ;
940
+
941
+ /* start of the current interval */
942
+ aggs -> start_time = INSTR_TIME_GET_DOUBLE (start );
943
+ }
944
+
914
945
/* return false iff client should be disconnected */
915
946
static bool
916
- doCustom (TState * thread , CState * st , instr_time * conn_time , FILE * logfile )
947
+ doCustom (TState * thread , CState * st , instr_time * conn_time , FILE * logfile , AggVals * agg )
917
948
{
918
949
PGresult * res ;
919
950
Command * * commands ;
@@ -978,22 +1009,74 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
978
1009
if (sample_rate == 0.0 ||
979
1010
pg_erand48 (thread -> random_state ) <= sample_rate )
980
1011
{
981
-
982
1012
INSTR_TIME_SET_CURRENT (now );
983
1013
diff = now ;
984
1014
INSTR_TIME_SUBTRACT (diff , st -> txn_begin );
985
1015
usec = (double ) INSTR_TIME_GET_MICROSEC (diff );
986
1016
1017
+ /* should we aggregate the results or not? */
1018
+ if (agg_interval > 0 )
1019
+ {
1020
+ /* are we still in the same interval? if yes, accumulate the
1021
+ * values (print them otherwise) */
1022
+ if (agg -> start_time + agg_interval >= INSTR_TIME_GET_DOUBLE (now ))
1023
+ {
1024
+ agg -> cnt += 1 ;
1025
+ agg -> sum += usec ;
1026
+ agg -> sum2 += usec * usec ;
1027
+
1028
+ /* first in this aggregation interval */
1029
+ if ((agg -> cnt == 1 ) || (usec < agg -> min_duration ))
1030
+ agg -> min_duration = usec ;
1031
+
1032
+ if ((agg -> cnt == 1 ) || (usec > agg -> max_duration ))
1033
+ agg -> max_duration = usec ;
1034
+ }
1035
+ else
1036
+ {
1037
+ /* Loop until we reach the interval of the current transaction (and
1038
+ * print all the empty intervals in between). */
1039
+ while (agg -> start_time + agg_interval < INSTR_TIME_GET_DOUBLE (now ))
1040
+ {
1041
+ /* This is a non-Windows branch (thanks to the ifdef in usage), so
1042
+ * we don't need to handle this in a special way (see below). */
1043
+ fprintf (logfile , "%ld %d %.0f %.0f %.0f %.0f\n" ,
1044
+ agg -> start_time , agg -> cnt , agg -> sum , agg -> sum2 ,
1045
+ agg -> min_duration , agg -> max_duration );
1046
+
1047
+ /* move to the next inteval */
1048
+ agg -> start_time = agg -> start_time + agg_interval ;
1049
+
1050
+ /* reset for "no transaction" intervals */
1051
+ agg -> cnt = 0 ;
1052
+ agg -> min_duration = 0 ;
1053
+ agg -> max_duration = 0 ;
1054
+ agg -> sum = 0 ;
1055
+ agg -> sum2 = 0 ;
1056
+ }
1057
+
1058
+ /* and now update the reset values (include the current) */
1059
+ agg -> cnt = 1 ;
1060
+ agg -> min_duration = usec ;
1061
+ agg -> max_duration = usec ;
1062
+ agg -> sum = usec ;
1063
+ agg -> sum2 = usec * usec ;
1064
+ }
1065
+ }
1066
+ else
1067
+ {
1068
+ /* no, print raw transactions */
987
1069
#ifndef WIN32
988
- /* This is more than we really ought to know about instr_time */
989
- fprintf (logfile , "%d %d %.0f %d %ld %ld\n" ,
990
- st -> id , st -> cnt , usec , st -> use_file ,
991
- (long ) now .tv_sec , (long ) now .tv_usec );
1070
+ /* This is more than we really ought to know about instr_time */
1071
+ fprintf (logfile , "%d %d %.0f %d %ld %ld\n" ,
1072
+ st -> id , st -> cnt , usec , st -> use_file ,
1073
+ (long ) now .tv_sec , (long ) now .tv_usec );
992
1074
#else
993
- /* On Windows, instr_time doesn't provide a timestamp anyway */
994
- fprintf (logfile , "%d %d %.0f %d 0 0\n" ,
995
- st -> id , st -> cnt , usec , st -> use_file );
1075
+ /* On Windows, instr_time doesn't provide a timestamp anyway */
1076
+ fprintf (logfile , "%d %d %.0f %d 0 0\n" ,
1077
+ st -> id , st -> cnt , usec , st -> use_file );
996
1078
#endif
1079
+ }
997
1080
}
998
1081
}
999
1082
@@ -2055,6 +2138,7 @@ main(int argc, char **argv)
2055
2138
{"tablespace" , required_argument , NULL , 2 },
2056
2139
{"unlogged-tables" , no_argument , & unlogged_tables , 1 },
2057
2140
{"sampling-rate" , required_argument , NULL , 4 },
2141
+ {"aggregate-interval" , required_argument , NULL , 5 },
2058
2142
{NULL , 0 , NULL , 0 }
2059
2143
};
2060
2144
@@ -2293,6 +2377,19 @@ main(int argc, char **argv)
2293
2377
exit (1 );
2294
2378
}
2295
2379
break ;
2380
+ case 5 :
2381
+ #ifdef WIN32
2382
+ fprintf (stderr , "--aggregate-interval is not currently supported on Windows" );
2383
+ exit (1 );
2384
+ #else
2385
+ agg_interval = atoi (optarg );
2386
+ if (agg_interval <= 0 )
2387
+ {
2388
+ fprintf (stderr , "invalid number of seconds for aggregation: %d\n" , agg_interval );
2389
+ exit (1 );
2390
+ }
2391
+ #endif
2392
+ break ;
2296
2393
default :
2297
2394
fprintf (stderr , _ ("Try \"%s --help\" for more information.\n" ), progname );
2298
2395
exit (1 );
@@ -2342,6 +2439,28 @@ main(int argc, char **argv)
2342
2439
exit (1 );
2343
2440
}
2344
2441
2442
+ /* --sampling-rate may must not be used with --aggregate-interval */
2443
+ if (sample_rate > 0.0 && agg_interval > 0 )
2444
+ {
2445
+ fprintf (stderr , "log sampling (--sampling-rate) and aggregation (--aggregate-interval) can't be used at the same time\n" );
2446
+ exit (1 );
2447
+ }
2448
+
2449
+ if (agg_interval > 0 && (! use_log )) {
2450
+ fprintf (stderr , "log aggregation is allowed only when actually logging transactions\n" );
2451
+ exit (1 );
2452
+ }
2453
+
2454
+ if ((duration > 0 ) && (agg_interval > duration )) {
2455
+ fprintf (stderr , "number of seconds for aggregation (%d) must not be higher that test duration (%d)\n" , agg_interval , duration );
2456
+ exit (1 );
2457
+ }
2458
+
2459
+ if ((duration > 0 ) && (agg_interval > 0 ) && (duration % agg_interval != 0 )) {
2460
+ fprintf (stderr , "duration (%d) must be a multiple of aggregation interval (%d)\n" , duration , agg_interval );
2461
+ exit (1 );
2462
+ }
2463
+
2345
2464
/*
2346
2465
* is_latencies only works with multiple threads in thread-based
2347
2466
* implementations, not fork-based ones, because it supposes that the
@@ -2601,7 +2720,10 @@ threadRun(void *arg)
2601
2720
int remains = nstate ; /* number of remaining clients */
2602
2721
int i ;
2603
2722
2723
+ AggVals aggs ;
2724
+
2604
2725
result = pg_malloc (sizeof (TResult ));
2726
+
2605
2727
INSTR_TIME_SET_ZERO (result -> conn_time );
2606
2728
2607
2729
/* open log file if requested */
@@ -2636,6 +2758,8 @@ threadRun(void *arg)
2636
2758
INSTR_TIME_SET_CURRENT (result -> conn_time );
2637
2759
INSTR_TIME_SUBTRACT (result -> conn_time , thread -> start_time );
2638
2760
2761
+ agg_vals_init (& aggs , thread -> start_time );
2762
+
2639
2763
/* send start up queries in async manner */
2640
2764
for (i = 0 ; i < nstate ; i ++ )
2641
2765
{
@@ -2644,7 +2768,7 @@ threadRun(void *arg)
2644
2768
int prev_ecnt = st -> ecnt ;
2645
2769
2646
2770
st -> use_file = getrand (thread , 0 , num_files - 1 );
2647
- if (!doCustom (thread , st , & result -> conn_time , logfile ))
2771
+ if (!doCustom (thread , st , & result -> conn_time , logfile , & aggs ))
2648
2772
remains -- ; /* I've aborted */
2649
2773
2650
2774
if (st -> ecnt > prev_ecnt && commands [st -> state ]-> type == META_COMMAND )
@@ -2746,7 +2870,7 @@ threadRun(void *arg)
2746
2870
if (st -> con && (FD_ISSET (PQsocket (st -> con ), & input_mask )
2747
2871
|| commands [st -> state ]-> type == META_COMMAND ))
2748
2872
{
2749
- if (!doCustom (thread , st , & result -> conn_time , logfile ))
2873
+ if (!doCustom (thread , st , & result -> conn_time , logfile , & aggs ))
2750
2874
remains -- ; /* I've aborted */
2751
2875
}
2752
2876
@@ -2773,7 +2897,6 @@ threadRun(void *arg)
2773
2897
return result ;
2774
2898
}
2775
2899
2776
-
2777
2900
/*
2778
2901
* Support for duration option: set timer_exceeded after so many seconds.
2779
2902
*/
0 commit comments