@@ -347,6 +347,9 @@ static char *select_only = {
347
347
static void setalarm (int seconds );
348
348
static void * threadRun (void * arg );
349
349
350
+ static void doLog (TState * thread , CState * st , FILE * logfile , instr_time * now ,
351
+ AggVals * agg );
352
+
350
353
static void
351
354
usage (void )
352
355
{
@@ -1016,6 +1019,16 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa
1016
1019
PGresult * res ;
1017
1020
Command * * commands ;
1018
1021
bool trans_needs_throttle = false;
1022
+ instr_time now ;
1023
+
1024
+ /*
1025
+ * gettimeofday() isn't free, so we get the current timestamp lazily the
1026
+ * first time it's needed, and reuse the same value throughout this
1027
+ * function after that. This also ensures that e.g. the calculated latency
1028
+ * reported in the log file and in the totals are the same. Zero means
1029
+ * "not set yet".
1030
+ */
1031
+ INSTR_TIME_SET_ZERO (now );
1019
1032
1020
1033
top :
1021
1034
commands = sql_files [st -> use_file ];
@@ -1049,10 +1062,10 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa
1049
1062
1050
1063
if (st -> sleeping )
1051
1064
{ /* are we sleeping? */
1052
- instr_time now ;
1053
1065
int64 now_us ;
1054
1066
1055
- INSTR_TIME_SET_CURRENT (now );
1067
+ if (INSTR_TIME_IS_ZERO (now ))
1068
+ INSTR_TIME_SET_CURRENT (now );
1056
1069
now_us = INSTR_TIME_GET_MICROSEC (now );
1057
1070
if (st -> txn_scheduled <= now_us )
1058
1071
{
@@ -1074,11 +1087,6 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa
1074
1087
1075
1088
if (st -> listen )
1076
1089
{ /* are we receiver? */
1077
- instr_time now ;
1078
- bool now_valid = false;
1079
-
1080
- INSTR_TIME_SET_ZERO (now ); /* initialize to keep compiler quiet */
1081
-
1082
1090
if (commands [st -> state ]-> type == SQL_COMMAND )
1083
1091
{
1084
1092
if (debug )
@@ -1100,181 +1108,40 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa
1100
1108
{
1101
1109
int cnum = commands [st -> state ]-> command_num ;
1102
1110
1103
- if (!now_valid )
1104
- {
1111
+ if (INSTR_TIME_IS_ZERO (now ))
1105
1112
INSTR_TIME_SET_CURRENT (now );
1106
- now_valid = true;
1107
- }
1108
1113
INSTR_TIME_ACCUM_DIFF (thread -> exec_elapsed [cnum ],
1109
1114
now , st -> stmt_begin );
1110
1115
thread -> exec_count [cnum ]++ ;
1111
1116
}
1112
1117
1113
- /* transaction finished: record latency under progress or throttling */
1114
- if (( progress || throttle_delay ) && commands [st -> state + 1 ] == NULL )
1118
+ /* transaction finished: calculate latency and log the transaction */
1119
+ if (commands [st -> state + 1 ] == NULL )
1115
1120
{
1116
- int64 latency ;
1117
-
1118
- if (!now_valid )
1121
+ /* only calculate latency if an option is used that needs it */
1122
+ if (progress || throttle_delay )
1119
1123
{
1120
- INSTR_TIME_SET_CURRENT (now );
1121
- now_valid = true;
1122
- }
1123
-
1124
- latency = INSTR_TIME_GET_MICROSEC (now ) - st -> txn_scheduled ;
1124
+ int64 latency ;
1125
1125
1126
- st -> txn_latencies += latency ;
1127
-
1128
- /*
1129
- * XXX In a long benchmark run of high-latency transactions, this
1130
- * int64 addition eventually overflows. For example, 100 threads
1131
- * running 10s transactions will overflow it in 2.56 hours. With
1132
- * a more-typical OLTP workload of .1s transactions, overflow
1133
- * would take 256 hours.
1134
- */
1135
- st -> txn_sqlats += latency * latency ;
1136
- }
1137
-
1138
- /*
1139
- * if transaction finished, record the time it took in the log
1140
- */
1141
- if (logfile && commands [st -> state + 1 ] == NULL )
1142
- {
1143
- double lag ;
1144
- double latency ;
1145
-
1146
- /*
1147
- * write the log entry if this row belongs to the random sample,
1148
- * or no sampling rate was given which means log everything.
1149
- */
1150
- if (sample_rate == 0.0 ||
1151
- pg_erand48 (thread -> random_state ) <= sample_rate )
1152
- {
1153
- if (!now_valid )
1154
- {
1126
+ if (INSTR_TIME_IS_ZERO (now ))
1155
1127
INSTR_TIME_SET_CURRENT (now );
1156
- now_valid = true;
1157
- }
1158
- latency = (double ) (INSTR_TIME_GET_MICROSEC (now ) - st -> txn_scheduled );
1159
- lag = (double ) (INSTR_TIME_GET_MICROSEC (st -> txn_begin ) - st -> txn_scheduled );
1160
-
1161
- /* should we aggregate the results or not? */
1162
- if (agg_interval > 0 )
1163
- {
1164
- /*
1165
- * are we still in the same interval? if yes, accumulate
1166
- * the values (print them otherwise)
1167
- */
1168
- if (agg -> start_time + agg_interval >= INSTR_TIME_GET_DOUBLE (now ))
1169
- {
1170
- agg -> cnt += 1 ;
1171
- agg -> sum_latency += latency ;
1172
- agg -> sum2_latency += latency * latency ;
1173
-
1174
- /* first in this aggregation interval */
1175
- if ((agg -> cnt == 1 ) || (latency < agg -> min_latency ))
1176
- agg -> min_latency = latency ;
1177
-
1178
- if ((agg -> cnt == 1 ) || (latency > agg -> max_latency ))
1179
- agg -> max_latency = latency ;
1180
-
1181
- /* and the same for schedule lag */
1182
- if (throttle_delay )
1183
- {
1184
- agg -> sum_lag += lag ;
1185
- agg -> sum2_lag += lag * lag ;
1186
-
1187
- if ((agg -> cnt == 1 ) || (lag < agg -> min_lag ))
1188
- agg -> min_lag = lag ;
1189
- if ((agg -> cnt == 1 ) || (lag > agg -> max_lag ))
1190
- agg -> max_lag = lag ;
1191
- }
1192
- }
1193
- else
1194
- {
1195
- /*
1196
- * Loop until we reach the interval of the current
1197
- * transaction (and print all the empty intervals in
1198
- * between).
1199
- */
1200
- while (agg -> start_time + agg_interval < INSTR_TIME_GET_DOUBLE (now ))
1201
- {
1202
- /*
1203
- * This is a non-Windows branch (thanks to the
1204
- * ifdef in usage), so we don't need to handle
1205
- * this in a special way (see below).
1206
- */
1207
- fprintf (logfile , "%ld %d %.0f %.0f %.0f %.0f" ,
1208
- agg -> start_time ,
1209
- agg -> cnt ,
1210
- agg -> sum_latency ,
1211
- agg -> sum2_latency ,
1212
- agg -> min_latency ,
1213
- agg -> max_latency );
1214
- if (throttle_delay )
1215
- fprintf (logfile , " %.0f %.0f %.0f %.0f" ,
1216
- agg -> sum_lag ,
1217
- agg -> sum2_lag ,
1218
- agg -> min_lag ,
1219
- agg -> max_lag );
1220
- fputc ('\n' , logfile );
1221
-
1222
- /* move to the next inteval */
1223
- agg -> start_time = agg -> start_time + agg_interval ;
1224
-
1225
- /* reset for "no transaction" intervals */
1226
- agg -> cnt = 0 ;
1227
- agg -> min_latency = 0 ;
1228
- agg -> max_latency = 0 ;
1229
- agg -> sum_latency = 0 ;
1230
- agg -> sum2_latency = 0 ;
1231
- agg -> min_lag = 0 ;
1232
- agg -> max_lag = 0 ;
1233
- agg -> sum_lag = 0 ;
1234
- agg -> sum2_lag = 0 ;
1235
- }
1236
-
1237
- /*
1238
- * and now update the reset values (include the
1239
- * current)
1240
- */
1241
- agg -> cnt = 1 ;
1242
- agg -> min_latency = latency ;
1243
- agg -> max_latency = latency ;
1244
- agg -> sum_latency = latency ;
1245
- agg -> sum2_latency = latency * latency ;
1246
- agg -> min_lag = lag ;
1247
- agg -> max_lag = lag ;
1248
- agg -> sum_lag = lag ;
1249
- agg -> sum2_lag = lag * lag ;
1250
- }
1251
- }
1252
- else
1253
- {
1254
- /* no, print raw transactions */
1255
- #ifndef WIN32
1256
-
1257
- /*
1258
- * This is more than we really ought to know about
1259
- * instr_time
1260
- */
1261
- fprintf (logfile , "%d %d %.0f %d %ld %ld" ,
1262
- st -> id , st -> cnt , latency , st -> use_file ,
1263
- (long ) now .tv_sec , (long ) now .tv_usec );
1264
- #else
1265
-
1266
- /*
1267
- * On Windows, instr_time doesn't provide a timestamp
1268
- * anyway
1269
- */
1270
- fprintf (logfile , "%d %d %.0f %d 0 0" ,
1271
- st -> id , st -> cnt , latency , st -> use_file );
1272
- #endif
1273
- if (throttle_delay )
1274
- fprintf (logfile , " %.0f" , lag );
1275
- fputc ('\n' , logfile );
1276
- }
1128
+ latency = INSTR_TIME_GET_MICROSEC (now ) - st -> txn_scheduled ;
1129
+
1130
+ st -> txn_latencies += latency ;
1131
+
1132
+ /*
1133
+ * XXX In a long benchmark run of high-latency transactions,
1134
+ * this int64 addition eventually overflows. For example, 100
1135
+ * threads running 10s transactions will overflow it in 2.56
1136
+ * hours. With a more-typical OLTP workload of .1s
1137
+ * transactions, overflow would take 256 hours.
1138
+ */
1139
+ st -> txn_sqlats += latency * latency ;
1277
1140
}
1141
+
1142
+ /* record the time it took in the log */
1143
+ if (logfile )
1144
+ doLog (thread , st , logfile , & now , agg );
1278
1145
}
1279
1146
1280
1147
if (commands [st -> state ]-> type == SQL_COMMAND )
@@ -1734,6 +1601,137 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa
1734
1601
return true;
1735
1602
}
1736
1603
1604
+ /*
1605
+ * print log entry after completing one transaction.
1606
+ */
1607
+ static void
1608
+ doLog (TState * thread , CState * st , FILE * logfile , instr_time * now , AggVals * agg )
1609
+ {
1610
+ double lag ;
1611
+ double latency ;
1612
+
1613
+ /*
1614
+ * Skip the log entry if sampling is enabled and this row doesn't belong
1615
+ * to the random sample.
1616
+ */
1617
+ if (sample_rate != 0.0 &&
1618
+ pg_erand48 (thread -> random_state ) > sample_rate )
1619
+ return ;
1620
+
1621
+ if (INSTR_TIME_IS_ZERO (* now ))
1622
+ INSTR_TIME_SET_CURRENT (* now );
1623
+
1624
+ latency = (double ) (INSTR_TIME_GET_MICROSEC (* now ) - st -> txn_scheduled );
1625
+ lag = (double ) (INSTR_TIME_GET_MICROSEC (st -> txn_begin ) - st -> txn_scheduled );
1626
+
1627
+ /* should we aggregate the results or not? */
1628
+ if (agg_interval > 0 )
1629
+ {
1630
+ /*
1631
+ * Are we still in the same interval? If yes, accumulate the values
1632
+ * (print them otherwise)
1633
+ */
1634
+ if (agg -> start_time + agg_interval >= INSTR_TIME_GET_DOUBLE (* now ))
1635
+ {
1636
+ agg -> cnt += 1 ;
1637
+ agg -> sum_latency += latency ;
1638
+ agg -> sum2_latency += latency * latency ;
1639
+
1640
+ /* first in this aggregation interval */
1641
+ if ((agg -> cnt == 1 ) || (latency < agg -> min_latency ))
1642
+ agg -> min_latency = latency ;
1643
+
1644
+ if ((agg -> cnt == 1 ) || (latency > agg -> max_latency ))
1645
+ agg -> max_latency = latency ;
1646
+
1647
+ /* and the same for schedule lag */
1648
+ if (throttle_delay )
1649
+ {
1650
+ agg -> sum_lag += lag ;
1651
+ agg -> sum2_lag += lag * lag ;
1652
+
1653
+ if ((agg -> cnt == 1 ) || (lag < agg -> min_lag ))
1654
+ agg -> min_lag = lag ;
1655
+ if ((agg -> cnt == 1 ) || (lag > agg -> max_lag ))
1656
+ agg -> max_lag = lag ;
1657
+ }
1658
+ }
1659
+ else
1660
+ {
1661
+ /*
1662
+ * Loop until we reach the interval of the current transaction
1663
+ * (and print all the empty intervals in between).
1664
+ */
1665
+ while (agg -> start_time + agg_interval < INSTR_TIME_GET_DOUBLE (* now ))
1666
+ {
1667
+ /*
1668
+ * This is a non-Windows branch (thanks to the
1669
+ * ifdef in usage), so we don't need to handle
1670
+ * this in a special way (see below).
1671
+ */
1672
+ fprintf (logfile , "%ld %d %.0f %.0f %.0f %.0f" ,
1673
+ agg -> start_time ,
1674
+ agg -> cnt ,
1675
+ agg -> sum_latency ,
1676
+ agg -> sum2_latency ,
1677
+ agg -> min_latency ,
1678
+ agg -> max_latency );
1679
+ if (throttle_delay )
1680
+ fprintf (logfile , " %.0f %.0f %.0f %.0f" ,
1681
+ agg -> sum_lag ,
1682
+ agg -> sum2_lag ,
1683
+ agg -> min_lag ,
1684
+ agg -> max_lag );
1685
+ fputc ('\n' , logfile );
1686
+
1687
+ /* move to the next inteval */
1688
+ agg -> start_time = agg -> start_time + agg_interval ;
1689
+
1690
+ /* reset for "no transaction" intervals */
1691
+ agg -> cnt = 0 ;
1692
+ agg -> min_latency = 0 ;
1693
+ agg -> max_latency = 0 ;
1694
+ agg -> sum_latency = 0 ;
1695
+ agg -> sum2_latency = 0 ;
1696
+ agg -> min_lag = 0 ;
1697
+ agg -> max_lag = 0 ;
1698
+ agg -> sum_lag = 0 ;
1699
+ agg -> sum2_lag = 0 ;
1700
+ }
1701
+
1702
+ /* reset the values to include only the current transaction. */
1703
+ agg -> cnt = 1 ;
1704
+ agg -> min_latency = latency ;
1705
+ agg -> max_latency = latency ;
1706
+ agg -> sum_latency = latency ;
1707
+ agg -> sum2_latency = latency * latency ;
1708
+ agg -> min_lag = lag ;
1709
+ agg -> max_lag = lag ;
1710
+ agg -> sum_lag = lag ;
1711
+ agg -> sum2_lag = lag * lag ;
1712
+ }
1713
+ }
1714
+ else
1715
+ {
1716
+ /* no, print raw transactions */
1717
+ #ifndef WIN32
1718
+
1719
+ /* This is more than we really ought to know about instr_time */
1720
+ fprintf (logfile , "%d %d %.0f %d %ld %ld" ,
1721
+ st -> id , st -> cnt , latency , st -> use_file ,
1722
+ (long ) now -> tv_sec , (long ) now -> tv_usec );
1723
+ #else
1724
+
1725
+ /* On Windows, instr_time doesn't provide a timestamp anyway */
1726
+ fprintf (logfile , "%d %d %.0f %d 0 0" ,
1727
+ st -> id , st -> cnt , latency , st -> use_file );
1728
+ #endif
1729
+ if (throttle_delay )
1730
+ fprintf (logfile , " %.0f" , lag );
1731
+ fputc ('\n' , logfile );
1732
+ }
1733
+ }
1734
+
1737
1735
/* discard connections */
1738
1736
static void
1739
1737
disconnect_all (CState * state , int length )
0 commit comments