]> granicus.if.org Git - postgresql/blob - src/backend/executor/instrument.c
b4c613891c4444e21571b46ab0a9a48614faa9ed
[postgresql] / src / backend / executor / instrument.c
1 /*-------------------------------------------------------------------------
2  *
3  * instrument.c
4  *       functions for instrumentation of plan execution
5  *
6  *
7  * Copyright (c) 2001-2006, PostgreSQL Global Development Group
8  *
9  * IDENTIFICATION
10  *        $PostgreSQL: pgsql/src/backend/executor/instrument.c,v 1.18 2006/06/09 19:30:56 tgl Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15
16 #include <unistd.h>
17
18 #include "executor/instrument.h"
19
20
21 /* Allocate new instrumentation structure(s) */
22 Instrumentation *
23 InstrAlloc(int n)
24 {
25         Instrumentation *instr = palloc0(n * sizeof(Instrumentation));
26
27         /* we don't need to do any initialization except zero 'em */
28
29         return instr;
30 }
31
32 /* Entry to a plan node */
33 void
34 InstrStartNode(Instrumentation *instr)
35 {
36         if (INSTR_TIME_IS_ZERO(instr->starttime))
37                 INSTR_TIME_SET_CURRENT(instr->starttime);
38         else
39                 elog(DEBUG2, "InstrStartNode called twice in a row");
40 }
41
42 /* Exit from a plan node */
43 void
44 InstrStopNode(Instrumentation *instr, double nTuples)
45 {
46         instr_time      endtime;
47
48         /* count the returned tuples */
49         instr->tuplecount += nTuples;
50
51         if (INSTR_TIME_IS_ZERO(instr->starttime))
52         {
53                 elog(DEBUG2, "InstrStopNode called without start");
54                 return;
55         }
56
57         INSTR_TIME_SET_CURRENT(endtime);
58
59 #ifndef WIN32
60         instr->counter.tv_sec += endtime.tv_sec - instr->starttime.tv_sec;
61         instr->counter.tv_usec += endtime.tv_usec - instr->starttime.tv_usec;
62
63         /* Normalize after each add to avoid overflow/underflow of tv_usec */
64         while (instr->counter.tv_usec < 0)
65         {
66                 instr->counter.tv_usec += 1000000;
67                 instr->counter.tv_sec--;
68         }
69         while (instr->counter.tv_usec >= 1000000)
70         {
71                 instr->counter.tv_usec -= 1000000;
72                 instr->counter.tv_sec++;
73         }
74 #else                                                   /* WIN32 */
75         instr->counter.QuadPart += (endtime.QuadPart - instr->starttime.QuadPart);
76 #endif
77
78         INSTR_TIME_SET_ZERO(instr->starttime);
79
80         /* Is this the first tuple of this cycle? */
81         if (!instr->running)
82         {
83                 instr->running = true;
84                 instr->firsttuple = INSTR_TIME_GET_DOUBLE(instr->counter);
85         }
86 }
87
88 /* Finish a run cycle for a plan node */
89 void
90 InstrEndLoop(Instrumentation *instr)
91 {
92         double          totaltime;
93
94         /* Skip if nothing has happened, or already shut down */
95         if (!instr->running)
96                 return;
97
98         if (!INSTR_TIME_IS_ZERO(instr->starttime))
99                 elog(DEBUG2, "InstrEndLoop called on running node");
100
101         /* Accumulate per-cycle statistics into totals */
102         totaltime = INSTR_TIME_GET_DOUBLE(instr->counter);
103
104         instr->startup += instr->firsttuple;
105         instr->total += totaltime;
106         instr->ntuples += instr->tuplecount;
107         instr->nloops += 1;
108
109         /* Reset for next cycle (if any) */
110         instr->running = false;
111         INSTR_TIME_SET_ZERO(instr->starttime);
112         INSTR_TIME_SET_ZERO(instr->counter);
113         instr->firsttuple = 0;
114         instr->tuplecount = 0;
115 }