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.
21 #include <arpa/inet.h>
25 #include <sys/types.h>
33 boolean g_little_endian;
37 pid_sort_t *g_original_pids;
39 pid_data_t *g_pid_data_list;
44 pid_data_t **s_pidhash;
50 double ticks_per_ns=1000.0;
51 boolean ticks_per_ns_set;
53 /****************************************************************************
55 ****************************************************************************/
67 g_little_endian = TRUE;
69 g_little_endian = FALSE;
71 askstr = getprop("dont_ask_ticks_per_ns_initially");
73 if (askstr && (*askstr == 't' || *askstr == 'T')) {
74 tmp = atol(getprop_default("ticks_per_ns", 0));
77 ticks_per_ns_set = TRUE;
82 /****************************************************************************
84 ****************************************************************************/
86 pid_data_t *find_or_add_pid (ulong pid)
91 bucket = pid % PIDHASH_NBUCKETS;
93 pp = s_pidhash[bucket];
96 pp = g_malloc0(sizeof(pid_data_t));
98 s_pidhash[bucket] = pp;
103 if (pp->pid_value == pid)
108 pp = g_malloc0(sizeof(pid_data_t));
110 pp->next = s_pidhash[bucket];
111 s_pidhash[bucket] = pp;
116 /****************************************************************************
118 ****************************************************************************/
120 int pid_cmp(const void *a1, const void *a2)
122 pid_sort_t *p1 = (pid_sort_t *)a1;
123 pid_sort_t *p2 = (pid_sort_t *)a2;
125 if (p1->pid_value < p2->pid_value)
127 else if (p1->pid_value == p2->pid_value)
133 /****************************************************************************
134 * make_sorted_pid_vector
135 ****************************************************************************/
137 static void make_sorted_pid_vector(void)
140 pid_data_t **p_previous;
144 psp = g_pids = g_malloc0(sizeof(pid_sort_t)*g_npids);
146 for (i = 0; i < PIDHASH_NBUCKETS; i++) {
150 psp->pid_value = pp->pid_value;
156 qsort(&g_pids[0], g_npids, sizeof(pid_sort_t), pid_cmp);
158 /* put the sort order into the pid objects */
162 * This is rather gross.
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.
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.
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.
178 p_previous = &g_pid_data_list;
179 for (i = 0; i < g_npids; i++) {
183 p_previous = &pp->next;
189 * Squirrel away original (sorted) vector, so we can
190 * toggle between "chase" mode, snapshots, and the original
191 * display method on short notice
193 g_original_pids = g_malloc0(sizeof(pid_sort_t)*g_npids);
194 memcpy (g_original_pids, g_pids, sizeof(pid_sort_t)*g_npids);
197 /****************************************************************************
199 ****************************************************************************/
201 void read_events(char *filename)
207 ulonglong start_time=0ULL;
213 ulp = (ulong *)mapfile(filename, &size);
216 snprintf(tmpbuf, sizeof(tmpbuf), "Couldn't open %s\n", filename);
217 infobox("Read Event Log Failure", tmpbuf);
221 g_nevents = ntohl(*ulp);
223 if (size != (g_nevents*sizeof(raw_event_t) + sizeof(g_nevents))) {
224 snprintf(tmpbuf, sizeof(tmpbuf),
225 "%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 integer 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 snprintf(tmpbuf+strlen(tmpbuf), 1024 - strlen(tmpbuf),
474 "%d total events, %.3f ticks per us\n",
475 (int)g_nevents, ticks_per_ns);