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_malloc0(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_malloc0(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 snprintf(tmpbuf, sizeof(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 snprintf(tmpbuf, sizeof(tmpbuf),
226 "%s was damaged, or isn't an event log.\n", filename);
227 infobox("Bad Input File", tmpbuf);
229 unmapfile((char *)ulp, size);
233 rep = (raw_event_t *)(ulp+1);
238 g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t));
241 while (g_npids > 0) {
242 g_free((g_pids + g_npids-1)->pid);
247 g_free(g_original_pids);
252 s_pidhash = (pid_data_t **)g_malloc0(
253 PIDHASH_NBUCKETS*sizeof(pid_data_t *));
255 /* $$$ add a SEGV handler... */
256 for (i = 0; i < g_nevents; i++) {
259 start_time = ((ulonglong)ntohl(rep->time[0]));
261 low_time = ntohl(rep->time[1]);
262 low_time &= 0xFFFFFFFF;
263 start_time |= low_time;
266 ep->time = ((ulonglong)ntohl(rep->time[0]));
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;
274 ep->code = ntohl(rep->code);
275 ep->pid = find_or_add_pid(ntohl(rep->pid));
276 ep->datum = ntohl(rep->datum);
282 unmapfile((char *)ulp, size);
284 make_sorted_pid_vector();
288 /* Give the view-1 world a chance to reset a few things... */
289 view1_read_events_callback();
292 static event_t *add_ep;
294 /****************************************************************************
296 ****************************************************************************/
297 void cpel_event_init (ulong nevents)
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);
309 g_free(g_original_pids);
313 s_pidhash = (pid_data_t **)g_malloc0(
314 PIDHASH_NBUCKETS*sizeof(pid_data_t *));
317 /****************************************************************************
319 ****************************************************************************/
321 void add_cpel_event(ulonglong delta, ulong track, ulong event, ulong datum)
327 ep->pid = find_or_add_pid(track);
333 /****************************************************************************
335 ****************************************************************************/
337 void add_clib_event(double delta, unsigned short track,
338 unsigned short event, unsigned int index)
343 ep->time = (ulonglong) (delta * 1e9); /* time in integer nanoseconds */
344 ep->pid = find_or_add_pid(track);
347 ep->flags = EVENT_FLAG_CLIB;
350 /****************************************************************************
351 * cpel_event_finalize
352 ****************************************************************************/
354 void cpel_event_finalize(void)
356 make_sorted_pid_vector();
360 /* Give the view-1 world a chance to reset a few things... */
361 view1_read_events_callback();
364 /****************************************************************************
366 ****************************************************************************/
368 char *mapfile (char *file, ulong *sizep)
375 maphfile = open (file, O_RDONLY);
380 if (fstat (maphfile, &statb) < 0) {
384 /* Don't try to mmap directories, FIFOs, semaphores, etc. */
385 if (! (statb.st_mode & S_IFREG)) {
389 mapfsize = statb.st_size;
396 rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0);
399 g_error ("%s mapping problem, I quit...\n", file);
404 if (madvise (rv, mapfsize, MADV_SEQUENTIAL) < 0) {
414 /****************************************************************************
416 ****************************************************************************/
418 boolean unmapfile (char *addr, ulong size)
420 if (munmap (addr, size) < 0) {
421 g_warning("Unmap error, addr 0x%lx size 0x%x\n",
422 (unsigned long) addr, (unsigned int)size);
428 /****************************************************************************
430 * Binary search for first event whose time is >= t
431 ****************************************************************************/
433 int find_event_index (ulonglong t)
435 int index, bottom, top;
438 bottom = g_nevents-1;
442 index = (bottom + top) / 2;
444 ep = (g_events + index);
450 while (index > 0 && ep->time > t) {
454 while (index < g_nevents && ep->time < t) {
468 /****************************************************************************
470 ****************************************************************************/
472 void events_about (char *tmpbuf)
474 snprintf(tmpbuf+strlen(tmpbuf), 1024 - strlen(tmpbuf),
475 "%d total events, %.3f ticks per us\n",
476 (int)g_nevents, ticks_per_ns);