http: fix client send another request
[vpp.git] / src / tools / g2 / events.c
1 /*
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/mman.h>
21 #include <arpa/inet.h>
22 #include <stdio.h>
23 #include <gtk/gtk.h>
24 #include "g2.h"
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <string.h>
29
30 /*
31  * globals
32  */
33 boolean g_little_endian;
34 event_t *g_events;
35 ulong g_nevents;
36 pid_sort_t *g_pids;
37 pid_sort_t *g_original_pids;
38 int g_npids;
39 pid_data_t *g_pid_data_list;
40
41 /*
42  * locals
43  */
44 pid_data_t **s_pidhash;
45
46 /*
47  * config parameters
48  */
49
50 double ticks_per_ns=1000.0;
51 boolean ticks_per_ns_set;
52
53 /****************************************************************************
54 * event_init
55 ****************************************************************************/
56
57 void event_init(void)
58 {
59     ulong endian;
60     char *ep;
61     char *askstr;
62     int tmp;
63
64     ep = (char *)&endian;
65     endian = 0x12345678;
66     if (*ep != 0x12)
67         g_little_endian = TRUE;
68     else
69         g_little_endian = FALSE;
70
71     askstr = getprop("dont_ask_ticks_per_ns_initially");
72
73     if (askstr && (*askstr == 't' || *askstr == 'T')) {
74         tmp = atol(getprop_default("ticks_per_ns", 0));
75         if (tmp > 0) {
76             ticks_per_ns = tmp;
77             ticks_per_ns_set = TRUE;
78         }
79     }
80 }
81
82 /****************************************************************************
83 * find_or_add_pid
84 ****************************************************************************/
85
86 pid_data_t *find_or_add_pid (ulong pid)
87 {
88     pid_data_t *pp;
89     ulong bucket;
90
91     bucket = pid % PIDHASH_NBUCKETS;
92
93     pp = s_pidhash[bucket];
94
95     if (pp == 0) {
96         pp = g_malloc0(sizeof(pid_data_t));
97         pp->pid_value = pid;
98         s_pidhash[bucket] = pp;
99         g_npids++;
100         return(pp);
101     }
102     while (pp) {
103         if (pp->pid_value == pid)
104             return(pp);
105         pp = pp->next;
106     }
107
108     pp = g_malloc0(sizeof(pid_data_t));
109     pp->pid_value = pid;
110     pp->next = s_pidhash[bucket];
111     s_pidhash[bucket] = pp;
112     g_npids++;
113     return(pp);
114 }
115
116 /****************************************************************************
117 * pid_cmp
118 ****************************************************************************/
119
120 int pid_cmp(const void *a1, const void *a2)
121 {
122     pid_sort_t *p1 = (pid_sort_t *)a1;
123     pid_sort_t *p2 = (pid_sort_t *)a2;
124
125     if (p1->pid_value < p2->pid_value)
126         return(-1);
127     else if (p1->pid_value == p2->pid_value)
128         return(0);
129     else
130         return(1);
131 }
132
133 /****************************************************************************
134 * make_sorted_pid_vector
135 ****************************************************************************/
136
137 static void make_sorted_pid_vector(void)
138 {
139     pid_data_t *pp;
140     pid_data_t **p_previous;
141     pid_sort_t *psp;
142     int i;
143
144     psp = g_pids = g_malloc0(sizeof(pid_sort_t)*g_npids);
145
146     for (i = 0; i < PIDHASH_NBUCKETS; i++) {
147         pp = s_pidhash[i];
148         while(pp) {
149             psp->pid = pp;
150             psp->pid_value = pp->pid_value;
151             psp++;
152             pp = pp->next;
153         }
154     }
155
156     qsort(&g_pids[0], g_npids, sizeof(pid_sort_t), pid_cmp);
157
158     /* put the sort order into the pid objects */
159     psp = g_pids;
160
161     /*
162      * This is rather gross.
163      *
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.
167      *
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.
172      *
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.
177      */
178     p_previous = &g_pid_data_list;
179     for (i = 0; i < g_npids; i++) {
180         pp = psp->pid;
181         pp->pid_index = i;
182         *p_previous = pp;
183         p_previous = &pp->next;
184         psp++;
185     }
186     *p_previous = NULL;
187
188     /*
189      * Squirrel away original (sorted) vector, so we can
190      * toggle between "chase" mode, snapshots, and the original
191      * display method on short notice
192      */
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);
195 }
196
197 /****************************************************************************
198 * read_events
199 ****************************************************************************/
200
201 void read_events(char *filename)
202 {
203     ulong *ulp;
204     ulong size;
205     event_t *ep;
206     raw_event_t *rep;
207     ulonglong start_time=0ULL;
208     ulonglong low_time;
209     boolean once=TRUE;
210     int i;
211     char tmpbuf [128];
212
213     ulp = (ulong *)mapfile(filename, &size);
214
215     if (ulp == NULL) {
216         snprintf(tmpbuf, sizeof(tmpbuf), "Couldn't open %s\n", filename);
217         infobox("Read Event Log Failure", tmpbuf);
218         return;
219     }
220
221     g_nevents = ntohl(*ulp);
222
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);
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
291 static event_t *add_ep;
292
293 /****************************************************************************
294 * cpel_event_init
295 ****************************************************************************/
296 void 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
320 void 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
336 void 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++;
342     ep->time = (ulonglong) (delta * 1e9); /* time in integer nanoseconds */
343     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
353 void 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
367 char *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
417 boolean 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
432 int 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
471 void events_about (char *tmpbuf)
472 {
473     snprintf(tmpbuf+strlen(tmpbuf), 1024 - strlen(tmpbuf),
474              "%d total events, %.3f ticks per us\n",
475              (int)g_nevents, ticks_per_ns);
476 }