@@ -347,6 +347,9 @@ static char *select_only = {
347347static void setalarm (int seconds );
348348static void * threadRun (void * arg );
349349
350+ static void doLog (TState * thread , CState * st , FILE * logfile , instr_time * now ,
351+ AggVals * agg );
352+
350353static void
351354usage (void )
352355{
@@ -1016,6 +1019,16 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa
10161019 PGresult * res ;
10171020 Command * * commands ;
10181021 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 );
10191032
10201033top :
10211034 commands = sql_files [st -> use_file ];
@@ -1049,10 +1062,10 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa
10491062
10501063 if (st -> sleeping )
10511064 { /* are we sleeping? */
1052- instr_time now ;
10531065 int64 now_us ;
10541066
1055- INSTR_TIME_SET_CURRENT (now );
1067+ if (INSTR_TIME_IS_ZERO (now ))
1068+ INSTR_TIME_SET_CURRENT (now );
10561069 now_us = INSTR_TIME_GET_MICROSEC (now );
10571070 if (st -> txn_scheduled <= now_us )
10581071 {
@@ -1074,11 +1087,6 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa
10741087
10751088 if (st -> listen )
10761089 { /* 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-
10821090 if (commands [st -> state ]-> type == SQL_COMMAND )
10831091 {
10841092 if (debug )
@@ -1100,181 +1108,40 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa
11001108 {
11011109 int cnum = commands [st -> state ]-> command_num ;
11021110
1103- if (!now_valid )
1104- {
1111+ if (INSTR_TIME_IS_ZERO (now ))
11051112 INSTR_TIME_SET_CURRENT (now );
1106- now_valid = true;
1107- }
11081113 INSTR_TIME_ACCUM_DIFF (thread -> exec_elapsed [cnum ],
11091114 now , st -> stmt_begin );
11101115 thread -> exec_count [cnum ]++ ;
11111116 }
11121117
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 )
11151120 {
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 )
11191123 {
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 ;
11251125
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 ))
11551127 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 ;
12771140 }
1141+
1142+ /* record the time it took in the log */
1143+ if (logfile )
1144+ doLog (thread , st , logfile , & now , agg );
12781145 }
12791146
12801147 if (commands [st -> state ]-> type == SQL_COMMAND )
@@ -1734,6 +1601,137 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa
17341601 return true;
17351602}
17361603
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+
17371735/* discard connections */
17381736static void
17391737disconnect_all (CState * state , int length )
0 commit comments