Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : /*
14 : * Martin Kersten
15 : * Performance profiler
16 : * A key issue in developing fast programs using the Monet database
17 : * back-end requires a keen eye on where performance is lost.
18 : * Although performance tracking and measurements are highly
19 : * application dependent, a simple to use tool makes life
20 : * a lot easier.
21 : *
22 : * Activation of the performance monitor has a global effect,
23 : * i.e. all concurrent actions on the kernel are traced,
24 : * but the events are only sent to the client initiated
25 : * the profiler thread.
26 : *
27 : * The profiler event can be handled in several ways.
28 : * The default strategy is to ship the event record immediately over a stream
29 : * to a performance monitor.
30 : * An alternative strategy is preparation of off-line performance analysis.
31 : *
32 : * To reduce the interference of performance measurement with
33 : * the experiments, the user can use an event cache, which is
34 : * emptied explicitly upon need.
35 : */
36 : /*
37 : * Using the Monet Performance Profiler is constrained by the mal_profiler.
38 : */
39 : #include "monetdb_config.h"
40 : #include "gdk.h"
41 : #include <time.h>
42 : #include "mal_stack.h"
43 : #include "mal_resolve.h"
44 : #include "mal_exception.h"
45 : #include "mal_client.h"
46 : #include "mal_profiler.h"
47 : #include "mal_interpreter.h"
48 : #include "mal_runtime.h"
49 :
50 : static str
51 0 : CMDopenProfilerStream(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pc)
52 : {
53 0 : (void) cntxt;
54 0 : (void) mb;
55 0 : (void) stk;
56 0 : (void) pc;
57 0 : int m = 0;
58 0 : if (pc->argc == 2 && getArgType(mb, pc, 1) == TYPE_int)
59 0 : m = *getArgReference_int(stk, pc, 1);
60 0 : else if (pc->argc > 2)
61 0 : m = -1;
62 0 : return openProfilerStream(cntxt, m);
63 : }
64 :
65 : static str
66 0 : CMDcloseProfilerStream(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pc)
67 : {
68 0 : (void) mb;
69 0 : (void) stk;
70 0 : (void) pc;
71 0 : return closeProfilerStream(cntxt);
72 : }
73 :
74 : // initialize SQL tracing
75 : static str
76 1 : CMDstartProfiler(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pc)
77 : {
78 1 : (void) mb;
79 1 : (void) stk;
80 1 : (void) pc;
81 1 : (void) cntxt;
82 1 : return startProfiler(cntxt);
83 : }
84 :
85 : static str
86 1 : CMDstopProfiler(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
87 : {
88 1 : (void) mb;
89 1 : (void) stk;
90 1 : (void) pci;
91 :
92 1 : return stopProfiler(cntxt);
93 : }
94 :
95 : // called by the SQL front end optional a directory to keep the traces.
96 : static str
97 18 : CMDstartTrace(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
98 : {
99 18 : (void) mb;
100 18 : (void) stk;
101 18 : (void) pci;
102 :
103 18 : return startTrace(cntxt);
104 : }
105 :
106 : static str
107 22 : CMDstopTrace(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
108 : {
109 22 : (void) mb;
110 22 : (void) stk;
111 22 : (void) pci;
112 22 : return stopTrace(cntxt);
113 : }
114 :
115 : static str
116 0 : CMDnoopProfiler(void *res)
117 : {
118 0 : (void) res; /* fool compiler */
119 0 : return MAL_SUCCEED;
120 : }
121 :
122 : static str
123 0 : CMDcleanupTraces(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
124 : {
125 0 : (void) mb;
126 0 : (void) stk;
127 0 : (void) pci;
128 0 : cleanupTraces(cntxt);
129 0 : return MAL_SUCCEED;
130 : }
131 :
132 : static str
133 8 : CMDgetTrace(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
134 : {
135 8 : str path = *getArgReference_str(stk, pci, 1);
136 8 : bat *res = getArgReference_bat(stk, pci, 0);
137 8 : BAT *bn;
138 :
139 8 : (void) cntxt; /* fool compiler */
140 8 : (void) mb;
141 8 : bn = getTrace(cntxt, path);
142 8 : if (bn) {
143 8 : *res = bn->batCacheid;
144 8 : BBPkeepref(bn);
145 8 : return MAL_SUCCEED;
146 : }
147 0 : throw(MAL, "getTrace", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING "%s", path);
148 : }
149 :
150 : static str
151 2 : CMDgetprofilerlimit(int *res)
152 : {
153 2 : *res = getprofilerlimit();
154 2 : return MAL_SUCCEED;
155 : }
156 :
157 : static str
158 0 : CMDsetprofilerlimit(void *res, const int *lim)
159 : {
160 0 : (void) res;
161 0 : setprofilerlimit(*lim);
162 0 : return MAL_SUCCEED;
163 : }
164 :
165 : /*
166 : * Tracing an active system.
167 : */
168 :
169 : static str
170 0 : CMDsetHeartbeat(void *res, const int *ev)
171 : {
172 0 : (void) res;
173 0 : setHeartbeat(*ev);
174 0 : return MAL_SUCCEED;
175 : }
176 :
177 : static str
178 0 : CMDgetDiskReads(lng *ret)
179 : {
180 0 : *ret = getDiskReads();
181 0 : return MAL_SUCCEED;
182 : }
183 :
184 : static str
185 0 : CMDgetDiskWrites(lng *ret)
186 : {
187 0 : *ret = getDiskWrites();
188 0 : return MAL_SUCCEED;
189 : }
190 :
191 : static str
192 0 : CMDgetUserTime(lng *ret)
193 : {
194 0 : *ret = getUserTime();
195 0 : return MAL_SUCCEED;
196 : }
197 :
198 : static str
199 0 : CMDgetSystemTime(lng *ret)
200 : {
201 0 : *ret = getUserTime();
202 0 : return MAL_SUCCEED;
203 : }
204 :
205 : static str
206 5 : CMDcpustats(lng *user, lng *nice, lng *sys, lng *idle, lng *iowait)
207 : {
208 5 : profilerGetCPUStat(user, nice, sys, idle, iowait);
209 5 : return MAL_SUCCEED;
210 : }
211 :
212 : static str
213 5 : CMDcpuloadPercentage(int *cycles, int *io, const lng *user, const lng *nice,
214 : const lng *sys, const lng *idle, const lng *iowait)
215 : {
216 5 : lng userN, niceN, sysN, idleN, iowaitN, N;
217 5 : *cycles = 0;
218 5 : *io = 0;
219 5 : profilerGetCPUStat(&userN, &niceN, &sysN, &idleN, &iowaitN);
220 5 : N = (userN - *user + niceN - *nice + sysN - *sys);
221 5 : if (N) {
222 0 : *cycles = (int) (((double) N) / (N + idleN - *idle + iowaitN - *iowait) * 100);
223 0 : *io = (int) (((double) iowaitN - *iowait) / (N + idleN - *idle +
224 0 : iowaitN - *iowait) * 100);
225 : }
226 5 : return MAL_SUCCEED;
227 : }
228 :
229 : #include "mel.h"
230 : mel_func profiler_init_funcs[] = {
231 : pattern("profiler", "start", CMDstartProfiler, true, "Start offline performance profiling", noargs),
232 : pattern("profiler", "stop", CMDstopProfiler, true, "Stop offline performance profiling", args(1,1, arg("",void))),
233 : pattern("profiler", "starttrace", CMDstartTrace, true, "Start collecting trace information", noargs),
234 : pattern("profiler", "stoptrace", CMDstopTrace, true, "Stop collecting trace information", args(1,1, arg("",void))),
235 : command("profiler", "setheartbeat", CMDsetHeartbeat, true, "Set heart beat performance tracing", args(1,2, arg("",void),arg("b",int))),
236 : command("profiler", "getlimit", CMDgetprofilerlimit, false, "Get profiler limit", args(1,1, arg("",int))),
237 : command("profiler", "setlimit", CMDsetprofilerlimit, true, "Set profiler limit", args(1,2, arg("",void),arg("l",int))),
238 : pattern("profiler", "openstream", CMDopenProfilerStream, false, "Start profiling the events, send to output stream", args(1,1, arg("",void))),
239 : pattern("profiler", "openstream", CMDopenProfilerStream, false, "Start profiling the events, send to output stream", args(1,2, arg("",void), arg("m",int))),
240 : pattern("profiler", "closestream", CMDcloseProfilerStream, false, "Stop offline proviling", args(1,1, arg("",void))),
241 : command("profiler", "noop", CMDnoopProfiler, false, "Fetch any pending performance events", args(1,1, arg("",void))),
242 : pattern("profiler", "getTrace", CMDgetTrace, false, "Get the trace details of a specific event", args(1,2, batargany("",1),arg("e",str))),
243 : pattern("profiler", "cleanup", CMDcleanupTraces, true, "Remove the temporary tables for profiling", args(1,1, arg("",void))),
244 : command("profiler", "getDiskReads", CMDgetDiskReads, false, "Obtain the number of physical reads", args(1,1, arg("",lng))),
245 : command("profiler", "getDiskWrites", CMDgetDiskWrites, false, "Obtain the number of physical reads", args(1,1, arg("",lng))),
246 : command("profiler", "getUserTime", CMDgetUserTime, false, "Obtain the user timing information.", args(1,1, arg("",lng))),
247 : command("profiler", "getSystemTime", CMDgetSystemTime, false, "Obtain the user timing information.", args(1,1, arg("",lng))),
248 : command("profiler", "cpustats", CMDcpustats, false, "Extract cpu statistics from the kernel", args(5,5, arg("user",lng),arg("nice",lng),arg("sys",lng),arg("idle",lng),arg("iowait",lng))),
249 : command("profiler", "cpuload", CMDcpuloadPercentage, false, "Calculate the average cpu load percentage and io waiting times", args(2,7, arg("cycles",int),arg("io",int),arg("user",lng),arg("nice",lng),arg("sys",lng),arg("idle",lng),arg("iowait",lng))),
250 : { .imp=NULL }
251 : };
252 : #include "mal_import.h"
253 : #ifdef _MSC_VER
254 : #undef read
255 : #pragma section(".CRT$XCU",read)
256 : #endif
257 320 : LIB_STARTUP_FUNC(init_profiler_mal)
258 320 : { mal_module("profiler", NULL, profiler_init_funcs); }
|