1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9/* (c) M Kersten, S Manegold
10 * The easiest calling method is something like:
11 * tomograph -d demo --atlas=10
12 * which connects to the demo database server and
13 * will collect the tomograph pages for at most 10 SQL queries
14 * For each page a gnuplot file, a data file, and the event trace
15 * are collected for more focussed analysis.
16 *
17*/
18
19#include "monetdb_config.h"
20#include "stream.h"
21#include "stream_socket.h"
22#include "mapi.h"
23#include <string.h>
24#include <sys/stat.h>
25#include <signal.h>
26#ifdef HAVE_UNISTD_H
27# include <unistd.h>
28#endif
29#include "mprompt.h"
30#include "dotmonetdb.h"
31#include "eventparser.h"
32
33#ifndef HAVE_GETOPT_LONG
34# include "monet_getopt.h"
35#else
36# ifdef HAVE_GETOPT_H
37# include "getopt.h"
38# endif
39#endif
40
41#include <time.h>
42
43#ifdef NATIVE_WIN32
44#include <direct.h>
45#endif
46
47#define die(dbh, hdl) \
48 do { \
49 if (hdl) \
50 mapi_explain_query(hdl, stderr); \
51 else if (dbh) \
52 mapi_explain(dbh, stderr); \
53 else \
54 fprintf(stderr, "!! command failed\n"); \
55 goto stop_disconnect; \
56 } while (0)
57
58#define doQ(X) \
59 do { \
60 if ((hdl = mapi_query(dbh, X)) == NULL || \
61 mapi_error(dbh) != MOK) \
62 die(dbh, hdl); \
63 } while (0)
64
65static stream *conn = NULL;
66static char hostname[128];
67static char *dbname = NULL;
68#ifdef NATIVE_WIN32
69static char *dirpath= "cache\\";
70#else
71static char *dirpath= "cache/";
72#endif
73static char *prefix = "tomograph";
74static char basefile[BUFSIZ];
75static FILE *tracefd;
76static int64_t startrange = 0, endrange = 0;
77static char *inputfile = NULL;
78static char *title = 0;
79static int beat = 5000;
80static int cpus = 0;
81static int atlas= 32;
82static int atlaspage = 0;
83static FILE *gnudata;
84static Mapi dbh;
85static MapiHdl hdl = NULL;
86
87/*
88 * Parsing the argument list of a MAL call to obtain un-quoted string values
89 */
90static int capturing=0;
91
92#define MAXTHREADS 1048
93#define MAXBOX 32678 /* should be > MAXTHREADS */
94
95static int crossings[MAXTHREADS][MAXTHREADS];
96static int target[MAXTHREADS];
97static int source[MAXTHREADS];
98
99/* color map management, fixed */
100/* see http://www.uni-hamburg.de/Wiss/FB/15/Sustainability/schneider/gnuplot/colors.htm */
101/* The initial dictionary is geared towars TPCH-use */
102typedef struct COLOR {
103 int freq;
104 int64_t timeused;
105 char *mod, *fcn, *col;
106} Color;
107
108#define NUM_COLORS ((int) (sizeof(dictionary) / sizeof(RGB)))
109#define MAX_LEGEND_SHORT 30 /* max. size of colormap / legend */
110#define PERCENTAGE 0.01 /* threshold for time filter */
111
112typedef struct {
113 char *name;
114 char *hsv;
115 int red, green, blue;
116} RGB;
117
118/* the color table is randomized */
119RGB
120dictionary[] = {
121/* 227 */ { "saddlebrown", "#8B4513", 139, 69, 19 },
122/* 557 */ { "navyblue", "#9FAFDF", 159, 175, 223 },
123/* 734 */ { "lightyellow", "#FFFFE0", 255, 255, 224 },
124/* 750 */ { "azure", "#F0FFFF", 240, 255, 255 },
125/* 496 */ { "turquoise", "#40E0D0", 64, 224, 208 },
126/* 750 */ { "mintcream", "#F5FFFA", 245, 255, 250 },
127/* 278 */ { "darkcyan", "#008B8B", 0, 139, 139 },
128/* 239 */ { "darkolivegreen", "#556B2F", 85, 107, 47 },
129/* 128 */ { "maroon", "#800000", 128, 0, 0 },
130/* 735 */ { "whitesmoke", "#F5F5F5", 245, 245, 245 },
131/* 315 */ { "dimgray", "#696969", 105, 105, 105 },
132/* 492 */ { "salmon", "#FA8072", 250, 128, 114 },
133/* 353 */ { "mediumvioletred", "#C71585", 199, 21, 133 },
134/* 477 */ { "mediumaquamarine", "#66CDAA", 102, 205, 170 },
135/* 139 */ { "darkblue", "#00008B", 0, 0, 139 },
136/* 710 */ { "beige", "#F5F5DC", 245, 245, 220 },
137/* 352 */ { "mediumseagreen", "#3CB371", 60, 179, 113 },
138/* 413 */ { "cadetblue", "#5F9EA0", 95, 158, 160 },
139/* 660 */ { "gainsboro", "#DCDCDC", 220, 220, 220 },
140/* 465 */ { "mediumslateblue", "#7B68EE", 123, 104, 238 },
141/* 623 */ { "thistle", "#D8BFD8", 216, 191, 216 },
142/* 745 */ { "floralwhite", "#FFFAF0", 255, 250, 240 },
143/* 710 */ { "lemonchiffon", "#FFFACD", 255, 250, 205 },
144/* 765 x { "white", "#FFFFFF", 255, 255, 255 }, */
145/* 256 */ { "olive", "#808000", 128, 128, 0 },
146/* 255 */ { "red", "#FF0000", 255, 0, 0 },
147/* 380 */ { "steelblue", "#4682B4", 70, 130, 180 },
148/* 664 */ { "moccasin", "#FFE4B5", 255, 228, 181 },
149/* 395 */ { "darkorange", "#FF8C00", 255, 140, 0 },
150/* 507 */ { "darkgray", "#A9A9A9", 169, 169, 169 },
151/* 272 */ { "seagreen", "#2E8B57", 46, 139, 87 },
152/* 755 */ { "snow", "#FFFAFA", 255, 250, 250 },
153/* 284 */ { "olivedrab", "#6B8E23", 107, 142, 35 },
154/* 382 */ { "chartreuse", "#7FFF00", 127, 255, 0 },
155/* 478 */ { "palevioletred", "#DB7093", 219, 112, 147 },
156/* 710 */ { "lavender", "#E6E6FA", 230, 230, 250 },
157/* 162 */ { "midnightblue", "#191970", 25, 25, 112 },
158/* 708 */ { "mistyrose", "#FFE4E1", 255, 228, 225 },
159/* 425 */ { "tomato", "#FF6347", 255, 99, 71 },
160/* 576 */ { "skyblue", "#87CEEB", 135, 206, 235 },
161/* 420 */ { "orange", "#FFA500", 255, 165, 0 },
162/* 128 */ { "green", "#008000", 0, 128, 0 },
163/* 740 */ { "lavenderblush", "#FFF0F5", 255, 240, 245 },
164/* 380 */ { "lightseagreen", "#20B2AA", 32, 178, 170 },
165/* 415 */ { "darkturquoise", "#00CED1", 0, 206, 209 },
166/* 526 */ { "lightgreen", "#90EE90", 144, 238, 144 },
167/* 395 */ { "royalblue", "#4169E1", 65, 105, 225 },
168/* 205 */ { "darkslategray", "#2F4F4F", 47, 79, 79 },
169/* 415 */ { "goldenrod", "#DAA520", 218, 165, 32 },
170/* 735 */ { "honeydew", "#F0FFF0", 240, 255, 240 },
171/* 246 */ { "firebrick", "#B22222", 178, 34, 34 },
172/* 255 */ { "lime", "#00FF00", 0, 255, 0 },
173/* 381 */ { "gray", "#7F7F7F", 127, 127, 127 },
174/* 128 */ { "navy", "#000080", 0, 0, 128 },
175/* 479 */ { "darkkhaki", "#BDB76B", 189, 183, 107 },
176/* 345 */ { "chocolate", "#D2691E", 210, 105, 30 },
177/* 474 */ { "rosybrown", "#BC8F8F", 188, 143, 143 },
178/* 255 */ { "blue", "#0000FF", 0, 0, 255 },
179/* 408 */ { "lightslategray", "#778899", 119, 136, 153 },
180/* 504 */ { "sandybrown", "#F4A460", 244, 164, 96 },
181/* 728 */ { "oldlace", "#FDF5E6", 253, 245, 230 },
182/* 249 */ { "brown", "#A52A2A", 165, 42, 42 },
183/* 743 */ { "aliceblue", "#F0F8FF", 240, 248, 255 },
184/* 630 */ { "lightpink", "#FFB6C1", 255, 182, 193 },
185/* 0 x { "black", "#000000", 0, 0, 0 }, */
186/* 404 */ { "mediumspringgreen", "#00FA9A", 0, 250, 154 },
187/* 486 */ { "cornflowerblue", "#6495ED", 100, 149, 237 },
188/* 723 */ { "cornsilk", "#FFF8DC", 255, 248, 220 },
189/* 710 */ { "lightgoldenrodyellow", "#FAFAD2", 250, 250, 210 },
190/* 207 */ { "forestgreen", "#228B22", 34, 139, 34 },
191/* 707 */ { "papayawhip", "#FFEFD5", 255, 239, 213 },
192/* 640 */ { "palegoldenrod", "#EEE8AA", 238, 232, 170 },
193/* 278 */ { "darkmagenta", "#8B008B", 139, 0, 139 },
194/* 576 */ { "silver", "#C0C0C0", 192, 192, 192 },
195/* 305 */ { "limegreen", "#32CD32", 50, 205, 50 },
196/* 429 */ { "dodgerblue", "#1E90FF", 30, 144, 255 },
197/* 324 */ { "orangered", "#FF4500", 255, 69, 0 },
198/* 540 */ { "hotpink", "#FF69B4", 255, 105, 180 },
199/* 205 */ { "mediumblue", "#0000CD", 0, 0, 205 },
200/* 734 */ { "lightcyan", "#E0FFFF", 224, 255, 255 },
201/* 407 */ { "blueviolet", "#8A2BE2", 138, 43, 226 },
202/* 256 */ { "purple", "#800080", 128, 0, 128 },
203/* 389 */ { "indianred", "#CD5C5C", 205, 92, 92 },
204/* 384 */ { "slategray", "#708090", 112, 128, 144 },
205/* 750 */ { "ivory", "#FFFFF0", 255, 255, 240 },
206/* 650 */ { "navajowhite", "#FFDEAD", 255, 222, 173 },
207/* 382 */ { "springgreen", "#00FF7F", 0, 255, 127 },
208/* 606 */ { "violet", "#EE82EE", 238, 130, 238 },
209/* 510 */ { "aqua", "#00FFFF", 0, 255, 255 },
210/* 510 */ { "cyan", "#00FFFF", 0, 255, 255 },
211/* 359 */ { "darkviolet", "#9400D3", 148, 0, 211 },
212/* 602 */ { "plum", "#DDA0DD", 221, 160, 221 },
213/* 591 */ { "lightskyblue", "#87CEFA", 135, 206, 250 },
214/* 720 */ { "linen", "#FAF0E6", 250, 240, 230 },
215/* 555 */ { "palegreen", "#98FB98", 152, 251, 152 },
216/* 272 */ { "darkslateblue", "#483D8B", 72, 61, 139 },
217/* 462 */ { "coral", "#FF7F50", 255, 127, 80 },
218/* 544 */ { "orchid", "#DA70D6", 218, 112, 214 },
219/* 505 */ { "darksalmon", "#E9967A", 233, 150, 122 },
220/* 650 */ { "pink", "#FFC0CB", 255, 192, 203 },
221/* 300 */ { "crimson", "#DC143C", 220, 20, 60 },
222/* 394 */ { "yellowgreen", "#9ACD32", 139, 205, 50 },
223/* 700 */ { "antiquewhite", "#FAEBD7", 250, 235, 215 },
224/* 407 */ { "darkorchid", "#9932CC", 153, 50, 204 },
225/* 651 */ { "paleturquoise", "#AFEEEE", 175, 238, 238 },
226/* 633 */ { "lightgrey", "#D3D3D3", 211, 211, 211 },
227/* 679 */ { "bisque", "#FFE4C4", 255, 228, 196 },
228/* 422 */ { "deeppink", "#FF1493", 255, 20, 147 },
229/* 139 */ { "darkred", "#8B0000", 139, 0, 0 },
230/* 475 */ { "greenyellow", "#ADFF2F", 173, 255, 47 },
231/* 205 */ { "indigo", "#4B0082", 75, 0, 130 },
232/* 446 */ { "deepskyblue", "#00BFFF", 0, 191, 255 },
233/* 329 */ { "darkgoldenrod", "#B8860B", 184, 134, 11 },
234/* 470 */ { "gold", "#FFD700", 255, 215, 0 },
235/* 610 */ { "khaki", "#F0E68C", 240, 230, 140 },
236/* 485 */ { "mediumturquoise", "#48D1CC", 72, 209, 204 },
237/* 100 */ { "darkgreen", "#006400", 0, 100, 0 },
238/* 510 */ { "fuchsia", "#FF00FF", 255, 0, 255 },
239/* 510 */ { "magenta", "#FF00FF", 255, 0, 255 },
240/* 751 */ { "ghostwhite", "#F8F8FF", 248, 248, 255 },
241/* 658 */ { "peachpuff", "#FFDAB9", 255, 218, 185 },
242/* 478 */ { "mediumpurple", "#9370DB", 147, 112, 219 },
243/* 376 */ { "lawngreen", "#7CFC00", 124, 252, 0 },
244/* 401 */ { "peru", "#CD853F", 205, 133, 63 },
245/* 695 */ { "blanchedalmond", "#FFEBCD", 255, 235, 205 },
246/* 256 */ { "teal", "#008080", 0, 128, 128 },
247/* 594 */ { "lightsteelblue", "#B0C4DE", 176, 196, 222 },
248/* 474 */ { "darkseagreen", "#8FBC8F", 143, 188, 143 },
249/* 287 */ { "sienna", "#A0522D", 160, 82, 45 },
250/* 401 */ { "slateblue", "#6A5ACD", 106, 90, 205 },
251/* 646 */ { "wheat", "#F5DEB3", 245, 222, 179 },
252/* 738 */ { "seashell", "#FFF5EE", 255, 245, 238 },
253/* 530 */ { "tan", "#D2B48C", 210, 180, 140 },
254/* 510 */ { "yellow", "#FFFF00", 255, 255, 0 },
255/* 496 */ { "lightcoral", "#F08080", 240, 128, 128 },
256/* 630 */ { "powderblue", "#B0E0E6", 176, 224, 230 },
257/* 541 */ { "burlywood", "#DEB887", 222, 184, 135 },
258/* 594 */ { "aquamarine", "#7FFFD4", 127, 255, 212 },
259/* 619 */ { "lightblue", "#ADD8E6", 173, 216, 230 },
260/* 537 */ { "lightsalmon", "#FFA07A", 255, 160, 122 },
261/* 482 */ { "mediumorchid", "#BA55D3", 186, 85, 211 },
262};
263
264/* initial mod.fcn list for adaptive colormap, this ensures ease of comparison */
265Color
266base_colors[NUM_COLORS] = {
267 /* reserve (base_)colors[0] for generic "*.*" */
268/* 99999 { 0, 0, "*", "*", 0 },*/
269/* arbitrarily ordered by descending frequency in TPCH SF-100 with 32 threads */
270/* 11054 */ { 0, 0, "algebra", "projection", 0 },
271/* 10355 */ { 0, 0, "language", "pass", 0 },
272/* 5941 */ { 0, 0, "sql", "bind", 0 },
273/* 5664 */ { 0, 0, "mat", "packIncrement", 0 },
274/* 4796 */ { 0, 0, "algebra", "select", 0 },
275/* 4789 */ { 0, 0, "algebra", "subjoin", 0 },
276/* 2664 */ { 0, 0, "sql", "projectdelta", 0 },
277/* 2112 */ { 0, 0, "batcalc", "!=", 0 },
278/* 1886 */ { 0, 0, "sql", "bind_idxbat", 0 },
279/* 1881 */ { 0, 0, "algebra", "projectionPath", 0 },
280/* */ { 0, 0, "algebra", "tinter", 0 },
281/* */ { 0, 0, "algebra", "tdiff", 0 },
282/* 1013 */ { 0, 0, "sql", "tid", 0 },
283/* 832 */ { 0, 0, "bat", "mergecand", 0 },
284/* 813 */ { 0, 0, "sql", "delta", 0 },
285/* 766 */ { 0, 0, "aggr", "subsum", 0 },
286/* 610 */ { 0, 0, "batcalc", "*", 0 },
287/* 577 */ { 0, 0, "group", "subgroupdone", 0 },
288/* 577 */ { 0, 0, "group", "groupdone", 0 },
289/* 481 */ { 0, 0, "sql", "subdelta", 0 },
290/* 481 */ { 0, 0, "sql", "subsort", 0 },
291/* 448 */ { 0, 0, "batcalc", "-", 0 },
292/* 334 */ { 0, 0, "bat", "mirror", 0 },
293/* 300 */ { 0, 0, "group", "subgroup", 0 },
294/* 300 */ { 0, 0, "group", "group", 0 },
295/* 264 */ { 0, 0, "batcalc", "==", 0 },
296/* 260 */ { 0, 0, "batcalc", "ifthenelse", 0 },
297/* 209 */ { 0, 0, "batcalc", "hge", 0 },
298/* 209 */ { 0, 0, "calc", "str", 0 },
299/* 207 */ { 0, 0, "aggr", "sum", 0 },
300/* 200 */ { 0, 0, "algebra", "thetaselect", 0 },
301/* 200 */ { 0, 0, "algebra", "selectNotNil", 0 },
302/* 197 */ { 0, 0, "aggr", "subcount", 0 },
303/* 166 */ { 0, 0, "batcalc", "dbl", 0 },
304/* 166 */ { 0, 0, "algebra", "tinter", 0 },
305/* 131 */ { 0, 0, "algebra", "leftjoin", 0 },
306/* 128 */ { 0, 0, "batcalc", "isnil", 0 },
307/* 98 */ { 0, 0, "aggr", "count", 0 },
308/* 97 */ { 0, 0, "batcalc", ">", 0 },
309/* */ { 0, 0, "bat", "mergecand", 0 },
310/* 96 */ { 0, 0, "batmtime", "year", 0 },
311/* 96 */ { 0, 0, "batcalc", "<", 0 },
312/* 79 */ { 0, 0, "sql", "assert", 0 },
313/* 72 */ { 0, 0, "sql", "rsColumn", 0 },
314/* 72 */ { 0, 0, "sql", "mvc", 0 },
315/* 69 */ { 0, 0, "mkey", "bulk_rotate_xor_hash", 0 },
316/* 69 */ { 0, 0, "calc", "lng", 0 },
317/* 69 */ { 0, 0, "batcalc", "hash", 0 },
318/* 66 */ { 0, 0, "pqueue", "utopn_max", 0 },
319/* 66 */ { 0, 0, "algebra", "tdiff", 0 },
320/* 53 */ { 0, 0, "calc", "int", 0 },
321/* 47 */ { 0, 0, "algebra", "likeselect", 0 },
322/* 44 */ { 0, 0, "sql", "exportOperation", 0 },
323/* 42 */ { 0, 0, "algebra", "subslice", 0 },
324/* 36 */ { 0, 0, "pqueue", "utopn_min", 0 },
325/* 36 */ { 0, 0, "pqueue", "topn_max", 0 },
326/* 33 */ { 0, 0, "aggr", "submin", 0 },
327/* 32 */ { 0, 0, "batalgebra", "like", 0 },
328/* 32 */ { 0, 0, "batcalc", "or", 0 },
329/* 32 */ { 0, 0, "batcalc", "and", 0 },
330/* 32 */ { 0, 0, "batcalc", "+", 0 },
331/* 24 */ { 0, 0, "sql", "setVariable", 0 },
332/* 23 */ { 0, 0, "language", "dataflow", 0 },
333/* 21 */ { 0, 0, "algebra", "subsort", 0 },
334/* 20 */ { 0, 0, "sql", "catalog", 0 },
335/* 19 */ { 0, 0, "calc", "ptr", 0 },
336/* 18 */ { 0, 0, "sql", "resultSet", 0 },
337/* 18 */ { 0, 0, "sql", "exportResult", 0 },
338/* 18 */ { 0, 0, "io", "stdout", 0 },
339/* 18 */ { 0, 0, "calc", "!=", 0 },
340/* 10 */ { 0, 0, "sql", "update", 0 },
341/* 9 */ { 0, 0, "mtime", "addmonths", 0 },
342/* 9 */ { 0, 0, "calc", "ifthenelse", 0 },
343/* 8 */ { 0, 0, "sql", "copy_from", 0 },
344/* 8 */ { 0, 0, "sql", "affectedRows", 0 },
345/* 8 */ { 0, 0, "calc", "isnil", 0 },
346/* 7 */ { 0, 0, "bat", "append", 0 },
347/* 6 */ { 0, 0, "mat", "pack", 0 },
348/* 6 */ { 0, 0, "bat", "new", 0 },
349/* 5 */ { 0, 0, "batcalc", "/", 0 },
350/* 4 */ { 0, 0, "sql", "exportValue", 0 },
351/* 4 */ { 0, 0, "calc", "date", 0 },
352/* 4 */ { 0, 0, "calc", "+", 0 },
353/* 3 */ { 0, 0, "calc", "/", 0 },
354/* 3 */ { 0, 0, "batstr", "substring", 0 },
355/* 3 */ { 0, 0, "batcalc", "lng", 0 },
356/* 2 */ { 0, 0, "calc", "min", 0 },
357/* 2 */ { 0, 0, "calc", "max", 0 },
358/* 2 */ { 0, 0, "calc", "bit", 0 },
359/* 2 */ { 0, 0, "calc", "*", 0 },
360/* 2 */ { 0, 0, "algebra", "subthetajoin", 0 },
361/* 1 */ { 0, 0, "sql", "dec_round", 0 },
362/* 1 */ { 0, 0, "pqueue", "topn_min", 0 },
363/* 1 */ { 0, 0, "mtime", "date_sub_msec_interval", 0 },
364/* 1 */ { 0, 0, "iterator", "next", 0 },
365/* 1 */ { 0, 0, "iterator", "new", 0 },
366/* 1 */ { 0, 0, "calc", "dbl", 0 },
367/* 1 */ { 0, 0, "calc", "-", 0 },
368/* 1 */ { 0, 0, "calc", "==", 0 },
369/* 1 */ { 0, 0, "bat", "reverse", 0 },
370/* 1 */ { 0, 0, "bat", "insert", 0 },
371/* 1 */ { 0, 0, "algebra", "project", 0 },
372/* 1 */ { 0, 0, "algebra", "fetch", 0 },
373/* 1 */ { 0, 0, "aggr", "max", 0 },
374/* ? */ { 0, 0, "aggr", "avg", 0 },
375/* ? */ { 0, 0, "aggr", "group_concat", 0 },
376/* ? */ { 0, 0, "aggr", "subavg", 0 },
377/* ? */ { 0, 0, "aggr", "submedian", 0 },
378/* ? */ { 0, 0, "aggr", "subquantile", 0 },
379/* ? */ { 0, 0, "aggr", "substdev", 0 },
380/* ? */ { 0, 0, "batcalc", "floor", 0 },
381/* ? */ { 0, 0, "batcalc", "identity", 0 },
382/* ? */ { 0, 0, "batmkey", "hash", 0 },
383/* ? */ { 0, 0, "calc", "hge", 0 },
384/* ? */ { 0, 0, "batcalc", "hge", 0 },
385/* ? */ { 0, 0, "algebra", "firstn", 0 },
386/* ? */ { 0, 0, "sql", "single", 0 },
387/* ? */ { 0, 0, "algebra", "crossproduct", 0 },
388/* ? */ { 0, 0, "profiler", "wait", 0 },
389/* ? */ { 0, 0, "querylog", "define", 0 },
390/* ? */ { 0, 0, "*", "*", 0 },
391/* 0 */ { 0, 0, 0, 0, 0 }
392};
393
394
395Color
396colors[NUM_COLORS] = {{0,0,0,0,0}};
397
398#ifdef NUMAprofiling
399static void
400showNumaHeatmap(void){
401 int i,j =0;
402 int max= 0;
403 FILE *f;
404 char buf[BUFSIZ];
405
406
407 snprintf(buf,BUFSIZ,"%s_heatmap.csv",basefile);
408 f= fopen(buf,"a");
409 if( f == NULL){
410 fprintf(stderr,"Can not create %s\n",buf);
411 exit(-1);
412 }
413 for( i=0; i< MAXTHREADS; i++){
414 if( target[i])
415 for(j=MAXTHREADS-1; j>0 && crossings[i][j]; j--)
416 ;
417 if (j > max) max =j;
418 }
419 for( i=0; i< max; i++)
420 if( target[i] && source[i] ){
421 for(j=0; j< max; j++)
422 if( target[j] && source[j])
423 fprintf(stderr,"%d\t", crossings[i][j]);
424 fprintf(stderr,"\n");
425 }
426
427 for( i=0; i< MAXTHREADS; i++){
428 for(j=0; j< MAXTHREADS; j++)
429 crossings[i][j]=0;
430 target[i]=0;
431 source[i]=0;
432 }
433}
434#endif
435
436static void
437usageTomograph(void)
438{
439 fprintf(stderr, "tomograph [options]\n");
440 fprintf(stderr, " -d | --dbname=<database_name>\n");
441 fprintf(stderr, " -u | --user=<user>\n");
442 fprintf(stderr, " -P | --password=<password>\n");
443 fprintf(stderr, " -p | --port=<portnr>\n");
444 fprintf(stderr, " -h | --host=<hostname>\n");
445 fprintf(stderr, " -T | --title=<plot title>\n");
446 fprintf(stderr, " -r | --range=<starttime>-<endtime>[ms,s]\n");
447 fprintf(stderr, " -i | --input=<profiler event file >\n");
448 fprintf(stderr, " -o | --output=<dir/file prefix > (default 'cache/<dbname>'\n");
449 fprintf(stderr, " -b | --beat=<delay> in milliseconds (default 5000)\n");
450 fprintf(stderr, " -A | --atlas=<number> maximum number of queries (default 1)\n");
451 fprintf(stderr, " -D | --debug\n");
452 fprintf(stderr, " -? | --help\n");
453 exit(-1);
454}
455
456/* Any signal should be captured and turned into a graceful
457 * termination of the profiling session. */
458static void createTomogram(void);
459
460static void
461stopListening(int i)
462{
463#define BSIZE 64*1024
464 char buf[BSIZE + BUFSIZ]={0};
465 char pages[BSIZE]={0};
466 int j, error =0, plen =0;
467 if( i)
468 fprintf(stderr,"signal %d received\n",i);
469 if( dbh)
470 doQ("profiler.stop();");
471stop_disconnect:
472 if (atlas != atlaspage )
473 createTomogram();
474 // show follow up action only once
475 if(atlaspage >= 1){
476 for (i = 0; i < atlaspage; i++){
477 snprintf(buf, BUFSIZ, "gnuplot %s_%02d.gpl;", basefile, i);
478 if( error == 0){
479 fprintf(stderr,"-- exec:%s\n",buf);
480 error = system(buf);
481 if( error){
482 fprintf(stderr, "To finish the atlas make sure gnuplot is available and run:\n");
483 for (j=i; j< atlaspage; j++)
484 fprintf(stderr, "gnuplot %s_%02d.gpl\n", basefile, j);
485 }
486 }
487
488 snprintf(buf, BUFSIZ, "%s_%02d.pdf ", basefile, i);
489 plen += snprintf(pages + plen, BSIZE -plen,"%s",buf);
490 if ( plen >= BSIZE-1){
491 error = -1;
492 break;
493 }
494 }
495
496
497 if( error == 0) {
498 snprintf(buf, BSIZE, "gs -q -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=%s.pdf -dBATCH %s",basefile,pages);
499 fprintf(stderr,"-- exec:%s\n",buf);
500 error = system(buf);
501 }
502 if( error == 0)
503 fprintf(stderr,"-- done: %s.pdf\n", basefile);
504 else
505 fprintf(stderr, "gs -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=%s.pdf -dBATCH %s\n", basefile, pages);
506 }
507
508 if(dbh)
509 mapi_disconnect(dbh);
510 exit(0);
511}
512
513typedef struct BOX {
514 int row;
515 int color;
516 int thread;
517 int64_t clkstart, clkend;
518 int64_t ticks;
519 int64_t memstart, memend;
520 int64_t footstart, tmpspace;
521 int64_t inblock, oublock;
522 int64_t majflt, nswap, csw;
523 char *stmt;
524 char *fcn;
525 char *numa;
526 int state;
527} Box;
528
529int threads[MAXTHREADS];
530int64_t lastclk[MAXTHREADS];
531Box *box= 0;
532int topbox = 0;
533int maxbox = 0;
534int events = 0;
535
536int64_t totalclkticks = 0; /* number of clock ticks reported */
537int64_t totalexecticks = 0; /* number of ticks reported for processing */
538int64_t lastclktick = 0;
539int64_t totalticks = 0;
540int64_t starttime = 0;
541int figures = 0;
542char *currentfunction= 0;
543int object = 1;
544
545static void resetTomograph(void){
546 static char buf[BUFSIZ];
547 int i;
548
549 snprintf(buf,BUFSIZ,"%s_%02d.trace", basefile, atlaspage);
550
551 if( inputfile && strcmp(inputfile,buf) == 0 ){
552 fprintf(stderr,"Should not overwrite existing trace file '%s'\n",buf);
553 exit(-1);
554 }
555 if( inputfile == 0 ){
556 // don't create another tracefile when input is given
557 tracefd = fopen(buf,"w");
558 if( tracefd == NULL){
559 fprintf(stderr,"Could not create trace file '%s'\n",buf);
560 exit(-1);
561 }
562 }
563 if (debug)
564 fprintf(stderr, "RESET tomograph %d\n", atlaspage);
565 for( i =0; i < NUM_COLORS; i++){
566 colors[i].freq = 0;
567 colors[i].timeused = 0;
568 }
569 for(i=0; i< MAXTHREADS; i++)
570 lastclk[i]=0;
571 topbox =0;
572 events = 0;
573 for (i = 0; i < MAXTHREADS; i++)
574 threads[i] = topbox++;
575 for ( i=MAXTHREADS; i< maxbox; i++){
576 if( box[i].fcn ){
577 free(box[i].fcn);
578 box[i].fcn=0;
579 }
580 }
581 memset((char*) box, 0, sizeof(Box) * maxbox);
582
583 totalclkticks = 0;
584 totalexecticks = 0;
585 lastclktick = 0;
586 figures = 0;
587 currentfunction = 0;
588 currentquery = 0;
589 object = 1;
590}
591
592static int64_t
593gnuXtics(int withlabels)
594{
595 const char * scalename = "MB";
596 int digits;
597 int64_t scale =1, tw, w = lastclktick - starttime;
598 int i;
599
600 if (w >= 10 * US_DD) {
601 scale = US_DD;
602 scalename = "d\0\0days";
603 } else if (w >= 10 * US_HH) {
604 scale = US_HH;
605 scalename = "h\0\0hours";
606 } else if (w >= 10 * US_MM) {
607 scale = US_MM;
608 scalename = "m\0\0minutes";
609 } else if (w >= US_SS) {
610 scale = US_SS;
611 scalename = "s\0\0seconds";
612 } else if (w >= US_MS) {
613 scale = US_MS;
614 scalename = "ms\0milliseconds";
615 } else {
616 scale = 1;
617 scalename = "us\0microseconds";
618 }
619 for (tw = (scale / 10 > 1)? scale/10:1; 15 * tw < w; tw *= 10)
620 ;
621 if (3 * tw > w)
622 tw /= 4;
623 else if (6 * tw > w)
624 tw /= 2;
625 if (w / scale >= 1000)
626 digits = 0;
627 else if (w / scale >= 100)
628 digits = 1;
629 else if (w / scale >= 10)
630 digits = 2;
631 else
632 digits = 3;
633
634 if(withlabels)
635 fprintf(gnudata, "set xtics (\"0\" 0.0,");
636 else
637 fprintf(gnudata, "set xtics ( \"\" 0.0,");
638 for (i = 1; i * tw < w - 2 * tw / 3; i++){
639 if( withlabels)
640 fprintf(gnudata, "\"%g\" %"PRId64".0,", ((double) i) * tw / scale, i * tw);
641 else
642 fprintf(gnudata, "\"\" %"PRId64".0,", i * tw);
643 }
644 if( withlabels)
645 fprintf(gnudata, "\"%.*f %s\" %"PRId64".0", digits, ((double) w) / scale, scalename, w);
646 else
647 fprintf(gnudata, "\"\" %"PRId64".0", w);
648 fprintf(gnudata, ")\n");
649 w /= 10;
650 fprintf(gnudata, "set grid xtics\n");
651 return w;
652}
653
654static void dumpbox(int i)
655{
656 fprintf(stderr,"object %d thread %d[%4d] row %d color %d ", object, box[i].thread,i, box[i].row, box[i].color);
657 if (box[i].fcn)
658 fprintf(stderr,"%s ", box[i].fcn);
659 fprintf(stderr,"clk %"PRId64" - %"PRId64" ", box[i].clkstart, box[i].clkend);
660 fprintf(stderr,"mem %"PRId64" - %"PRId64" ", box[i].memstart, box[i].memend);
661 fprintf(stderr,"foot %"PRId64" - %"PRId64" ", box[i].footstart, box[i].tmpspace);
662 fprintf(stderr,"ticks %"PRId64" ", box[i].ticks);
663 if (box[i].stmt)
664 fprintf(stderr,"\"%s\"", box[i].stmt);
665 else
666 fprintf(stderr,"MISSING");
667 fprintf(stderr,"\n");
668}
669
670static int
671cmp_clr(const void * _one , const void * _two)
672{
673 Color *one = (Color*) _one, *two = (Color*) _two;
674
675 /* "*.*" should always be smallest / first */
676 if (one->mod && one->fcn &&
677 one->mod[0] == '*' && one->mod[1] == '\0' &&
678 one->fcn[0] == '*' && one->fcn[1] == '\0')
679 return -1;
680 if (two->mod && two->fcn &&
681 two->mod[0] == '*' && two->mod[1] == '\0' &&
682 two->fcn[0] == '*' && two->fcn[1] == '\0')
683 return 1;
684
685 /* order on timeused; use freq as tiebreaker */
686 return ((one->timeused < two->timeused) ? -1 :
687 ((one->timeused > two->timeused) ? 1 :
688 ((one->freq < two->freq) ? -1 :
689 ((one->freq > two->freq) ? 1 :
690 0))));
691}
692
693static void
694initcolors(void)
695{
696 int i = 0;
697
698 for (i = 0; i < NUM_COLORS && base_colors[i].mod; i++) {
699 colors[i].mod = base_colors[i].mod;
700 colors[i].fcn = base_colors[i].fcn;
701 colors[i].freq = 0;
702 colors[i].timeused = 0;
703 colors[i].col = dictionary[i].hsv;
704 }
705 for (; i < NUM_COLORS; i++) {
706 colors[i].mod = 0;
707 colors[i].fcn = 0;
708 colors[i].freq = 0;
709 colors[i].timeused = 0;
710 colors[i].col = dictionary[i].hsv;
711 }
712}
713
714static void
715dumpboxes(void)
716{
717 FILE *f = 0;
718 char buf[BUFSIZ];
719 int i;
720 int written = 0;
721
722 snprintf(buf, BUFSIZ, "%s_%02d.dat", basefile,atlaspage);
723 f = fopen(buf, "w");
724 if(f == NULL){
725 fprintf(stderr,"Could not create file '%s'\n",buf);
726 exit(-1);
727 }
728
729 for (i = 0; i < topbox; i++)
730 if (box[i].clkend && box[i].fcn) {
731 fprintf(f, "%"PRId64" %f %f %"PRId64" %"PRId64 " %" PRId64 " %" PRId64 " %" PRId64"\n", box[i].clkstart, (box[i].memend / 1024.0), box[i].tmpspace/1024.0, box[i].inblock, box[i].oublock, box[i].majflt, box[i].nswap,box[i].csw);
732 written++;
733 }
734 if( written == 0){
735 topbox = 0;
736 fprintf(stderr,"Insufficient data for %s\n",buf);
737 }
738
739 if (f)
740 (void) fclose(f);
741}
742
743/* produce memory thread trace */
744static void
745showmemory(void)
746{
747 int i;
748 int64_t max = 0, min = INT64_MAX;
749 double mx, mn, mm;
750 double scale = 1.0;
751 const char * scalename = "MB";
752 int digits;
753
754 for (i = 0; i < topbox; i++)
755 if (box[i].clkend && box[i].fcn) {
756 if (box[i].memstart > max)
757 max = box[i].memstart;
758 if (box[i].memend > max)
759 max = box[i].memend;
760 if (box[i].memstart < min)
761 min = box[i].memstart;
762 if (box[i].memend < min)
763 min = box[i].memend;
764 }
765 if (min == max) {
766 min -= 1;
767 max += 1;
768 }
769
770 if (max >= 1024) {
771 scale = 1024.0;
772 scalename = "GB";
773 }
774 if (max / scale >= 100)
775 digits = 0;
776 else if (max / scale >= 10)
777 digits = 1;
778 else
779 digits = 2;
780
781 fprintf(gnudata, "\nset tmarg 1\n");
782 fprintf(gnudata, "set bmarg 1\n");
783 fprintf(gnudata, "set lmarg 10\n");
784 fprintf(gnudata, "set rmarg 10\n");
785 fprintf(gnudata, "set size 1,%s\n", "0.1");
786 fprintf(gnudata, "set origin 0.0,0.87\n");
787
788 fprintf(gnudata, "set xrange [%"PRId64".0:%"PRId64".0]\n", startrange, lastclktick - starttime);
789 fprintf(gnudata, "set ylabel \"memory in %s\"\n", scalename);
790 fprintf(gnudata, "unset xtics\n");
791 fprintf(gnudata, "set border\n");
792 gnuXtics(0);
793 mn = min / 1024.0;
794 mx = max / 1024.0;
795 mm = (mx - mn) / 50.0; /* 2% top & bottom margin */
796 fprintf(gnudata, "set yrange [%f:%f]\n", mn - mm, mx + mm);
797 fprintf(gnudata, "set ytics (\"%.*f\" %f, \"%.*f\" %f) nomirror\n", digits, min / scale, mn, digits, max / scale, mx);
798 fprintf(gnudata, "plot \"%s_%02d.dat\" using 1:2 notitle with dots linecolor rgb \"blue\"\n", basefile, atlaspage);
799 fprintf(gnudata, "unset yrange\n");
800}
801
802static char *
803getHeatColor(double load)
804{
805 if ( load > 0.9 ) return "red";
806 if ( load > 0.75 ) return "orangered";
807 if ( load > 0.5 ) return "orange";
808 if ( load > 0.25 ) return "gold";
809 if ( load > 0.02 ) return "yellow";
810 return "white";
811}
812
813/* produce memory thread trace */
814static void
815showcpu(void)
816{
817 int prev= -1, i, j = 0;
818 double cpuload[MAXTHREADS];
819 char *s;
820
821 for (i = 0; i < MAXTHREADS; i++)
822 cpuload[i] = 0;
823 fprintf(gnudata, "\nset tmarg 1\n");
824 fprintf(gnudata, "set bmarg 0\n");
825 fprintf(gnudata, "set lmarg 10\n");
826 fprintf(gnudata, "set rmarg 10\n");
827 fprintf(gnudata, "set size 1,0.084\n");
828 fprintf(gnudata, "set origin 0.0, 0.8\n");
829 fprintf(gnudata, "set ylabel \"%d cores\"\n",cpus);
830 fprintf(gnudata, "unset xtics\n");
831 fprintf(gnudata, "unset ytics\n");
832 fprintf(gnudata, "set ytics 0, %d\n",cpus <48?(cpus <=8 ?4:8):12);
833 fprintf(gnudata, "set grid ytics\n");
834
835 fprintf(gnudata, "set border\n");
836 gnuXtics(0);
837
838 fprintf(gnudata, "set xrange [%"PRId64".0:%"PRId64".0]\n", startrange, (endrange? endrange:lastclktick - starttime));
839 fprintf(gnudata, "set yrange [0:%d]\n", cpus);
840 for (i = 0; i < topbox; i++)
841 j+=(box[i].state == MDB_PING);
842 if( debug)
843 fprintf(stderr,"Pings for cpu heat:%d\n",j);
844 for (i = 0; i < topbox; i++)
845 if (box[i].state == MDB_PING) {
846 // decode the cpu heat
847 j = 0;
848 s = box[i].stmt +1;
849 while (s) {
850 s = strchr(s + 1, ' ');
851 while (s && isspace((unsigned char) *s))
852 s++;
853 if( s){
854 cpuload[j++] = atof(s);
855 }
856 }
857 // paint the heatmap, the load refers the previous time slot
858 if( prev >= 0)
859 for(j=0; j < cpus; j++)
860 fprintf(gnudata,"set object %d rectangle from %"PRId64".0, %d.0 to %"PRId64".0, %d fillcolor rgb \"%s\" fillstyle solid 1.0 noborder\n",
861 object++, box[prev].clkend, j , box[i].clkstart, (j+1) , getHeatColor(cpuload[j]) );
862 prev = i;
863 }
864 if( cpus)
865 fprintf(gnudata," plot 0 notitle with lines\n unset for[i=1:%d] object i\n",object);
866 fprintf(gnudata, "set border\n");
867 fprintf(gnudata, "unset yrange\n");
868 fprintf(gnudata, "unset ytics\n");
869 fprintf(gnudata, "unset grid\n");
870}
871
872/* produce memory thread trace */
873/* The IO statistics are not provided anymore in LINUX unless you have root permissions */
874static void
875showio(void)
876{
877 int i,b = (beat? beat:1);
878 int64_t max = 0;
879 char *c, ch;
880
881 for (i = 0; i < topbox; i++)
882 if (box[i].clkend && box[i].state >= MDB_PING) {
883 if (box[i].inblock > max)
884 max = box[i].inblock;
885 if (box[i].oublock > max)
886 max = box[i].oublock;
887 //if (box[i].majflt > max)
888 //max = box[i].majflt;
889 //if (box[i].nswap > max)
890 //max = box[i].nswap;
891 }
892 max += b;
893
894
895 fprintf(gnudata, "\nset tmarg 1\n");
896 fprintf(gnudata, "set bmarg 1\n");
897 fprintf(gnudata, "set lmarg 10\n");
898 fprintf(gnudata, "set rmarg 10\n");
899 fprintf(gnudata, "set size 1,%s\n", "0.1");
900 fprintf(gnudata, "set origin 0.0,0.87\n");
901 fprintf(gnudata, "set xrange [%"PRId64".0:%"PRId64".0]\n", startrange, lastclktick - starttime);
902 fprintf(gnudata, "set yrange [0:%"PRId64".0]\n", max / b);
903 fprintf(gnudata, "unset xtics\n");
904 fprintf(gnudata, "unset ytics\n");
905 fprintf(gnudata, "unset ylabel\n");
906 fprintf(gnudata, "set y2tics in (0, %"PRId64".0) nomirror\n", max / b);
907 fprintf(gnudata, "set y2label \"in/oublock\"\n");
908 fprintf(gnudata, "set key font \",8\"\n");
909 fprintf(gnudata, "set key bottom right horizontal\n");
910 if( title){
911 for (c = title; c && *c && i <100; c++, i++)
912 if (*c == '_')// for gnuplot
913 *c = '-';
914 ch= *c; *c =0;
915 fprintf(gnudata, "set title \"%s%s\"\n", title, (*c? "...":""));
916 *c =ch;
917 } else
918 if( dbname)
919 fprintf(gnudata, "set title \"Database %s\"\n", dbname);
920#ifdef GNUPLOT_463_BUG_ON_FEDORA_20
921/* this is the original version, but on Fedora 20 with
922 * gnuplot-4.6.3-6.fc20.x86_64 it produces a red background on most of
923 * the page */
924 fprintf(gnudata, "plot \"%s_%02d.dat\" using 1:($4/%d.0) notitle with dots fs solid linecolor rgb \"gray\" ,\\\n", basefile, atlaspage, b);
925 fprintf(gnudata, "\"%s_%02d.dat\" using ($1+4):($5/%d.0) notitle with dots solid linecolor rgb \"red\"\n", basefile, atlaspage, b);
926 //fprintf(gnudata, "\"%s_%02d.dat\" using ($1+8):($6/%d.0) notitle with dots linecolor rgb \"green\", \\\n", basefile, atlaspage, b);
927 //fprintf(gnudata, "\"%s_%02d.dat\" using ($1+12):($7/%d.0) notitle with dots linecolor rgb \"purple\"\n", basefile, atlaspage, b);
928#else
929/* this is a slightly modified version that produces decent results on
930 * all platforms */
931 fprintf(gnudata, "plot \"%s_%02d.dat\" using 1:($4/%d.0) notitle with dots linecolor rgb \"gray\" ,\\\n", basefile, atlaspage, b);
932 fprintf(gnudata, "\"%s_%02d.dat\" using ($1+4):($5/%d.0) notitle with dots linecolor rgb \"red\"\n", basefile, atlaspage, b);
933 //fprintf(gnudata, "\"%s_%02d.dat\" using ($1+8):($6/%d.0) notitle with dots linecolor rgb \"green\", \\\n", basefile, atlaspage, b);
934 //fprintf(gnudata, "\"%s_%02d.dat\" using ($1+12):($7/%d.0) notitle with dots linecolor rgb \"purple\"\n", basefile, atlaspage, b);
935#endif
936 fprintf(gnudata, "unset y2label\n");
937 fprintf(gnudata, "unset y2tics\n");
938 fprintf(gnudata, "unset y2range\n");
939 fprintf(gnudata, "unset title\n");
940}
941
942
943/* print time (given in microseconds) in human-readable form
944 * showing the highest two relevant units */
945static void
946fprintf_time(FILE *f, int64_t time)
947{
948 if (time >= US_DD)
949 fprintf(f, "%"PRId64 " d %02d h ", time / US_DD,
950 (int) ((time % US_DD) / US_HH));
951 else if (time >= US_HH)
952 fprintf(f, "%d h %02d m ", (int) (time / US_HH),
953 (int) ((time % US_HH) / US_MM));
954 else if (time >= US_MM)
955 fprintf(f, "%d m %02d s ", (int) (time / US_MM),
956 (int) ((time % US_MM) / US_SS));
957 else if (time >= US_SS)
958 fprintf(f, "%d.%03d s ", (int) (time / US_SS),
959 (int) ((time % US_SS) / US_MS));
960 else if (time >= US_MS)
961 fprintf(f, "%d.%03d ms ", (int) (time / US_MS),
962 (int) ((time % US_MS)));
963 else
964 fprintf(f, "%d us ", (int) time);
965}
966
967/* produce a legenda image for the color map */
968#define COLUMNS 3
969
970static void
971showcolormap(char *filename, int all)
972{
973 FILE *f = 0;
974 char buf[BUFSIZ];
975 int i, k = 0,nl;
976 int w = 380; // 600 for 3 columns
977 int h = 590, h1=h;
978 int64_t totfreq = 0, tottime = 0;
979 Color *clrs = colors, *_clrs_ = NULL;
980 char *c;
981 time_t tm;
982 char *date;
983 int64_t longest = lastclktick > starttime? lastclktick - starttime: 0;
984 double perc;
985
986 tm = time(0);
987 date = ctime(&tm);
988 if (strchr(date, '\n'))
989 *strchr(date, '\n') = 0;
990
991
992 // count size of query text
993 for (nl=0, c= currentquery; c && *c; c++)
994 nl += *c == '\n';
995
996 snprintf(buf, BUFSIZ, "%s_%02d.gpl", basefile, atlaspage);
997 if (all) {
998 f = fopen(buf, "w");
999 if (f == NULL) {
1000 fprintf(stderr, "Could not create file '%s'\n", buf);
1001 exit(-1);
1002 }
1003 fprintf(f, "set terminal pdfcairo noenhanced color solid size 8.3, 11.7\n");
1004 fprintf(f, "set output \"%s.pdf\"\n", filename);
1005 fprintf(f, "set size 1,1\n");
1006 fprintf(f, "set xrange [0:1800]\n");
1007 fprintf(f, "set yrange [0:600]\n");
1008 fprintf(f, "unset xtics\n");
1009 fprintf(f, "unset ytics\n");
1010 fprintf(f, "unset colorbox\n");
1011 fprintf(f, "unset border\n");
1012 fprintf(f, "unset title\n");
1013 fprintf(f, "unset ylabel\n");
1014 fprintf(f, "unset xlabel\n");
1015 fprintf(f, "set origin 0.0,0.0\n");
1016 } else {
1017 f = gnudata;
1018 fprintf(f, "\nset tmarg 0\n");
1019 fprintf(f, "set bmarg 0\n");
1020 fprintf(f, "set lmarg 10\n");
1021 fprintf(f, "set rmarg 10\n");
1022 fprintf(f, "set size 1,0.4\n");
1023 fprintf(f, "set origin 0.0,%s\n", "-0.04");
1024 fprintf(f, "set xrange [0:1800]\n");
1025 fprintf(f, "set yrange [0:600]\n");
1026 fprintf(f, "unset xtics\n");
1027 fprintf(f, "unset ytics\n");
1028 fprintf(f, "unset colorbox\n");
1029 fprintf(f, "unset border\n");
1030 fprintf(f, "unset title\n");
1031 fprintf(f, "unset ylabel\n");
1032 }
1033 /* create copy of colormap and sort in ascending order of timeused;
1034 * "*.*" stays first (colors[0]) */
1035 _clrs_ = (Color*) malloc(sizeof(colors));
1036 if (_clrs_) {
1037 memcpy(_clrs_, colors, sizeof(colors));
1038 qsort(_clrs_, NUM_COLORS, sizeof(Color), cmp_clr);
1039 clrs = _clrs_;
1040 }
1041 /* show colormap / legend in descending order of timeused;
1042 * show max. the MAX_LEGEND_SHORT-1 most expensive function calls;
1043 * show all remaining aggregated as "*.*" */
1044 for (i = NUM_COLORS - 1; i >= 0; i--)
1045 if (clrs[i].mod && (clrs[i].freq > 0 || all)) {
1046 if (all || k < MAX_LEGEND_SHORT - 1 || i == 0) {
1047 tottime += clrs[i].timeused;
1048 totfreq += clrs[i].freq;
1049
1050 if (k % COLUMNS == 0 && i)
1051 h -= 35;
1052 fprintf(f, "set object %d rectangle from %.2f, %.2f to %.2f, %.2f fillcolor rgb \"%s\" fillstyle solid 1.0\n",
1053 object++, (double) (k % COLUMNS) * w, (double) h - 40, (double) ((k % COLUMNS) * w + 0.09 * w), (double) h - 15, clrs[i].col);
1054 fprintf(f, "set label %d \"%s.%s \" at %d,%d\n",
1055 object++, (clrs[i].mod?clrs[i].mod:""), clrs[i].fcn, (int) ((k % COLUMNS) * w + 0.1 * w), h - 20);
1056 fprintf(f, "set label %d \"%d call%s: ", object++, clrs[i].freq, clrs[i].freq>1?"s":"");
1057 fprintf_time(f, clrs[i].timeused);
1058 fprintf(f, "\" at %f,%f\n", (double) ((k % COLUMNS) * w + 0.1 * w), (double) h - 35);
1059 k++;
1060 } else {
1061 clrs[0].timeused += clrs[i].timeused;
1062 clrs[0].freq += clrs[i].freq;
1063 }
1064 }
1065 if (_clrs_) {
1066 clrs = colors;
1067 free(_clrs_);
1068 _clrs_ = NULL;
1069 }
1070
1071 h -= 30;
1072 fprintf(f, "set label %d \"MAL instructions executed: %"PRId64, object++, totfreq);
1073 fprintf(f, "\" at 0.0,120\n");
1074
1075 fprintf(f, "set label %d \"Total CPU core time: ", object++);
1076 fprintf_time(f, tottime);
1077 fprintf(f, "\" at 750.0,120.0\n");
1078
1079 perc = (totalclkticks-longest) / ((cpus * longest) / 100.0);
1080 perc = perc <0?0.0:perc;
1081 fprintf(f, "set label %d \"Parallelism %.2f %%", object++, perc>100.0 ? 100.0:perc);
1082 fprintf(f, "\" at 1550.0,120.0\n");
1083 // show complete query text
1084 if( currentquery ){
1085 h = h1-40;
1086 //fprintf(gnudata, "set object %d rectangle from %d.0, 250.0 to %d.0,%d.0\n", object++, 3 * w, 5 *w , h -5);
1087 fprintf(f, "set label %d \"", object++);
1088 k=0;
1089 for (c= currentquery; *c; c++){
1090 if (*c == '"') fprintf(f,"\\"); else
1091 if (*c == '\t') fprintf(f," "); else
1092 if (*c == '\n') { fprintf(f,"\\n"); k=0; continue;} else
1093 if( ++k >60 && (*c == ' ' || *c =='\t')){
1094 fprintf(f,"\\n");
1095 k = 1;
1096 }
1097 fputc(*c,f);
1098 }
1099 fprintf(f, "\" at %d,%d\n", (int) ( 3 * w ), h - 17);
1100 h-= 17;
1101 }
1102 fprintf(f, "set label %d \"%d\" at 1750.0, 100.00\n", object++, atlaspage + 1);
1103 fprintf(f, "set label %d \"%s\" at 750.0, 100.00\n", object++, buf);
1104 fprintf(f, "set label %d \"%s\" at 0.0, 100.00\n", object++, date);
1105 fprintf(f, "plot 0 notitle with lines linecolor rgb \"white\"\n");
1106 if (all) {
1107 fclose(f);
1108 }
1109}
1110
1111static void
1112updatecolormap(int idx)
1113{
1114 char *mod, *fcn, buf[BUFSIZ], *call = buf;
1115 int i, fnd = 0;
1116
1117 if( box[idx].fcn == 0)
1118 return;
1119
1120 snprintf(buf, sizeof(buf), "%s", box[idx].fcn);
1121 mod = call;
1122 fcn = strchr(call, '.');
1123 if (fcn) {
1124 *fcn = 0;
1125 fcn++;
1126 } else{
1127 fcn = "*";
1128 }
1129 if( strncmp(call,"end",3) == 0)
1130 mod ="*";
1131 /* find "mod.fcn" */
1132 for (i = 1; i < NUM_COLORS && colors[i].mod; i++)
1133 if (strcmp(mod, colors[i].mod) == 0 &&
1134 strcmp(fcn, colors[i].fcn) == 0) {
1135 fnd = i;
1136 break;
1137 }
1138 if (fnd == 0 && i < NUM_COLORS) {
1139 /* not found, but still free slot: add new one */
1140 fnd = i;
1141 colors[fnd].mod = strdup(mod);
1142 colors[fnd].fcn = strdup(fcn);
1143 if( debug)
1144 fprintf(stderr,"-- Added function #%d: %s.%s\n", fnd, mod, fcn);
1145 }
1146
1147 colors[fnd].freq++;
1148 colors[fnd].timeused += box[idx].clkend - box[idx].clkstart;
1149 box[idx].color = fnd;
1150}
1151
1152/* gnuplot defaults */
1153static int height = 160;
1154
1155#define LOGOFILE DATA_DIR "/doc/MonetDB/monetdblogo.png"
1156
1157static char *
1158(void)
1159{
1160#ifdef _MSC_VER
1161 /* on Windows, convert \ to / path separators since this path
1162 * is added to gnuplot input */
1163 static char buf[sizeof(LOGOFILE)];
1164 int i;
1165
1166 snprintf(buf, sizeof(buf), "%s", LOGOFILE);
1167 for (i = 0; buf[i]; i++)
1168 if (buf[i] == '\\')
1169 buf[i] = '/';
1170 return buf;
1171#else
1172 return LOGOFILE;
1173#endif
1174}
1175
1176static void
1177gnuplotheader(char *filename)
1178{
1179 fprintf(gnudata, "set terminal pdfcairo noenhanced font 'verdana,10' color solid size 8.3,11.7\n");
1180 fprintf(gnudata, "set output \"%s.pdf\"\n", filename);
1181 fprintf(gnudata, "set size 1,1\n");
1182 fprintf(gnudata, "set tics front\n");
1183 fprintf(gnudata, "set multiplot\n");
1184 // try to inject the MonetDB logo and documentation
1185 fprintf(gnudata,"set tmarg 1\n");
1186 fprintf(gnudata,"set bmarg 1\n");
1187 fprintf(gnudata,"set lmarg 10\n");
1188 fprintf(gnudata,"set rmarg 10\n");
1189 fprintf(gnudata,"set size 0.450,0.11\n");
1190 fprintf(gnudata,"set origin 0.0,0.945\n");
1191 fprintf(gnudata,"set xrange [0.0:1125.0]\n");
1192 fprintf(gnudata,"set yrange [0:581.0]\n");
1193 fprintf(gnudata,"unset border\n");
1194 fprintf(gnudata,"unset xtics\n");
1195 fprintf(gnudata,"unset ytics\n");
1196 fprintf(gnudata,"plot \"%s\" binary filetype=png dx=0.5 dy=0.5 notitle with rgbimage\n", findlogo());
1197 fprintf(gnudata,"unset title\n");
1198
1199}
1200
1201static void
1202createTomogram(void)
1203{
1204 char buf[BUFSIZ];
1205 int rows[MAXTHREADS] = {0};
1206 int top = 0, rowoffset = 0;
1207 int i, j;
1208 int h, prevobject = 1;
1209 int64_t w = lastclktick - starttime;
1210
1211 if( debug)
1212 fprintf(stderr,"create tomogram\n");
1213 if( events == 0){
1214 if( debug)
1215 fprintf(stderr,"No further events found\n");
1216 return;
1217 }
1218 snprintf(buf, BUFSIZ, "%s_%02d.gpl", basefile, atlaspage);
1219 gnudata = fopen(buf, "w");
1220 if (gnudata == 0) {
1221 printf("Could not create file '%s'\n", buf);
1222 exit(-1);
1223 }
1224 if( strrchr(buf,'.'))
1225 *strrchr(buf, '.') = 0;
1226 gnuplotheader(buf);
1227 object=1;
1228 dumpboxes();
1229 showio(); //DISABLED due to access permissions
1230 showmemory();
1231 showcpu();
1232
1233 fprintf(gnudata, "\nset tmarg 1\n");
1234 fprintf(gnudata, "set bmarg 3\n");
1235 fprintf(gnudata, "set lmarg 10\n");
1236 fprintf(gnudata, "set rmarg 10\n");
1237 fprintf(gnudata, "set size 1,0.48\n");
1238 fprintf(gnudata, "set origin 0.0,%s\n", "0.33");
1239 fprintf(gnudata, "set xrange [%"PRId64".0:%"PRId64".0]\n", startrange, lastclktick - starttime);
1240
1241 /* detect all different threads and assign them a row */
1242 for (i = 0; i < topbox; i++){
1243 if (box[i].clkend && box[i].state != MDB_PING) {
1244 for (j = 0; j < top; j++)
1245 if (rows[j] == box[i].thread)
1246 break;
1247 box[i].row = j;
1248 if (j == top){
1249 if( debug)
1250 fprintf(stderr,"Assign thread %d to %d\n", box[i].thread, top);
1251 rows[top++] = box[i].thread;
1252 }
1253 if( box[i].state != MDB_WAIT)
1254 updatecolormap(i);
1255 }
1256 }
1257
1258
1259 h = 10; /* unit height of bars */
1260 height = (cpus+1) * 2 * h;
1261 fprintf(gnudata, "set yrange [0:%d]\n", height);
1262 fprintf(gnudata, "set ylabel \"worker threads\"\n");
1263 fprintf(gnudata, "set key right\n");
1264 fprintf(gnudata, "unset colorbox\n");
1265 fprintf(gnudata, "unset title\n");
1266
1267 w = gnuXtics(1);
1268
1269 /* calculate the effective use of parallelism */
1270 totalticks = 0;
1271 for (i = 0; i < top; i++)
1272 totalticks += lastclk[rows[i]];
1273
1274 /* fill the page from top to bottom */
1275 if( top <= cpus +1){
1276 rowoffset = cpus+1 - top;
1277 if ( top <= cpus/2+1){
1278 h *= 2;
1279 rowoffset = (cpus+2)/2 - top;
1280 }
1281
1282 }
1283
1284 fprintf(gnudata, "set ytics (");
1285 for (i = 0; i < top; i++)
1286 fprintf(gnudata, "\"%d\" %d%c", rows[i], (rowoffset + i) * 2 * h + h / 2, (i < top - 1 ? ',' : ' '));
1287 fprintf(gnudata, ")\n");
1288
1289 /* mark duration of each thread */
1290 for (i = 0; i < top; i++)
1291 fprintf(gnudata, "set object %d rectangle from %d, %d to %"PRId64".0, %d\n",
1292 object++, 0, (rowoffset +i) * 2 * h + h/3, lastclk[rows[i]], (rowoffset +i) * 2 * h + h - h/3);
1293
1294 /* fill the duration of each instruction encountered that fit our range constraint */
1295 for (i = 0; i < topbox; i++)
1296 if (box[i].clkend)
1297 switch (box[i].state) {
1298 default:
1299 if (debug)
1300 dumpbox(i);
1301 // always show a start line
1302 if ( box[i].clkend - box[i].clkstart < w/200.0)
1303 fprintf(gnudata, "set object %d rectangle from %"PRId64".0, %d.0 to %"PRId64".0, %d.0 fillcolor rgb \"%s\" fillstyle solid 1.0\n",
1304 object++, box[i].clkstart, (rowoffset + box[i].row) * 2 * h, box[i].clkstart+2, (rowoffset + box[i].row) * 2 * h + h, colors[box[i].color].col);
1305 else
1306 fprintf(gnudata, "set object %d rectangle from %"PRId64".0, %d.0 to %"PRId64".0, %d.0 fillcolor rgb \"%s\" fillstyle solid 1.0\n",
1307 object++, box[i].clkstart, (rowoffset + box[i].row) * 2 * h, box[i].clkend, (rowoffset + box[i].row) * 2 * h + h, colors[box[i].color].col);
1308 break;
1309 case MDB_PING:
1310 break;
1311 case MDB_WAIT:
1312 fprintf(gnudata, "set object %d rectangle from %"PRId64".0, %d.0 to %.2f,%.2f front fillcolor rgb \"red\" fillstyle solid 1.0\n",
1313 object++, box[i].clkstart, (rowoffset + box[i].row) * 2 * h+h/3, box[i].clkstart+ w /25.0, (rowoffset + box[i].row) *2 *h + h - 0.3 * h);
1314 break;
1315 }
1316
1317
1318
1319 fprintf(gnudata, "plot 0 notitle with lines\n");
1320 fprintf(gnudata, "unset for[i=%d:%d] object i\n", prevobject, object - 1);
1321 prevobject = object - 1;
1322 showcolormap(0, 0);
1323 fprintf(gnudata, "unset multiplot\n");
1324 (void) fclose(gnudata);
1325 gnudata = 0;
1326 atlaspage++;
1327 if (atlas == atlaspage ) {
1328 stopListening(0);
1329 }
1330#ifdef NUMAprofiling
1331 showNumaHeatmap();
1332#endif
1333}
1334
1335/* The intra-thread flow is collected for later presentation */
1336
1337
1338static void
1339updateNumaHeatmap(int thread, char *numa){
1340 char *c;
1341 int t;
1342 for( c= numa; *c && *c == '@';){
1343 c++;
1344 t =atoi(c);
1345 crossings[thread][t]++;
1346 target[thread]++;
1347 source[t]++;
1348 while(*c && *c !='@') c++;
1349 }
1350}
1351
1352
1353/* the main issue to deal with in the analysis is
1354 * that the tomograph start can appear while the
1355 * system is already processing.
1356 * receiving 'done' events without matching 'start'
1357 *
1358 * A secondary issue is to properly count the functions
1359 * being monitored.
1360 */
1361
1362static int ping = -1;
1363
1364static void
1365update(char *line, EventRecord *ev)
1366{
1367 int idx, i;
1368 Box b;
1369 int uid = 0,qid = 0;
1370
1371 if (topbox == maxbox || maxbox < topbox) {
1372 if( box == 0){
1373 box = calloc(MAXBOX, sizeof(Box));
1374 } else
1375 box = realloc(box, (maxbox + MAXBOX) * sizeof(Box));
1376 if( box == NULL){
1377 fprintf(stderr, "Out of space for trace, exceeds max entries %d\n", maxbox);
1378 fprintf(stderr, "Restart with a slower beat might help, e.g. --beat=5000 or --beat=0\n");
1379 exit(-1);
1380 }
1381 maxbox += MAXBOX;
1382 }
1383 /* handle a ping event, keep the current instruction in focus */
1384 if (ev->state >= MDB_PING ) {
1385 if (cpus == 0 && ev->state == MDB_PING) {
1386 char *s;
1387 if( (s= strchr(ev->stmt,'[')) != NULL)
1388 s++;
1389 else s = ev->stmt;
1390 while (s && isspace((unsigned char) *s))
1391 s++;
1392 while (s) {
1393 s = strchr(s + 1, ' ');
1394 while (s && isspace((unsigned char) *s))
1395 s++;
1396 if (s)
1397 cpus++;
1398 }
1399 }
1400 if( startrange && starttime && ev->clkticks-starttime < startrange)
1401 return;
1402 if( endrange && starttime && ev->clkticks-starttime > endrange)
1403 return;
1404 idx = threads[ev->thread];
1405 b = box[idx];
1406 box[idx].state = ev->state;
1407 box[idx].thread = ev->thread;
1408 //lastclk[thread] = clkticks-starttime;
1409 box[idx].clkend = box[idx].clkstart = ev->clkticks-starttime;
1410 box[idx].memend = box[idx].memstart = ev->rss;
1411 box[idx].footstart = box[idx].tmpspace = ev->size;
1412 box[idx].inblock = ev->inblock;
1413 box[idx].oublock = ev->oublock;
1414 box[idx].majflt = ev->majflt;
1415 box[idx].nswap = ev->swaps;
1416 box[idx].csw = ev->csw;
1417 box[idx].stmt = strdup(ev->stmt);
1418
1419 if ( !capturing){
1420 ping = idx;
1421 return;
1422 }
1423 box[idx].fcn = ev->state == MDB_PING? strdup("profiler.ping"):strdup("profiler.wait");
1424 if( box[idx].fcn == NULL){
1425 fprintf(stderr,"Could not allocate blk->fcn\n");
1426 exit(-1);
1427 }
1428 threads[ev->thread] = ++topbox;
1429 idx = threads[ev->thread];
1430 box[idx] = b;
1431 if( tracefd)
1432 fprintf(tracefd,"%s\n",line);
1433 return;
1434 }
1435
1436 if (debug)
1437 fprintf(stderr, "Update %s input %s stmt %s time %" PRId64" %s\n",(ev->state>=0?statenames[ev->state]:"unknown"),(ev->fcn?ev->fcn:"(null)"),(currentfunction?currentfunction:""),ev->clkticks -starttime,(ev->numa?ev->numa:""));
1438
1439 if (starttime == 0) {
1440 if (ev->fcn == 0 ) {
1441 if (debug)
1442 fprintf(stderr, "Skip %s input\n",(ev->state>=0?statenames[ev->state]:"unknown"));
1443 return;
1444 }
1445 if (debug)
1446 fprintf(stderr, "Start capturing updates %s\n",ev->fcn);
1447 }
1448 if (ev->clkticks < 0) {
1449 /* HACK: *TRY TO* compensate for the fact that the MAL
1450 * profiler chops-off day information, and assume that
1451 * clkticks is < starttime because the tomograph run
1452 * crossed a day boundary (midnight);
1453 * we simply add 1 day (24 hours) worth of microseconds.
1454 * NOTE: this surely does NOT work correctly if the
1455 * tomograph run takes 24 hours or more ...
1456 */
1457 ev->clkticks += US_DD;
1458 }
1459
1460 /* monitor top level function brackets, we restrict ourselves to SQL queries */
1461 if (!capturing && ev->state == MDB_START && ev->fcn && strncmp(ev->fcn, "function", 8) == 0) {
1462 if( (i = sscanf(ev->fcn + 9,"user.s%d_%d",&uid,&qid)) != 2){
1463 if( debug)
1464 fprintf(stderr,"Start phase parsing %d, uid %d qid %d\n",i,uid,qid);
1465 return;
1466 }
1467 if (capturing++ == 0)
1468 starttime = ev->clkticks;
1469 if( ping >= 0){
1470 box[ping].clkend = box[ping].clkstart = 0;
1471 ping = -1;
1472 }
1473 if (currentfunction == 0)
1474 currentfunction = strdup(ev->fcn+9);
1475 if (debug)
1476 fprintf(stderr, "Enter function %s capture %d\n", currentfunction, capturing);
1477 if( tracefd)
1478 fprintf(tracefd,"%s\n",line);
1479 return;
1480 }
1481 ev->clkticks -= starttime;
1482
1483 if ( !capturing || ev->thread >= MAXTHREADS)
1484 return;
1485 idx = threads[ev->thread];
1486 lastclk[ev->thread] = endrange? endrange: ev->clkticks;
1487
1488 /* track the input in the trace file */
1489 if( tracefd)
1490 fprintf(tracefd,"%s\n",line);
1491 /* start of instruction box */
1492 if (ev->state == MDB_START ) {
1493 if(debug)
1494 fprintf(stderr, "Start box %s clicks %"PRId64" stmt %s thread %d idx %d box %d\n", (ev->fcn?ev->fcn:""), ev->clkticks,currentfunction, ev->thread,idx,topbox);
1495 box[idx].state = ev->state;
1496 box[idx].thread = ev->thread;
1497 box[idx].clkstart = ev->clkticks? ev->clkticks:1;
1498 box[idx].clkend = ev->clkticks;
1499 box[idx].memstart = ev->rss;
1500 box[idx].memend = ev->rss;
1501 box[idx].numa = ev->numa;
1502 if(ev->numa) updateNumaHeatmap(ev->thread, ev->numa);
1503 box[idx].footstart = ev->size;
1504 box[idx].stmt = ev->beauty;
1505 box[idx].fcn = ev->fcn ? strdup(ev->fcn) : strdup("");
1506 if(ev->fcn && strstr(ev->fcn,"querylog.define") )
1507 fprintf(stderr,"-- page %d :%s\n",atlaspage, currentquery);
1508 return;
1509 }
1510 /* end the instruction box */
1511 if (ev->state == MDB_DONE && ev->fcn && strncmp(ev->fcn, "function", 8) == 0) {
1512 if (currentfunction && strcmp(currentfunction, ev->fcn+9) == 0) {
1513 if( capturing == 0){
1514 free(currentfunction);
1515 currentfunction = 0;
1516 }
1517 capturing--;
1518 if(debug)
1519 fprintf(stderr, "Leave function %s capture %d\n", currentfunction, capturing);
1520 }
1521 if( capturing == 0){
1522 if( tracefd){
1523 fflush(tracefd);
1524 fclose(tracefd);
1525 tracefd = NULL;
1526 }
1527
1528 createTomogram();
1529 resetTomograph();
1530 return;
1531 }
1532 }
1533 if (ev->state == MDB_DONE ){
1534 if( box[idx].clkstart == 0){
1535 // ignore incorrect pairs
1536 if(debug) fprintf(stderr, "INCORRECT START\n");
1537 return;
1538 }
1539 if( debug)
1540 fprintf(stderr, "End box [%d] %s clicks %"PRId64" : %s thread %d idx %d box %d\n", idx, (ev->fcn?ev->fcn:""), ev->clkticks, (currentfunction?currentfunction:""), ev->thread,idx,topbox);
1541 events++;
1542 box[idx].clkend = ev->clkticks;
1543 box[idx].memend = ev->rss;
1544 box[idx].tmpspace = ev->size;
1545 box[idx].ticks = ev->ticks;
1546 box[idx].state = MDB_DONE;
1547 box[idx].inblock = ev->inblock;
1548 box[idx].oublock = ev->oublock;
1549 box[idx].majflt = ev->majflt;
1550 box[idx].nswap = ev->swaps;
1551 box[idx].csw = ev->csw;
1552 /* focus on part of the time frame */
1553 if (endrange) {
1554 if( debug){
1555 fprintf(stderr,"range filter %"PRId64" %" PRId64"\n",startrange,endrange);
1556 fprintf(stderr,"expression %"PRId64" %" PRId64"\n", box[idx].clkstart, box[idx].clkend);
1557 }
1558 if (box[idx].clkend < startrange || box[idx].clkstart >endrange){
1559 fprintf(stderr,"reject %"PRId64":%"PRId64" out %"PRId64":%"PRId64"\n",box[idx].clkstart , box[idx].clkend, startrange, endrange);
1560 return;
1561 }
1562 if (box[idx].clkstart < startrange)
1563 box[idx].clkstart = startrange;
1564 if (box[idx].clkend > endrange)
1565 box[idx].clkend = endrange;
1566 }
1567 threads[ev->thread] = ++topbox;
1568 lastclktick = box[idx].clkend + starttime;
1569 totalclkticks += box[idx].clkend - box[idx].clkstart;
1570 totalexecticks += box[idx].ticks - box[idx].ticks;
1571 }
1572}
1573
1574
1575int
1576main(int argc, char **argv)
1577{
1578 int i;
1579 ssize_t m;
1580 size_t n, len, buflen;
1581 char *host = NULL;
1582 int portnr = 0;
1583 char *uri = NULL;
1584 char *user = NULL;
1585 char *password = NULL;
1586 char buf[BUFSIZ], *buffer, *e, *response;
1587 FILE *inpfd;
1588 int colormap=0;
1589 EventRecord event;
1590 char *s;
1591
1592 static struct option long_options[18] = {
1593 { "dbname", 1, 0, 'd' },
1594 { "user", 1, 0, 'u' },
1595 { "port", 1, 0, 'p' },
1596 { "password", 1, 0, 'P' },
1597 { "host", 1, 0, 'h' },
1598 { "help", 0, 0, '?' },
1599 { "title", 1, 0, 'T' },
1600 { "input", 1, 0, 'i' },
1601 { "range", 1, 0, 'r' },
1602 { "output", 1, 0, 'o' },
1603 { "debug", 0, 0, 'D' },
1604 { "beat", 1, 0, 'b' },
1605 { "atlas", 1, 0, 'A' },
1606 { "map", 1, 0, 'm' },
1607 { 0, 0, 0, 0 }
1608 };
1609
1610 /* parse config file first, command line options override */
1611 parse_dotmonetdb(&user, &password, &dbname, NULL, NULL, NULL, NULL);
1612
1613 if( argc == 1){
1614 usageTomograph();
1615 exit(-1);
1616 }
1617 while (1) {
1618 int option_index = 0;
1619 int c = getopt_long(argc, argv, "d:u:p:P:h:?T:i:r:s:o:c:Db:A:m",
1620 long_options, &option_index);
1621 if (c == -1)
1622 break;
1623 switch (c) {
1624 case 'm':
1625 colormap =1;
1626 break;
1627 case 'A':
1628 atlas = atoi(optarg ? optarg : "1");
1629 break;
1630 case 'b':
1631 beat = atoi(optarg ? optarg : "5000");
1632 break;
1633 case 'D':
1634 debug = 1;
1635 break;
1636 case 'd':
1637 if (dbname)
1638 free(dbname);
1639 prefix = dbname = strdup(optarg);
1640 break;
1641 case 'i':
1642 inputfile = optarg;
1643 prefix = strdup("");
1644 break;
1645 case 'u':
1646 if (user)
1647 free(user);
1648 user = strdup(optarg);
1649 /* force password prompt */
1650 if (password)
1651 free(password);
1652 password = NULL;
1653 break;
1654 case 'P':
1655 if (password)
1656 free(password);
1657 password = strdup(optarg);
1658 break;
1659 case 'p':
1660 if (optarg)
1661 portnr = atoi(optarg);
1662 break;
1663 case 'h':
1664 host = optarg;
1665 break;
1666 case 'T':
1667 title = optarg;
1668 break;
1669 case 'o':
1670 //store the output files in a specific place
1671 prefix = strdup(optarg);
1672#ifdef NATIVE_WIN32
1673 s= strrchr(prefix, (int) '\\');
1674#else
1675 s= strrchr(prefix, (int) '/');
1676#endif
1677 if( s ){
1678 dirpath= prefix;
1679 prefix = strdup(prefix);
1680 *(s+1) = 0;
1681 prefix += s-dirpath;
1682 }
1683 break;
1684 case 'r':
1685 {
1686 int cnt;
1687 if (optarg == 0)
1688 break;
1689 if( *optarg == '=')
1690 optarg++;
1691 cnt = sscanf(optarg,"%"SCNd64"-%"SCNd64, &startrange,&endrange);
1692 if( cnt != 2)
1693 usageTomograph();
1694
1695 if( strstr(optarg,"ms") ){
1696 startrange *= 1000;
1697 endrange *= 1000;
1698 } else if( strchr(optarg,'s')){
1699 startrange *= 1000000;
1700 endrange *= 1000000;
1701 } else
1702 usageTomograph();
1703 if( debug )
1704 fprintf(stderr,"Cut out slice %"PRId64" -%"PRId64"\n",startrange,endrange);
1705 break;
1706 }
1707 case '?':
1708 usageTomograph();
1709 /* a bit of a hack: look at the option that the
1710 current `c' is based on and see if we recognize
1711 it: if -? or --help, exit with 0, else with -1 */
1712 exit(strcmp(argv[optind - 1], "-?") == 0 || strcmp(argv[optind - 1], "--help") == 0 ? 0 : -1);
1713 default:
1714 usageTomograph();
1715 exit(-1);
1716 }
1717 }
1718
1719 if ( dbname == NULL && inputfile == NULL){
1720 fprintf(stderr,"Database name and inputfile missing\n");
1721 usageTomograph();
1722 exit(-1);
1723 }
1724 if (dbname != NULL && strncmp(dbname, "mapi:monetdb://", 15) == 0) {
1725 uri = dbname;
1726 dbname = NULL;
1727 }
1728
1729 /* reprocess an existing profiler trace, possibly producing the trace split */
1730 if( debug )
1731 printf("-- Output directed towards %s%s_*\n", dirpath, prefix);
1732 if (
1733#ifdef NATIVE_WIN32
1734 _mkdir(dirpath) < 0
1735#else
1736 mkdir(dirpath,0755) < 0
1737#endif
1738 && errno != EEXIST) {
1739 fprintf(stderr,"Failed to create dirpath '%s'\n",dirpath);
1740 exit(-1);
1741 }
1742
1743 initcolors();
1744
1745 if (colormap) {
1746 showcolormap(prefix, 1);
1747 printf("Color map file generated\n");
1748 exit(0);
1749 }
1750
1751#ifdef SIGPIPE
1752 signal(SIGPIPE, stopListening);
1753#endif
1754#ifdef SIGHUP
1755 signal(SIGHUP, stopListening);
1756#endif
1757#ifdef SIGQUIT
1758 signal(SIGQUIT, stopListening);
1759#endif
1760 signal(SIGINT, stopListening);
1761 signal(SIGTERM, stopListening);
1762 close(0);
1763
1764 if (inputfile) {
1765 inpfd = fopen(inputfile,"r");
1766 if (inpfd == NULL ){
1767 fprintf(stderr,"Can not access '%s'\n",inputfile);
1768 exit(-1);
1769 }
1770 if( strstr(inputfile,".trace"))
1771 *strstr(inputfile,".trace") = 0;
1772 snprintf(basefile,BUFSIZ,"%s",inputfile);
1773 len = 0;
1774 resetTomograph();
1775 while ((n = fread(buf + len, 1, BUFSIZ - len, inpfd)) > 0) {
1776 buf[len + n] = 0;
1777 response = buf;
1778 while ((e = strchr(response, '\n')) != NULL) {
1779 *e = 0;
1780 i = keyvalueparser(response, &event);
1781 if( i == 1)
1782 update(response, &event);
1783 if (debug )
1784 fprintf(stderr, "PARSE %d:%s\n", i, response);
1785 response = e + 1;
1786 }
1787 /* handle last line in buffer */
1788 if (*response) {
1789 if (debug)
1790 fprintf(stderr,"LASTLINE:%s", response);
1791 len = strlen(response);
1792 snprintf(buf, len + 1, "%s", response);
1793 } else
1794 len = 0;
1795 }
1796 createTomogram();
1797 stopListening(0);
1798 } else {
1799 if (user == NULL)
1800 user = simple_prompt("user", BUFSIZ, 1, prompt_getlogin());
1801 if (password == NULL)
1802 password = simple_prompt("password", BUFSIZ, 0, NULL);
1803
1804 /* our hostname, how remote servers have to contact us */
1805 gethostname(hostname, sizeof(hostname));
1806
1807 /* set up the profiler */
1808 if (uri)
1809 dbh = mapi_mapiuri(uri, user, password, "mal");
1810 else
1811 dbh = mapi_mapi(host, portnr, user, password, "mal", dbname);
1812 if (dbh == NULL || mapi_error(dbh))
1813 die(dbh, hdl);
1814 mapi_reconnect(dbh);
1815 if (mapi_error(dbh))
1816 die(dbh, hdl);
1817 host = strdup(mapi_get_host(dbh));
1818 if(debug)
1819 fprintf(stderr,"-- connection with server %s\n", uri ? uri : host);
1820
1821 snprintf(buf,BUFSIZ-1,"profiler.setheartbeat(%d);",beat);
1822 if( debug)
1823 fprintf(stderr,"-- %s\n",buf);
1824 doQ(buf);
1825
1826 snprintf(buf,BUFSIZ,"profiler.openstream(0);");
1827 if( debug)
1828 fprintf(stderr,"-- %s\n",buf);
1829 doQ(buf);
1830
1831 snprintf(basefile,BUFSIZ,"%s%s",dirpath, prefix);
1832 snprintf(buf,BUFSIZ,"%s_%02d.trace",basefile, atlaspage);
1833 tracefd = fopen(buf,"w");
1834 if( tracefd == NULL)
1835 fprintf(stderr,"Could not create file '%s'\n",buf);
1836
1837 len = 0;
1838 buflen = BUFSIZ;
1839 buffer = malloc(buflen);
1840 if( buffer == NULL){
1841 fprintf(stderr,"Could not create input buffer\n");
1842 exit(-1);
1843 }
1844 resetTomograph();
1845 conn = mapi_get_from(dbh);
1846 while ((m = mnstr_read(conn, buffer + len, 1, buflen - len-1)) >= 0) {
1847 if (m == 0 &&
1848 (m = mnstr_read(conn, buffer + len, 1, buflen - len-1)) <= 0)
1849 break;
1850 buffer[len + m] = 0;
1851 response = buffer;
1852 while ((e = strchr(response, '\n')) != NULL) {
1853 *e = 0;
1854 i = keyvalueparser(response,&event);
1855 if( i == 1)
1856 update(response, &event);
1857 if (debug )
1858 fprintf(stderr, "PARSE %d:%s\n", i, response);
1859 response = e + 1;
1860 }
1861 /* handle the case that the line is too long to
1862 * fit in the buffer */
1863 if( response == buffer){
1864 char *new = realloc(buffer, buflen + BUFSIZ);
1865 if( new == NULL){
1866 fprintf(stderr,"Could not extend input buffer\n");
1867 assert(0);
1868 }
1869 new[buflen] = 0;
1870 buffer = new;
1871 buflen += BUFSIZ;
1872 len += m;
1873 }
1874 /* handle the case the buffer contains more than one
1875 * line, and the last line is not completely read yet.
1876 * Copy the first part of the incomplete line to the
1877 * beginning of the buffer */
1878 else if (*response) {
1879 if (debug)
1880 fprintf(stderr,"LASTLINE:%s", response);
1881 len = strlen(response);
1882 snprintf(buffer, len + 1, "%s", response);
1883 } else /* reset this line of buffer */
1884 len = 0;
1885 }
1886 }
1887
1888 if( !inputfile)
1889 doQ("profiler.stop();");
1890 stop_disconnect:
1891 if( !inputfile) {
1892 mapi_disconnect(dbh);
1893 printf("-- connection with server %s closed\n", uri ? uri : host);
1894 }
1895 return 0;
1896}
1897