Header And Logo

PostgreSQL
| The world's most advanced open source database.

instrument.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * instrument.c
00004  *   functions for instrumentation of plan execution
00005  *
00006  *
00007  * Copyright (c) 2001-2013, PostgreSQL Global Development Group
00008  *
00009  * IDENTIFICATION
00010  *    src/backend/executor/instrument.c
00011  *
00012  *-------------------------------------------------------------------------
00013  */
00014 #include "postgres.h"
00015 
00016 #include <unistd.h>
00017 
00018 #include "executor/instrument.h"
00019 
00020 BufferUsage pgBufferUsage;
00021 
00022 static void BufferUsageAccumDiff(BufferUsage *dst,
00023                      const BufferUsage *add, const BufferUsage *sub);
00024 
00025 
00026 /* Allocate new instrumentation structure(s) */
00027 Instrumentation *
00028 InstrAlloc(int n, int instrument_options)
00029 {
00030     Instrumentation *instr;
00031 
00032     /* initialize all fields to zeroes, then modify as needed */
00033     instr = palloc0(n * sizeof(Instrumentation));
00034     if (instrument_options & (INSTRUMENT_BUFFERS | INSTRUMENT_TIMER))
00035     {
00036         bool        need_buffers = (instrument_options & INSTRUMENT_BUFFERS) != 0;
00037         bool        need_timer = (instrument_options & INSTRUMENT_TIMER) != 0;
00038         int         i;
00039 
00040         for (i = 0; i < n; i++)
00041         {
00042             instr[i].need_bufusage = need_buffers;
00043             instr[i].need_timer = need_timer;
00044         }
00045     }
00046 
00047     return instr;
00048 }
00049 
00050 /* Entry to a plan node */
00051 void
00052 InstrStartNode(Instrumentation *instr)
00053 {
00054     if (instr->need_timer)
00055     {
00056         if (INSTR_TIME_IS_ZERO(instr->starttime))
00057             INSTR_TIME_SET_CURRENT(instr->starttime);
00058         else
00059             elog(ERROR, "InstrStartNode called twice in a row");
00060     }
00061 
00062     /* save buffer usage totals at node entry, if needed */
00063     if (instr->need_bufusage)
00064         instr->bufusage_start = pgBufferUsage;
00065 }
00066 
00067 /* Exit from a plan node */
00068 void
00069 InstrStopNode(Instrumentation *instr, double nTuples)
00070 {
00071     instr_time  endtime;
00072 
00073     /* count the returned tuples */
00074     instr->tuplecount += nTuples;
00075 
00076     /* let's update the time only if the timer was requested */
00077     if (instr->need_timer)
00078     {
00079         if (INSTR_TIME_IS_ZERO(instr->starttime))
00080             elog(ERROR, "InstrStopNode called without start");
00081 
00082         INSTR_TIME_SET_CURRENT(endtime);
00083         INSTR_TIME_ACCUM_DIFF(instr->counter, endtime, instr->starttime);
00084 
00085         INSTR_TIME_SET_ZERO(instr->starttime);
00086     }
00087 
00088     /* Add delta of buffer usage since entry to node's totals */
00089     if (instr->need_bufusage)
00090         BufferUsageAccumDiff(&instr->bufusage,
00091                              &pgBufferUsage, &instr->bufusage_start);
00092 
00093     /* Is this the first tuple of this cycle? */
00094     if (!instr->running)
00095     {
00096         instr->running = true;
00097         instr->firsttuple = INSTR_TIME_GET_DOUBLE(instr->counter);
00098     }
00099 }
00100 
00101 /* Finish a run cycle for a plan node */
00102 void
00103 InstrEndLoop(Instrumentation *instr)
00104 {
00105     double      totaltime;
00106 
00107     /* Skip if nothing has happened, or already shut down */
00108     if (!instr->running)
00109         return;
00110 
00111     if (!INSTR_TIME_IS_ZERO(instr->starttime))
00112         elog(ERROR, "InstrEndLoop called on running node");
00113 
00114     /* Accumulate per-cycle statistics into totals */
00115     totaltime = INSTR_TIME_GET_DOUBLE(instr->counter);
00116 
00117     instr->startup += instr->firsttuple;
00118     instr->total += totaltime;
00119     instr->ntuples += instr->tuplecount;
00120     instr->nloops += 1;
00121 
00122     /* Reset for next cycle (if any) */
00123     instr->running = false;
00124     INSTR_TIME_SET_ZERO(instr->starttime);
00125     INSTR_TIME_SET_ZERO(instr->counter);
00126     instr->firsttuple = 0;
00127     instr->tuplecount = 0;
00128 }
00129 
00130 /* dst += add - sub */
00131 static void
00132 BufferUsageAccumDiff(BufferUsage *dst,
00133                      const BufferUsage *add,
00134                      const BufferUsage *sub)
00135 {
00136     dst->shared_blks_hit += add->shared_blks_hit - sub->shared_blks_hit;
00137     dst->shared_blks_read += add->shared_blks_read - sub->shared_blks_read;
00138     dst->shared_blks_dirtied += add->shared_blks_dirtied - sub->shared_blks_dirtied;
00139     dst->shared_blks_written += add->shared_blks_written - sub->shared_blks_written;
00140     dst->local_blks_hit += add->local_blks_hit - sub->local_blks_hit;
00141     dst->local_blks_read += add->local_blks_read - sub->local_blks_read;
00142     dst->local_blks_dirtied += add->local_blks_dirtied - sub->local_blks_dirtied;
00143     dst->local_blks_written += add->local_blks_written - sub->local_blks_written;
00144     dst->temp_blks_read += add->temp_blks_read - sub->temp_blks_read;
00145     dst->temp_blks_written += add->temp_blks_written - sub->temp_blks_written;
00146     INSTR_TIME_ACCUM_DIFF(dst->blk_read_time,
00147                           add->blk_read_time, sub->blk_read_time);
00148     INSTR_TIME_ACCUM_DIFF(dst->blk_write_time,
00149                           add->blk_write_time, sub->blk_write_time);
00150 }