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