diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2001-09-18 01:59:07 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2001-09-18 01:59:07 +0000 |
commit | 89fa551808e3d4da4325f5ccf20d26d731bc577f (patch) | |
tree | 44fa14dc0ecac64d152483065a5ff22644dfa65a /src/backend/executor/instrument.c | |
parent | 27d2890b87bf8a933e149e88a5663acd61ee4f41 (diff) |
EXPLAIN ANALYZE feature to measure and show actual runtimes and tuple
counts alongside the planner's estimates. By Martijn van Oosterhout,
with some further work by Tom Lane.
Diffstat (limited to 'src/backend/executor/instrument.c')
-rw-r--r-- | src/backend/executor/instrument.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/src/backend/executor/instrument.c b/src/backend/executor/instrument.c new file mode 100644 index 00000000000..753efbcee9a --- /dev/null +++ b/src/backend/executor/instrument.c @@ -0,0 +1,122 @@ +/*------------------------------------------------------------------------- + * + * instrument.c + * functions for instrumentation of plan execution + * + * + * Copyright (c) 2001, PostgreSQL Global Development Group + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/executor/instrument.c,v 1.1 2001/09/18 01:59:06 tgl Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include <unistd.h> + +#include "executor/instrument.h" + + +/* Allocate new instrumentation structure */ +Instrumentation * +InstrAlloc(void) +{ + Instrumentation *instr = palloc( sizeof(Instrumentation) ); + + memset( instr, 0, sizeof(Instrumentation) ); + + return instr; +} + +/* Entry to a plan node */ +void +InstrStartNode(Instrumentation *instr) +{ + if (!instr) + return; + + if (instr->starttime.tv_sec != 0 || instr->starttime.tv_usec != 0) + elog(DEBUG, "InstrStartTimer called twice in a row"); + else + gettimeofday(&instr->starttime, NULL); +} + +/* Exit from a plan node */ +void +InstrStopNode(Instrumentation *instr, bool returnedTuple) +{ + struct timeval endtime; + + if (!instr) + return; + + if (instr->starttime.tv_sec == 0 && instr->starttime.tv_usec == 0) + { + elog(DEBUG, "InstrStopNode without start"); + return; + } + + gettimeofday(&endtime, NULL); + + instr->counter.tv_sec += endtime.tv_sec - instr->starttime.tv_sec; + instr->counter.tv_usec += endtime.tv_usec - instr->starttime.tv_usec; + + /* Normalize after each add to avoid overflow/underflow of tv_usec */ + while (instr->counter.tv_usec < 0) + { + instr->counter.tv_usec += 1000000; + instr->counter.tv_sec--; + } + while (instr->counter.tv_usec >= 1000000) + { + instr->counter.tv_usec -= 1000000; + instr->counter.tv_sec++; + } + + instr->starttime.tv_sec = 0; + instr->starttime.tv_usec = 0; + + /* Is this the first tuple of this cycle? */ + if (!instr->running) + { + instr->running = true; + instr->firsttuple = (double) instr->counter.tv_sec + + (double) instr->counter.tv_usec / 1000000.0; + } + + if (returnedTuple) + instr->tuplecount += 1; +} + +/* Finish a run cycle for a plan node */ +void +InstrEndLoop(Instrumentation *instr) +{ + double totaltime; + + if (!instr) + return; + + /* Skip if nothing has happened, or already shut down */ + if (!instr->running) + return; + + /* Accumulate statistics */ + totaltime = (double) instr->counter.tv_sec + + (double) instr->counter.tv_usec / 1000000.0; + + instr->startup += instr->firsttuple; + instr->total += totaltime; + instr->ntuples += instr->tuplecount; + instr->nloops += 1; + + /* Reset for next cycle (if any) */ + instr->running = false; + instr->starttime.tv_sec = 0; + instr->starttime.tv_usec = 0; + instr->counter.tv_sec = 0; + instr->counter.tv_usec = 0; + instr->firsttuple = 0; + instr->tuplecount = 0; +} |