mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-21 08:29:39 +08:00
pgbench: Elaborate latency reporting.
Isolate transaction latency (elapsed time between submitting first command and receiving response to last command) from client-side delays pertaining to the --rate schedule. Under --rate, report schedule lag as defined in the documentation. Report latency standard deviation whenever we collect the measurements to do so. All of these changes affect --progress messages and the final report. Fabien COELHO, reviewed by Pavel Stehule.
This commit is contained in:
parent
8e00a3850d
commit
2d6c0f10ef
@ -172,6 +172,7 @@ int agg_interval; /* log aggregates instead of individual
|
||||
* transactions */
|
||||
int progress = 0; /* thread progress report every this seconds */
|
||||
int progress_nclients = 0; /* number of clients for progress report */
|
||||
int progress_nthreads = 0; /* number of threads for progress report */
|
||||
bool is_connect; /* establish connection for each transaction */
|
||||
bool is_latencies; /* report per-command latencies */
|
||||
int main_pid; /* main process id used in log filename */
|
||||
@ -214,6 +215,8 @@ typedef struct
|
||||
int nvariables;
|
||||
instr_time txn_begin; /* used for measuring transaction latencies */
|
||||
instr_time stmt_begin; /* used for measuring statement latencies */
|
||||
int64 txn_latencies; /* cumulated latencies */
|
||||
int64 txn_sqlats; /* cumulated square latencies */
|
||||
bool is_throttled; /* whether transaction throttling is done */
|
||||
int use_file; /* index in sql_files for this client */
|
||||
bool prepared[MAX_FILES];
|
||||
@ -243,6 +246,8 @@ typedef struct
|
||||
{
|
||||
instr_time conn_time;
|
||||
int xacts;
|
||||
int64 latencies;
|
||||
int64 sqlats;
|
||||
int64 throttle_lag;
|
||||
int64 throttle_lag_max;
|
||||
} TResult;
|
||||
@ -1006,6 +1011,26 @@ top:
|
||||
thread->exec_count[cnum]++;
|
||||
}
|
||||
|
||||
/* transaction finished: record latency under progress or throttling */
|
||||
if ((progress || throttle_delay) && commands[st->state + 1] == NULL)
|
||||
{
|
||||
instr_time diff;
|
||||
int64 latency;
|
||||
|
||||
INSTR_TIME_SET_CURRENT(diff);
|
||||
INSTR_TIME_SUBTRACT(diff, st->txn_begin);
|
||||
latency = INSTR_TIME_GET_MICROSEC(diff);
|
||||
st->txn_latencies += latency;
|
||||
/*
|
||||
* XXX In a long benchmark run of high-latency transactions, this
|
||||
* int64 addition eventually overflows. For example, 100 threads
|
||||
* running 10s transactions will overflow it in 2.56 hours. With
|
||||
* a more-typical OLTP workload of .1s transactions, overflow
|
||||
* would take 256 hours.
|
||||
*/
|
||||
st->txn_sqlats += latency * latency;
|
||||
}
|
||||
|
||||
/*
|
||||
* if transaction finished, record the time it took in the log
|
||||
*/
|
||||
@ -1195,8 +1220,8 @@ top:
|
||||
goto top;
|
||||
}
|
||||
|
||||
/* Record transaction start time if logging is enabled */
|
||||
if (logfile && st->state == 0)
|
||||
/* Record transaction start time under logging, progress or throttling */
|
||||
if ((logfile || progress || throttle_delay) && st->state == 0)
|
||||
INSTR_TIME_SET_CURRENT(st->txn_begin);
|
||||
|
||||
/* Record statement start time if per-command latencies are requested */
|
||||
@ -2105,6 +2130,7 @@ static void
|
||||
printResults(int ttype, int normal_xacts, int nclients,
|
||||
TState *threads, int nthreads,
|
||||
instr_time total_time, instr_time conn_total_time,
|
||||
int64 total_latencies, int64 total_sqlats,
|
||||
int64 throttle_lag, int64 throttle_lag_max)
|
||||
{
|
||||
double time_include,
|
||||
@ -2144,6 +2170,22 @@ printResults(int ttype, int normal_xacts, int nclients,
|
||||
normal_xacts);
|
||||
}
|
||||
|
||||
if (throttle_delay || progress)
|
||||
{
|
||||
/* compute and show latency average and standard deviation */
|
||||
double latency = 0.001 * total_latencies / normal_xacts;
|
||||
double sqlat = (double) total_sqlats / normal_xacts;
|
||||
printf("latency average: %.3f ms\n"
|
||||
"latency stddev: %.3f ms\n",
|
||||
latency, 0.001 * sqrt(sqlat - 1000000.0 * latency * latency));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* only an average latency computed from the duration is available */
|
||||
printf("latency average: %.3f ms\n",
|
||||
1000.0 * duration * nclients / normal_xacts);
|
||||
}
|
||||
|
||||
if (throttle_delay)
|
||||
{
|
||||
/*
|
||||
@ -2152,7 +2194,7 @@ printResults(int ttype, int normal_xacts, int nclients,
|
||||
* transaction. The measured lag may be caused by thread/client load,
|
||||
* the database load, or the Poisson throttling process.
|
||||
*/
|
||||
printf("average rate limit schedule lag: %.3f ms (max %.3f ms)\n",
|
||||
printf("rate limit schedule lag: avg %.3f (max %.3f) ms\n",
|
||||
0.001 * throttle_lag / normal_xacts, 0.001 * throttle_lag_max);
|
||||
}
|
||||
|
||||
@ -2263,7 +2305,9 @@ main(int argc, char **argv)
|
||||
instr_time start_time; /* start up time */
|
||||
instr_time total_time;
|
||||
instr_time conn_total_time;
|
||||
int total_xacts;
|
||||
int total_xacts = 0;
|
||||
int64 total_latencies = 0;
|
||||
int64 total_sqlats = 0;
|
||||
int64 throttle_lag = 0;
|
||||
int64 throttle_lag_max = 0;
|
||||
|
||||
@ -2617,6 +2661,7 @@ main(int argc, char **argv)
|
||||
*/
|
||||
main_pid = (int) getpid();
|
||||
progress_nclients = nclients;
|
||||
progress_nthreads = nthreads;
|
||||
|
||||
if (nclients > 1)
|
||||
{
|
||||
@ -2825,7 +2870,6 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* wait for threads and accumulate results */
|
||||
total_xacts = 0;
|
||||
INSTR_TIME_SET_ZERO(conn_total_time);
|
||||
for (i = 0; i < nthreads; i++)
|
||||
{
|
||||
@ -2841,6 +2885,8 @@ main(int argc, char **argv)
|
||||
TResult *r = (TResult *) ret;
|
||||
|
||||
total_xacts += r->xacts;
|
||||
total_latencies += r->latencies;
|
||||
total_sqlats += r->sqlats;
|
||||
throttle_lag += r->throttle_lag;
|
||||
if (r->throttle_lag_max > throttle_lag_max)
|
||||
throttle_lag_max = r->throttle_lag_max;
|
||||
@ -2854,7 +2900,8 @@ main(int argc, char **argv)
|
||||
INSTR_TIME_SET_CURRENT(total_time);
|
||||
INSTR_TIME_SUBTRACT(total_time, start_time);
|
||||
printResults(ttype, total_xacts, nclients, threads, nthreads,
|
||||
total_time, conn_total_time, throttle_lag, throttle_lag_max);
|
||||
total_time, conn_total_time, total_latencies, total_sqlats,
|
||||
throttle_lag, throttle_lag_max);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2875,7 +2922,7 @@ threadRun(void *arg)
|
||||
int64 thread_start = INSTR_TIME_GET_MICROSEC(thread->start_time);
|
||||
int64 last_report = thread_start;
|
||||
int64 next_report = last_report + progress * 1000000;
|
||||
int64 last_count = 0;
|
||||
int64 last_count = 0, last_lats = 0, last_sqlats = 0, last_lags = 0;
|
||||
|
||||
AggVals aggs;
|
||||
|
||||
@ -3075,21 +3122,40 @@ threadRun(void *arg)
|
||||
if (now >= next_report)
|
||||
{
|
||||
/* generate and show report */
|
||||
int64 count = 0;
|
||||
int64 count = 0, lats = 0, sqlats = 0;
|
||||
int64 lags = thread->throttle_lag;
|
||||
int64 run = now - last_report;
|
||||
double tps, total_run, latency;
|
||||
double tps, total_run, latency, sqlat, stdev, lag;
|
||||
|
||||
for (i = 0 ; i < nstate ; i++)
|
||||
{
|
||||
count += state[i].cnt;
|
||||
lats += state[i].txn_latencies;
|
||||
sqlats += state[i].txn_sqlats;
|
||||
}
|
||||
|
||||
total_run = (now - thread_start) / 1000000.0;
|
||||
tps = 1000000.0 * (count - last_count) / run;
|
||||
latency = 1000.0 * nstate / tps;
|
||||
latency = 0.001 * (lats - last_lats) / (count - last_count);
|
||||
sqlat = 1.0 * (sqlats - last_sqlats) / (count - last_count);
|
||||
stdev = 0.001 * sqrt(sqlat - 1000000.0 * latency * latency);
|
||||
lag = 0.001 * (lags - last_lags) / (count - last_count);
|
||||
|
||||
fprintf(stderr, "progress %d: %.1f s, %.1f tps, %.3f ms lat\n",
|
||||
thread->tid, total_run, tps, latency);
|
||||
if (throttle_delay)
|
||||
fprintf(stderr,
|
||||
"progress %d: %.1f s, %.1f tps, "
|
||||
"lat %.3f ms stddev %.3f, lag %.3f ms\n",
|
||||
thread->tid, total_run, tps, latency, stdev, lag);
|
||||
else
|
||||
fprintf(stderr,
|
||||
"progress %d: %.1f s, %.1f tps, "
|
||||
"lat %.3f ms stddev %.3f\n",
|
||||
thread->tid, total_run, tps, latency, stdev);
|
||||
|
||||
last_count = count;
|
||||
last_lats = lats;
|
||||
last_sqlats = sqlats;
|
||||
last_lags = lags;
|
||||
last_report = now;
|
||||
next_report += progress * 1000000;
|
||||
}
|
||||
@ -3105,21 +3171,42 @@ threadRun(void *arg)
|
||||
if (now >= next_report)
|
||||
{
|
||||
/* generate and show report */
|
||||
int64 count = 0;
|
||||
int64 count = 0, lats = 0, sqlats = 0, lags = 0;
|
||||
int64 run = now - last_report;
|
||||
double tps, total_run, latency;
|
||||
double tps, total_run, latency, sqlat, lag, stdev;
|
||||
|
||||
for (i = 0 ; i < progress_nclients ; i++)
|
||||
{
|
||||
count += state[i].cnt;
|
||||
lats += state[i].txn_latencies;
|
||||
sqlats += state[i].txn_sqlats;
|
||||
}
|
||||
|
||||
for (i = 0 ; i < progress_nthreads ; i++)
|
||||
lags += thread[i].throttle_lag;
|
||||
|
||||
total_run = (now - thread_start) / 1000000.0;
|
||||
tps = 1000000.0 * (count - last_count) / run;
|
||||
latency = 1000.0 * progress_nclients / tps;
|
||||
latency = 0.001 * (lats - last_lats) / (count - last_count);
|
||||
sqlat = 1.0 * (sqlats - last_sqlats) / (count - last_count);
|
||||
stdev = 0.001 * sqrt(sqlat - 1000000.0 * latency * latency);
|
||||
lag = 0.001 * (lags - last_lags) / (count - last_count);
|
||||
|
||||
fprintf(stderr, "progress: %.1f s, %.1f tps, %.3f ms lat\n",
|
||||
total_run, tps, latency);
|
||||
if (throttle_delay)
|
||||
fprintf(stderr,
|
||||
"progress: %.1f s, %.1f tps, "
|
||||
"lat %.3f ms stddev %.3f, lag %.3f ms\n",
|
||||
total_run, tps, latency, stdev, lag);
|
||||
else
|
||||
fprintf(stderr,
|
||||
"progress: %.1f s, %.1f tps, "
|
||||
"lat %.3f ms stddev %.3f\n",
|
||||
total_run, tps, latency, stdev);
|
||||
|
||||
last_count = count;
|
||||
last_lats = lats;
|
||||
last_sqlats = sqlats;
|
||||
last_lags = lags;
|
||||
last_report = now;
|
||||
next_report += progress * 1000000;
|
||||
}
|
||||
@ -3131,8 +3218,14 @@ done:
|
||||
INSTR_TIME_SET_CURRENT(start);
|
||||
disconnect_all(state, nstate);
|
||||
result->xacts = 0;
|
||||
result->latencies = 0;
|
||||
result->sqlats = 0;
|
||||
for (i = 0; i < nstate; i++)
|
||||
{
|
||||
result->xacts += state[i].cnt;
|
||||
result->latencies += state[i].txn_latencies;
|
||||
result->sqlats += state[i].txn_sqlats;
|
||||
}
|
||||
result->throttle_lag = thread->throttle_lag;
|
||||
result->throttle_lag_max = thread->throttle_lag_max;
|
||||
INSTR_TIME_SET_CURRENT(end);
|
||||
|
@ -412,7 +412,11 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
|
||||
<term><option>--progress=</option><replaceable>sec</></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Show progress report every <literal>sec</> seconds.
|
||||
Show progress report every <literal>sec</> seconds. The report
|
||||
includes the time since the beginning of the run, the tps since the
|
||||
last report, and the transaction latency average and standard
|
||||
deviation since the last report. Under throttling (<option>-R</>), it
|
||||
also includes the average schedule lag time since the last report.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
Loading…
Reference in New Issue
Block a user