blob: ef85c208b3c960e728d5427ded0165583d61564d [file] [log] [blame]
Dave Barach3e07a4a2020-04-04 10:05:48 -04001/*
Dave Barach52642c32016-02-11 19:28:19 -05002 *------------------------------------------------------------------
3 * Copyright (c) 2005-2016 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18#include <unistd.h>
19#include <sys/stat.h>
Dave Barach52642c32016-02-11 19:28:19 -050020#include <sys/mman.h>
21#include <arpa/inet.h>
22#include <stdio.h>
23#include <gtk/gtk.h>
24#include "g2.h"
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <fcntl.h>
28#include <string.h>
29
30/*
31 * globals
32 */
33boolean g_little_endian;
34event_t *g_events;
35ulong g_nevents;
36pid_sort_t *g_pids;
37pid_sort_t *g_original_pids;
38int g_npids;
39pid_data_t *g_pid_data_list;
40
41/*
42 * locals
43 */
44pid_data_t **s_pidhash;
45
46/*
47 * config parameters
48 */
49
50double ticks_per_ns=1000.0;
51boolean ticks_per_ns_set;
52
53/****************************************************************************
54* event_init
55****************************************************************************/
56
57void event_init(void)
58{
59 ulong endian;
60 char *ep;
61 char *askstr;
62 int tmp;
63
64 ep = (char *)&endian;
65 endian = 0x12345678;
66 if (*ep != 0x12)
67 g_little_endian = TRUE;
68 else
69 g_little_endian = FALSE;
70
71 askstr = getprop("dont_ask_ticks_per_ns_initially");
Dave Barach3e07a4a2020-04-04 10:05:48 -040072
Dave Barach52642c32016-02-11 19:28:19 -050073 if (askstr && (*askstr == 't' || *askstr == 'T')) {
74 tmp = atol(getprop_default("ticks_per_ns", 0));
75 if (tmp > 0) {
76 ticks_per_ns = tmp;
77 ticks_per_ns_set = TRUE;
78 }
79 }
80}
81
82/****************************************************************************
83* find_or_add_pid
84****************************************************************************/
85
86pid_data_t *find_or_add_pid (ulong pid)
87{
88 pid_data_t *pp;
89 ulong bucket;
90
91 bucket = pid % PIDHASH_NBUCKETS;
92
93 pp = s_pidhash[bucket];
94
95 if (pp == 0) {
96 pp = g_malloc0(sizeof(pid_data_t));
97 pp->pid_value = pid;
98 s_pidhash[bucket] = pp;
99 g_npids++;
100 return(pp);
101 }
102 while (pp) {
103 if (pp->pid_value == pid)
104 return(pp);
105 pp = pp->next;
106 }
107
108 pp = g_malloc0(sizeof(pid_data_t));
109 pp->pid_value = pid;
110 pp->next = s_pidhash[bucket];
111 s_pidhash[bucket] = pp;
112 g_npids++;
113 return(pp);
114}
115
116/****************************************************************************
117* pid_cmp
118****************************************************************************/
119
120int pid_cmp(const void *a1, const void *a2)
121{
122 pid_sort_t *p1 = (pid_sort_t *)a1;
123 pid_sort_t *p2 = (pid_sort_t *)a2;
124
125 if (p1->pid_value < p2->pid_value)
126 return(-1);
127 else if (p1->pid_value == p2->pid_value)
128 return(0);
129 else
130 return(1);
131}
132
133/****************************************************************************
134* make_sorted_pid_vector
135****************************************************************************/
136
137static void make_sorted_pid_vector(void)
138{
139 pid_data_t *pp;
140 pid_data_t **p_previous;
141 pid_sort_t *psp;
142 int i;
143
Dave Baracha8ed6bd2017-04-04 08:00:23 -0400144 psp = g_pids = g_malloc0(sizeof(pid_sort_t)*g_npids);
Dave Barach52642c32016-02-11 19:28:19 -0500145
146 for (i = 0; i < PIDHASH_NBUCKETS; i++) {
147 pp = s_pidhash[i];
148 while(pp) {
149 psp->pid = pp;
150 psp->pid_value = pp->pid_value;
151 psp++;
152 pp = pp->next;
153 }
154 }
155
156 qsort(&g_pids[0], g_npids, sizeof(pid_sort_t), pid_cmp);
157
158 /* put the sort order into the pid objects */
159 psp = g_pids;
160
161 /*
162 * This is rather gross.
163 *
164 * We happen to know that whenever this function is called, the hash table
165 * structure itself is immediately torn down. So the "next" pointers in the
166 * pid_data_t elements are about to become useless.
167 *
168 * So we re-use them, to link all the pid_data_t elements together into a
169 * single unified linked list, with g_pid_data_list pointing to the head.
170 * This means we can walk all the pid_data_t objects if we really want to.
171 * Reading snapshots from disk is one example.
172 *
173 * Alternatively we could just leave the hash table in place; this is
174 * far nicer, but as it happens, trading O(n) lookups for O(1) lookups
175 * isn't actually a problem for the restricted post-tear-down usage. So for
176 * now we take the memory savings and swap our hash table for a list.
177 */
178 p_previous = &g_pid_data_list;
179 for (i = 0; i < g_npids; i++) {
180 pp = psp->pid;
181 pp->pid_index = i;
182 *p_previous = pp;
183 p_previous = &pp->next;
184 psp++;
185 }
186 *p_previous = NULL;
187
188 /*
189 * Squirrel away original (sorted) vector, so we can
190 * toggle between "chase" mode, snapshots, and the original
Dave Barach3e07a4a2020-04-04 10:05:48 -0400191 * display method on short notice
Dave Barach52642c32016-02-11 19:28:19 -0500192 */
Dave Baracha8ed6bd2017-04-04 08:00:23 -0400193 g_original_pids = g_malloc0(sizeof(pid_sort_t)*g_npids);
Dave Barach3e07a4a2020-04-04 10:05:48 -0400194 memcpy (g_original_pids, g_pids, sizeof(pid_sort_t)*g_npids);
Dave Barach52642c32016-02-11 19:28:19 -0500195}
196
197/****************************************************************************
198* read_events
199****************************************************************************/
200
201void read_events(char *filename)
202{
203 ulong *ulp;
204 ulong size;
205 event_t *ep;
206 raw_event_t *rep;
207 ulonglong start_time=0ULL;
208 ulonglong low_time;
209 boolean once=TRUE;
210 int i;
211 char tmpbuf [128];
212
213 ulp = (ulong *)mapfile(filename, &size);
214
215 if (ulp == NULL) {
Dave Barach3e07a4a2020-04-04 10:05:48 -0400216 snprintf(tmpbuf, sizeof(tmpbuf), "Couldn't open %s\n", filename);
Dave Barach52642c32016-02-11 19:28:19 -0500217 infobox("Read Event Log Failure", tmpbuf);
218 return;
219 }
220
221 g_nevents = ntohl(*ulp);
222
223 if (size != (g_nevents*sizeof(raw_event_t) + sizeof(g_nevents))) {
Dave Barach3e07a4a2020-04-04 10:05:48 -0400224 snprintf(tmpbuf, sizeof(tmpbuf),
225 "%s was damaged, or isn't an event log.\n", filename);
Dave Barach52642c32016-02-11 19:28:19 -0500226 infobox("Bad Input File", tmpbuf);
227 g_nevents = 0;
228 unmapfile((char *)ulp, size);
229 return;
230 }
231
232 rep = (raw_event_t *)(ulp+1);
233
234 if (g_events)
235 g_free(g_events);
236
237 g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t));
238 ep = g_events;
239
240 while (g_npids > 0) {
241 g_free((g_pids + g_npids-1)->pid);
242 g_npids--;
243 }
244 if (g_pids) {
245 g_free(g_pids);
246 g_free(g_original_pids);
247 g_pids = 0;
248 g_original_pids = 0;
249 }
250
251 s_pidhash = (pid_data_t **)g_malloc0(
252 PIDHASH_NBUCKETS*sizeof(pid_data_t *));
253
254 /* $$$ add a SEGV handler... */
255 for (i = 0; i < g_nevents; i++) {
256 if (once) {
257 once = FALSE;
258 start_time = ((ulonglong)ntohl(rep->time[0]));
259 start_time <<= 32;
260 low_time = ntohl(rep->time[1]);
261 low_time &= 0xFFFFFFFF;
262 start_time |= low_time;
263 ep->time = 0LL;
264 } else {
265 ep->time = ((ulonglong)ntohl(rep->time[0]));
266 ep->time <<= 32;
267 low_time = ntohl(rep->time[1]);
268 low_time &= 0xFFFFFFFF;
269 ep->time |= low_time;
270 ep->time -= start_time;
271 ep->time /= ticks_per_ns;
272 }
273 ep->code = ntohl(rep->code);
274 ep->pid = find_or_add_pid(ntohl(rep->pid));
275 ep->datum = ntohl(rep->datum);
276 ep->flags = 0;
277 ep++;
278 rep++;
279 }
280
281 unmapfile((char *)ulp, size);
Dave Barach3e07a4a2020-04-04 10:05:48 -0400282
Dave Barach52642c32016-02-11 19:28:19 -0500283 make_sorted_pid_vector();
284 g_free(s_pidhash);
285 s_pidhash = 0;
286
287 /* Give the view-1 world a chance to reset a few things... */
288 view1_read_events_callback();
289}
290
291static event_t *add_ep;
292
293/****************************************************************************
294* cpel_event_init
295****************************************************************************/
296void cpel_event_init (ulong nevents)
297{
298 g_nevents = nevents;
299 if (g_events)
300 g_free(g_events);
301 add_ep = g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t));
302 while (g_npids > 0) {
303 g_free((g_pids + g_npids-1)->pid);
304 g_npids--;
305 }
306 if (g_pids) {
307 g_free(g_pids);
308 g_free(g_original_pids);
309 g_pids = 0;
310 g_original_pids = 0;
311 }
312 s_pidhash = (pid_data_t **)g_malloc0(
313 PIDHASH_NBUCKETS*sizeof(pid_data_t *));
314}
315
316/****************************************************************************
317* add_cpel_event
318****************************************************************************/
319
320void add_cpel_event(ulonglong delta, ulong track, ulong event, ulong datum)
321{
322 event_t *ep;
323
324 ep = add_ep++;
325 ep->time = delta;
326 ep->pid = find_or_add_pid(track);
327 ep->code = event;
328 ep->datum = datum;
329 ep->flags = 0;
330}
331
332/****************************************************************************
333* add_clib_event
334****************************************************************************/
335
Dave Barach3e07a4a2020-04-04 10:05:48 -0400336void add_clib_event(double delta, unsigned short track,
Dave Barach52642c32016-02-11 19:28:19 -0500337 unsigned short event, unsigned int index)
338{
339 event_t *ep;
340
341 ep = add_ep++;
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700342 ep->time = (ulonglong) (delta * 1e9); /* time in integer nanoseconds */
Dave Barach52642c32016-02-11 19:28:19 -0500343 ep->pid = find_or_add_pid(track);
344 ep->code = event;
345 ep->datum = index;
346 ep->flags = EVENT_FLAG_CLIB;
347}
348
349/****************************************************************************
350* cpel_event_finalize
351****************************************************************************/
352
353void cpel_event_finalize(void)
354{
355 make_sorted_pid_vector();
356 g_free(s_pidhash);
357 s_pidhash = 0;
Dave Barach3e07a4a2020-04-04 10:05:48 -0400358
Dave Barach52642c32016-02-11 19:28:19 -0500359 /* Give the view-1 world a chance to reset a few things... */
360 view1_read_events_callback();
361}
362
363/****************************************************************************
364* mapfile
365****************************************************************************/
366
367char *mapfile (char *file, ulong *sizep)
368{
369 struct stat statb;
370 char *rv;
371 int maphfile;
372 size_t mapfsize;
Dave Barach3e07a4a2020-04-04 10:05:48 -0400373
Dave Barach52642c32016-02-11 19:28:19 -0500374 maphfile = open (file, O_RDONLY);
375
376 if (maphfile < 0)
377 return (NULL);
378
379 if (fstat (maphfile, &statb) < 0) {
380 return (NULL);
381 }
382
383 /* Don't try to mmap directories, FIFOs, semaphores, etc. */
384 if (! (statb.st_mode & S_IFREG)) {
385 return (NULL);
386 }
387
388 mapfsize = statb.st_size;
389
390 if (mapfsize < 3) {
391 close (maphfile);
392 return (NULL);
393 }
394
395 rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0);
396
397 if (rv == 0) {
398 g_error ("%s mapping problem, I quit...\n", file);
399 }
400
401 close (maphfile);
402
403 if (madvise (rv, mapfsize, MADV_SEQUENTIAL) < 0) {
404 return (rv);
405 }
406
407 if (sizep) {
408 *sizep = mapfsize;
409 }
410 return (rv);
411}
412
413/****************************************************************************
414* unmapfile
415****************************************************************************/
416
417boolean unmapfile (char *addr, ulong size)
418{
419 if (munmap (addr, size) < 0) {
Dave Barach3e07a4a2020-04-04 10:05:48 -0400420 g_warning("Unmap error, addr 0x%lx size 0x%x\n",
Dave Barach52642c32016-02-11 19:28:19 -0500421 (unsigned long) addr, (unsigned int)size);
422 return(FALSE);
423 }
424 return(TRUE);
425}
426
427/****************************************************************************
428* find_event_index
429* Binary search for first event whose time is >= t
430****************************************************************************/
431
432int find_event_index (ulonglong t)
433{
434 int index, bottom, top;
435 event_t *ep;
436
437 bottom = g_nevents-1;
438 top = 0;
439
440 while (1) {
441 index = (bottom + top) / 2;
442
443 ep = (g_events + index);
444
445 if (ep->time == t)
446 return(index);
447
448 if (top >= bottom) {
449 while (index > 0 && ep->time > t) {
450 ep--;
451 index--;
452 }
453 while (index < g_nevents && ep->time < t) {
454 ep++;
455 index++;
456 }
457 return(index);
458 }
459
460 if (ep->time < t)
461 top = index + 1;
Dave Barach3e07a4a2020-04-04 10:05:48 -0400462 else
Dave Barach52642c32016-02-11 19:28:19 -0500463 bottom = index - 1;
464 }
465}
466
467/****************************************************************************
468* events_about
469****************************************************************************/
470
471void events_about (char *tmpbuf)
472{
Dave Barach3e07a4a2020-04-04 10:05:48 -0400473 snprintf(tmpbuf+strlen(tmpbuf), 1024 - strlen(tmpbuf),
474 "%d total events, %.3f ticks per us\n",
475 (int)g_nevents, ticks_per_ns);
Dave Barach52642c32016-02-11 19:28:19 -0500476}