blob: f17a69db8f7c8927111d78ab5ed9386aed6f586c [file] [log] [blame]
Dave Barach52642c32016-02-11 19:28:19 -05001/*
2 *------------------------------------------------------------------
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");
73
74 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
192 * display method on short notice
193 */
Dave Baracha8ed6bd2017-04-04 08:00:23 -0400194 g_original_pids = g_malloc0(sizeof(pid_sort_t)*g_npids);
Dave Barach52642c32016-02-11 19:28:19 -0500195 memcpy (g_original_pids, g_pids, sizeof(pid_sort_t)*g_npids);
196}
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) {
217 sprintf(tmpbuf, "Couldn't open %s\n", filename);
218 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))) {
225 sprintf(tmpbuf, "%s was damaged, or isn't an event log.\n", filename);
226 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);
282
283 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
336void add_clib_event(double delta, unsigned short track,
337 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;
358
359 /* 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;
373
374 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) {
420 g_warning("Unmap error, addr 0x%lx size 0x%x\n",
421 (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;
462 else
463 bottom = index - 1;
464 }
465}
466
467/****************************************************************************
468* events_about
469****************************************************************************/
470
471void events_about (char *tmpbuf)
472{
473 sprintf(tmpbuf+strlen(tmpbuf), "%d total events, %.3f ticks per us\n",
474 (int)g_nevents, ticks_per_ns);
475}