misc: use right include for fctnl.h and poll.h
[vpp.git] / src / tools / perftool / cpel_util.c
1 /* 
2  *------------------------------------------------------------------
3  * Copyright (c) 2006-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 #include <stdio.h>
17 #include <stdlib.h>
18 #include <netinet/in.h>
19 #include <string.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <sys/mman.h>
24 #include <unistd.h>
25 #include <ctype.h>
26 #include <vppinfra/clib.h>
27 #include <vppinfra/vec.h>
28 #include <vppinfra/hash.h>
29 #include <vppinfra/bitmap.h>
30 #include <vppinfra/byte_order.h>
31 #include <pwd.h>
32 #include <stdarg.h>
33 #include <time.h>
34 #include "cpel.h"
35 #include "cpel_util.h"
36
37 evt_t *the_events;
38
39 track_t *the_tracks;
40 u32 *track_alpha_map;
41
42 event_definition_t *the_event_definitions;
43 i64 min_timestamp;
44
45 /* Hash tables, used to find previous instances of the same items */
46 uword *the_track_hash;
47 uword *the_msg_event_hash;
48 uword *the_strtab_hash;
49 uword *the_pidtid_hash;
50 uword *the_pid_to_name_hash;
51 u8 *the_strtab;
52
53 uword *the_event_id_bitmap;
54
55 /*
56  * find_or_add_strtab
57  * Finds or adds a string to the string table
58  */
59 u32 find_or_add_strtab(void *s_arg)
60 {
61     uword *p;
62     int len;
63     u8 *this_string;
64     u8 *scopy=0;
65     char *s = s_arg;
66
67     p = hash_get_mem(the_strtab_hash, s);
68     if (p) {
69         return (p[0]);
70     }
71
72     /*
73      * Here's a CLIB bear-trap. We can't add the string-table 
74      * strings to the to the hash table (directly), since it 
75      * expands and moves periodically. All of the hash table
76      * entries turn into dangling references, yadda yadda. 
77      */
78
79     len = strlen(s)+1;
80     vec_add2(the_strtab, this_string, len);
81     memcpy(this_string, s, len);
82     
83     /* Make a copy which won't be moving around... */
84     vec_validate(scopy, len);
85     memcpy(scopy, s, len);
86
87     hash_set_mem(the_strtab_hash, scopy, this_string - the_strtab);
88
89     return(this_string - the_strtab);
90 }
91
92 /*
93  * find_or_add_track
94  * returns index in track table
95  */
96 u32 find_or_add_track(void *s_arg)
97 {
98     uword *p;
99     track_t *this_track;
100     u8 *copy_s;
101     char *s=s_arg;
102
103     p = hash_get_mem(the_track_hash, s);
104     if (p) {
105         return (p[0]);
106     }
107     vec_add2(the_tracks, this_track, 1);
108
109     this_track->original_index = this_track - the_tracks;
110     this_track->strtab_offset = find_or_add_strtab(s);
111
112     copy_s = (u8 *)vec_dup(s);
113
114     hash_set_mem(the_track_hash, copy_s, this_track - the_tracks);
115     return(this_track - the_tracks);
116 }
117
118 /* 
119  * find_or_add_event
120  * Adds an event to the event definition vector and add it to
121  * the event hash table
122  */
123
124 u32 find_or_add_event(void *s_arg, char *datum_format)
125 {
126     uword *p;
127     u8 *copy_s;
128     event_definition_t *this_event_definition;
129     u32 event_id;
130     char *s=s_arg;
131
132     p = hash_get_mem(the_msg_event_hash, s);
133     if (p) {
134         return (p[0]);
135     }
136     vec_add2(the_event_definitions, this_event_definition, 1);
137
138     /* Allocate a new event-id */
139     event_id = clib_bitmap_first_clear (the_event_id_bitmap);
140     the_event_id_bitmap = clib_bitmap_set(the_event_id_bitmap, event_id, 1);
141     this_event_definition->event = event_id;
142     this_event_definition->event_format = find_or_add_strtab(s);
143     this_event_definition->datum_format = find_or_add_strtab(datum_format);
144
145     copy_s = (u8 *)vec_dup(s);
146
147     hash_set_mem(the_msg_event_hash, copy_s, event_id);
148
149     return(event_id);
150 }
151
152 /*
153  * write_string_table
154  */
155 int write_string_table(FILE *ofp)
156 {
157     cpel_section_header_t sh;
158
159     /* Round up string table size */
160     while (vec_len(the_strtab) & 0x7)
161         vec_add1(the_strtab, 0);
162
163     sh.section_type = ntohl(CPEL_SECTION_STRTAB);
164     sh.data_length = ntohl(vec_len(the_strtab));
165     
166     if (fwrite(&sh, sizeof(sh), 1, ofp) != 1)
167         return(0);
168     
169     if (fwrite(the_strtab, 1, vec_len(the_strtab), ofp) != 
170         vec_len(the_strtab))
171         return(0);
172
173     return(1);
174 }
175
176 /*
177  * write_cpel_header
178  */
179 int write_cpel_header(FILE *ofp, u32 nsections)
180 {
181     cpel_file_header_t h;
182     
183     h.endian_version = CPEL_FILE_VERSION;
184     h.pad = 0; 
185     h.nsections = ntohs(nsections);
186     h.file_date = ntohl(time(0));
187     if (fwrite(&h, sizeof(h), 1, ofp) != 1)
188         return (0);
189
190     return(1);
191 }
192
193 /* 
194  * write_event_defs
195  */
196 int write_event_defs(FILE *ofp)
197 {
198     cpel_section_header_t sh;
199     event_definition_section_header_t edsh;
200     event_definition_t *this_event_definition;
201     int i;
202
203     /* Next, the event definitions */
204     sh.section_type = ntohl(CPEL_SECTION_EVTDEF);
205     sh.data_length = ntohl(vec_len(the_event_definitions)
206                            *sizeof(the_event_definitions[0]) 
207                            + sizeof(event_definition_section_header_t));
208
209     if (fwrite(&sh, sizeof(sh), 1, ofp) != 1)
210         return(0);
211
212     clib_memset(&edsh, 0, sizeof(edsh));
213
214     strcpy(edsh.string_table_name, "FileStrtab");
215     edsh.number_of_event_definitions = ntohl(vec_len(the_event_definitions));
216     
217     if (fwrite(&edsh, sizeof(edsh), 1, ofp) != 1)
218         return(0);
219
220     for (i = 0; i < vec_len(the_event_definitions); i++) {
221         this_event_definition = &the_event_definitions[i];
222         /* Endian fixup */
223         this_event_definition->event = ntohl(this_event_definition->event);
224         this_event_definition->event_format = 
225             ntohl(this_event_definition->event_format);
226         this_event_definition->datum_format =
227             ntohl(this_event_definition->datum_format);
228
229         if (fwrite(this_event_definition, sizeof(the_event_definitions[0]), 
230                    1, ofp) != 1)
231             return(0);
232     }
233     return(1);
234 }
235
236 /*
237  * ntohll
238  */
239 u64 ntohll (u64 x) {
240     if (clib_arch_is_little_endian)
241         x = ((((x >> 0) & 0xff) << 56)
242              | (((x >> 8) & 0xff) << 48)
243              | (((x >> 16) & 0xff) << 40)
244              | (((x >> 24) & 0xff) << 32)
245              | (((x >> 32) & 0xff) << 24)
246              | (((x >> 40) & 0xff) << 16)
247              | (((x >> 48) & 0xff) << 8)
248              | (((x >> 56) & 0xff) << 0));
249     
250     return x;
251 }
252
253 /* 
254  * write_events
255  */
256 int write_events(FILE *ofp, u64 clock_ticks_per_second)
257 {
258     cpel_section_header_t sh;
259     event_section_header_t eh;
260     u32 number_of_events;
261     int i;
262     event_entry_t e;
263     u64 net_timestamp;
264     evt_t *this_event;
265     u32 time0, time1;
266
267     number_of_events = vec_len(the_events);
268
269     sh.section_type = ntohl(CPEL_SECTION_EVENT);
270     sh.data_length = ntohl(number_of_events * sizeof(e) +
271                            sizeof(event_section_header_t));
272
273     if (fwrite(&sh, sizeof(sh), 1, ofp) != 1)
274         return(0);
275     
276     clib_memset(&eh, 0, sizeof(eh));
277     strcpy(eh.string_table_name, "FileStrtab");
278     eh.number_of_events = ntohl(number_of_events);
279     eh.clock_ticks_per_second = ntohl(clock_ticks_per_second);
280     
281     if (fwrite(&eh, sizeof(eh), 1, ofp) != 1)
282         return(0);
283
284     for (i = 0; i < number_of_events; i++) {
285         this_event = &the_events[i];
286         net_timestamp = ntohll(this_event->timestamp);
287     
288         time1 = net_timestamp>>32;
289         time0 = net_timestamp & 0xFFFFFFFF;
290         
291         e.time[0] = time0;
292         e.time[1] = time1;
293         e.track = ntohl(this_event->track_id);
294         e.event_code = ntohl(this_event->event_id);
295         e.event_datum = ntohl(this_event->datum);
296         
297         if (fwrite(&e, sizeof(e), 1, ofp) != 1)
298             return(0);
299     }
300     return(1);
301 }
302
303 /*
304  * write_track_defs
305  */
306 int write_track_defs(FILE *ofp)
307 {
308     cpel_section_header_t sh;
309     track_definition_section_header_t tdsh;
310     track_definition_t record;
311     track_definition_t *this_track_definition = &record;
312     int i;
313     event_definition_section_header_t edsh;
314
315     /* Next, the event definitions */
316     sh.section_type = ntohl(CPEL_SECTION_TRACKDEF);
317     sh.data_length = ntohl(vec_len(the_tracks)
318                            *sizeof(this_track_definition[0]) 
319                            + sizeof(track_definition_section_header_t));
320
321     if (fwrite(&sh, sizeof(sh), 1, ofp) != 1)
322         return(0);
323
324     clib_memset(&tdsh, 0, sizeof(tdsh));
325
326     strcpy(tdsh.string_table_name, "FileStrtab");
327     tdsh.number_of_track_definitions = ntohl(vec_len(the_tracks));
328     
329     if (fwrite(&tdsh, sizeof(edsh), 1, ofp) != 1)
330         return(0);
331
332     for (i = 0; i < vec_len(the_tracks); i++) {
333         this_track_definition->track = ntohl(i);
334         this_track_definition->track_format = 
335             ntohl(the_tracks[i].strtab_offset);
336
337         if (fwrite(this_track_definition, sizeof(this_track_definition[0]),
338                    1, ofp) != 1)
339             return(0);
340     }
341     return(1);
342 }
343
344 void cpel_util_init (void)
345 {
346     u8 *eventstr;
347
348     the_strtab_hash = hash_create_string (0, sizeof (uword));
349     the_msg_event_hash = hash_create_string (0, sizeof (uword));
350     the_track_hash = hash_create_string (0, sizeof (uword));
351     the_pidtid_hash = hash_create_string (0, sizeof(uword));
352     the_pid_to_name_hash = hash_create(0, sizeof(uword));
353     
354     /* Must be first, or no supper... */
355     find_or_add_strtab("FileStrtab");
356
357     /* Historical canned events, no longer used. */
358     if (0) {
359         /* event 0 (not used) */
360         eventstr = format(0, "PlaceholderNotUsed");
361         vec_add1(eventstr, 0);
362         find_or_add_event(eventstr, "%s");
363         vec_free(eventstr);
364         
365         /* event 1 (thread on CPU) */
366         eventstr = format(0, "THREAD/THRUNNING");
367         vec_add1(eventstr, 0);
368         find_or_add_event(eventstr, "%s");
369         vec_free(eventstr);
370         
371         /* event 2 (thread ready) */
372         eventstr = format(0, "THREAD/THREADY");
373         vec_add1(eventstr, 0);
374         find_or_add_event(eventstr, "%s");
375         vec_free(eventstr);
376         
377         /* event 3 (function enter) */
378         eventstr = format(0, "FUNC/ENTER");
379         vec_add1(eventstr, 0);
380         find_or_add_event(eventstr, "0x%x");
381         vec_free(eventstr);
382         
383         /* event 4 (function enter) */
384         eventstr = format(0, "FUNC/EXIT");
385         vec_add1(eventstr, 0);
386         find_or_add_event(eventstr, "0x%x");
387         vec_free(eventstr);
388     }
389 }
390
391 /*
392  * alpha_compare_tracks
393  */
394 static int alpha_compare_tracks(const void *a1, const void *a2)
395 {
396     int i;
397     track_t *t1 = (track_t *)a1;
398     track_t *t2 = (track_t *)a2;
399     u8 *s1 = &the_strtab[t1->strtab_offset];
400     u8 *s2 = &the_strtab[t2->strtab_offset];
401
402     for (i = 0; s1[i] && s2[i]; i++) {
403         if (s1[i] < s2[i])
404             return(-1);
405         if (s1[i] > s2[i])
406             return(1);
407     }
408     return(0);
409 }
410
411 /*
412  * alpha_sort_tracks
413  * Alphabetically sort tracks, set up a mapping
414  * vector so we can quickly map the original track index to
415  * the new/improved/alpha-sorted index
416  */
417 void alpha_sort_tracks(void)
418 {
419     track_t *this_track;
420     int i;
421
422     qsort(the_tracks, vec_len(the_tracks), sizeof(track_t),
423           alpha_compare_tracks);
424
425     vec_validate(track_alpha_map, vec_len(the_tracks));
426     vec_set_len (track_alpha_map, vec_len (the_tracks));
427
428     for (i = 0; i < vec_len(the_tracks); i++) {
429         this_track = &the_tracks[i];
430         track_alpha_map[this_track->original_index] = i;
431     }
432 }
433
434 /*
435  * fixup_event_tracks
436  * Use the track alpha mapping to account for the alphabetic
437  * sort performed by the previous routine
438  */
439 void fixup_event_tracks(void)
440 {
441     int i;
442     u32 old_track;
443
444     for (i = 0; i < vec_len(the_events); i++) {
445         old_track = the_events[i].track_id;
446         the_events[i].track_id = track_alpha_map[old_track];
447     }
448 }
449
450 /* Indispensable for debugging in gdb... */
451
452 u32 vl(void *x)
453 {
454     return vec_len(x);
455 }