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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include <sys/fcntl.h>
22 #include <arpa/inet.h>
26 #include <sys/types.h>
34 boolean g_little_endian;
38 pid_sort_t *g_original_pids;
40 pid_data_t *g_pid_data_list;
45 pid_data_t **s_pidhash;
51 double ticks_per_ns=1000.0;
52 boolean ticks_per_ns_set;
54 /****************************************************************************
56 ****************************************************************************/
68 g_little_endian = TRUE;
70 g_little_endian = FALSE;
72 askstr = getprop("dont_ask_ticks_per_ns_initially");
74 if (askstr && (*askstr == 't' || *askstr == 'T')) {
75 tmp = atol(getprop_default("ticks_per_ns", 0));
78 ticks_per_ns_set = TRUE;
83 /****************************************************************************
85 ****************************************************************************/
87 pid_data_t *find_or_add_pid (ulong pid)
92 bucket = pid % PIDHASH_NBUCKETS;
94 pp = s_pidhash[bucket];
97 pp = g_malloc0(sizeof(pid_data_t));
99 s_pidhash[bucket] = pp;
104 if (pp->pid_value == pid)
109 pp = g_malloc0(sizeof(pid_data_t));
111 pp->next = s_pidhash[bucket];
112 s_pidhash[bucket] = pp;
117 /****************************************************************************
119 ****************************************************************************/
121 int pid_cmp(const void *a1, const void *a2)
123 pid_sort_t *p1 = (pid_sort_t *)a1;
124 pid_sort_t *p2 = (pid_sort_t *)a2;
126 if (p1->pid_value < p2->pid_value)
128 else if (p1->pid_value == p2->pid_value)
134 /****************************************************************************
135 * make_sorted_pid_vector
136 ****************************************************************************/
138 static void make_sorted_pid_vector(void)
141 pid_data_t **p_previous;
145 psp = g_pids = g_malloc(sizeof(pid_sort_t)*g_npids);
147 for (i = 0; i < PIDHASH_NBUCKETS; i++) {
151 psp->pid_value = pp->pid_value;
157 qsort(&g_pids[0], g_npids, sizeof(pid_sort_t), pid_cmp);
159 /* put the sort order into the pid objects */
163 * This is rather gross.
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.
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.
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.
179 p_previous = &g_pid_data_list;
180 for (i = 0; i < g_npids; i++) {
184 p_previous = &pp->next;
190 * Squirrel away original (sorted) vector, so we can
191 * toggle between "chase" mode, snapshots, and the original
192 * display method on short notice
194 g_original_pids = g_malloc(sizeof(pid_sort_t)*g_npids);
195 memcpy (g_original_pids, g_pids, sizeof(pid_sort_t)*g_npids);
198 /****************************************************************************
200 ****************************************************************************/
202 void read_events(char *filename)
208 ulonglong start_time=0ULL;
214 ulp = (ulong *)mapfile(filename, &size);
217 sprintf(tmpbuf, "Couldn't open %s\n", filename);
218 infobox("Read Event Log Failure", tmpbuf);
222 g_nevents = ntohl(*ulp);
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);
228 unmapfile((char *)ulp, size);
232 rep = (raw_event_t *)(ulp+1);
237 g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t));
240 while (g_npids > 0) {
241 g_free((g_pids + g_npids-1)->pid);
246 g_free(g_original_pids);
251 s_pidhash = (pid_data_t **)g_malloc0(
252 PIDHASH_NBUCKETS*sizeof(pid_data_t *));
254 /* $$$ add a SEGV handler... */
255 for (i = 0; i < g_nevents; i++) {
258 start_time = ((ulonglong)ntohl(rep->time[0]));
260 low_time = ntohl(rep->time[1]);
261 low_time &= 0xFFFFFFFF;
262 start_time |= low_time;
265 ep->time = ((ulonglong)ntohl(rep->time[0]));
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;
273 ep->code = ntohl(rep->code);
274 ep->pid = find_or_add_pid(ntohl(rep->pid));
275 ep->datum = ntohl(rep->datum);
281 unmapfile((char *)ulp, size);
283 make_sorted_pid_vector();
287 /* Give the view-1 world a chance to reset a few things... */
288 view1_read_events_callback();
291 static event_t *add_ep;
293 /****************************************************************************
295 ****************************************************************************/
296 void cpel_event_init (ulong nevents)
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);
308 g_free(g_original_pids);
312 s_pidhash = (pid_data_t **)g_malloc0(
313 PIDHASH_NBUCKETS*sizeof(pid_data_t *));
316 /****************************************************************************
318 ****************************************************************************/
320 void add_cpel_event(ulonglong delta, ulong track, ulong event, ulong datum)
326 ep->pid = find_or_add_pid(track);
332 /****************************************************************************
334 ****************************************************************************/
336 void add_clib_event(double delta, unsigned short track,
337 unsigned short event, unsigned int index)
342 ep->time = (ulonglong) (delta * 1e9); /* time in intger nanoseconds */
343 ep->pid = find_or_add_pid(track);
346 ep->flags = EVENT_FLAG_CLIB;
349 /****************************************************************************
350 * cpel_event_finalize
351 ****************************************************************************/
353 void cpel_event_finalize(void)
355 make_sorted_pid_vector();
359 /* Give the view-1 world a chance to reset a few things... */
360 view1_read_events_callback();
363 /****************************************************************************
365 ****************************************************************************/
367 char *mapfile (char *file, ulong *sizep)
374 maphfile = open (file, O_RDONLY);
379 if (fstat (maphfile, &statb) < 0) {
383 /* Don't try to mmap directories, FIFOs, semaphores, etc. */
384 if (! (statb.st_mode & S_IFREG)) {
388 mapfsize = statb.st_size;
395 rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0);
398 g_error ("%s mapping problem, I quit...\n", file);
403 if (madvise (rv, mapfsize, MADV_SEQUENTIAL) < 0) {
413 /****************************************************************************
415 ****************************************************************************/
417 boolean unmapfile (char *addr, ulong size)
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);
427 /****************************************************************************
429 * Binary search for first event whose time is >= t
430 ****************************************************************************/
432 int find_event_index (ulonglong t)
434 int index, bottom, top;
437 bottom = g_nevents-1;
441 index = (bottom + top) / 2;
443 ep = (g_events + index);
449 while (index > 0 && ep->time > t) {
453 while (index < g_nevents && ep->time < t) {
467 /****************************************************************************
469 ****************************************************************************/
471 void events_about (char *tmpbuf)
473 sprintf(tmpbuf+strlen(tmpbuf), "%d total events, %.3f ticks per us\n",
474 (int)g_nevents, ticks_per_ns);