misc: use right include for fctnl.h and poll.h
[vpp.git] / src / tools / perftool / cpelinreg.c
1 /* 
2  *------------------------------------------------------------------
3  * Copyright (c) 2008-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 /*
18  * Search for O(N**2) functions bracketed by before/after
19  * events. The "before" event's datum is used as a tag, e.g. which function
20  * did we call that's strongly O(N).
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <netinet/in.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <sys/mman.h>
31 #include <unistd.h>
32 #include <ctype.h>
33 #include <vppinfra/clib.h>
34 #include <vppinfra/vec.h>
35 #include <vppinfra/hash.h>
36 #include <pwd.h>
37 #include <stdarg.h>
38 #include <time.h>
39 #include "cpel.h"
40
41 FILE *g_ifp;
42 char *g_ifile;
43
44 typedef unsigned long long ulonglong;
45
46 void process_traces (void);
47 void record_instance (ulong tag, ulonglong time);
48 void report_actors (void);
49 void scatterplot_data(void);
50 int entry_event, exit_event;
51 int nokey;
52 char *version = "cpelinreg 2.0";
53 int model_these[10];
54 int model_index;
55 int summary_stats;
56 ulonglong first_start_time;
57 ulonglong last_end_time;
58 ulonglong total_time;
59 ulong scatterkey;
60 int inline_mokus;
61
62 typedef struct bound_track_ {
63     u32 track_code;
64     u32 *start_datum;
65     u8  *dup_event;
66     int state;
67     u64 *start_time;
68     u64 thread_timestamp;
69     u64 time_thread_on_cpu;
70 } bound_track_t;
71
72 bound_track_t *bound_tracks;
73 uword *the_trackdef_hash;
74
75
76 #define MAXSTACK 128
77
78 typedef struct instance_ {
79     struct instance_ *next;
80     ulonglong time;
81 }instance_t;
82
83 typedef struct actor_ {
84     struct actor_ *next;
85     ulong key;
86     struct instance_ *first;
87     struct instance_ *last;
88     double a;
89     double b;
90     double min;
91     double max;
92     double mean;
93     double r;
94     ulong ninst;
95 } actor_t;
96
97 #define NBUCKETS 1811
98
99 actor_t *hash[NBUCKETS];
100
101 actor_t *find_or_create_actor (ulong key)
102 {
103     ulong bucket;
104     actor_t *ap;
105     u8 *mem;
106
107     bucket = key % NBUCKETS;
108
109     ap = hash[bucket];
110
111     if (ap == NULL) {
112         /* Ensure 8-byte alignment to avoid (double) alignment faults */
113         mem = malloc(sizeof(*ap) + 4);
114         if (((uword)(mem)) & 0x7)
115             mem += 4;
116         ap = (actor_t *)mem;
117
118         if (ap == NULL) {
119             fprintf (stderr, "out of memory...\n");
120             exit (1);
121         }
122         ap->next = 0;
123         ap->key = key;
124         ap->first = 0;
125         ap->last = 0;
126         ap->a = 0.00;
127         ap->b = 0.00;
128         hash [bucket] = ap;
129         return (ap);
130     }
131     
132     while (ap) {
133         if (ap->key == key)
134             return (ap);
135         ap = ap->next;
136     }
137
138     mem = malloc(sizeof(*ap)+4);
139     if (((uword)(mem) & 0x7))
140         mem += 4;
141     ap = (actor_t *)mem;
142
143     if (ap == NULL) {
144         fprintf (stderr, "out of memory...\n");
145         exit (1);
146     }
147     ap->key = key;
148     ap->first = 0;
149     ap->last = 0;
150     ap->a = 0.00;
151     ap->b = 0.00;
152
153     ap->next = hash[bucket];
154     hash[bucket] = ap;
155
156     return (ap);
157 }
158
159 void record_instance (ulong key, ulonglong time)
160 {
161     actor_t *ap;
162     instance_t *ip;
163
164     if (nokey)
165         key = 0;
166
167     ap = find_or_create_actor (key);
168
169     ip = (instance_t *)malloc(sizeof(*ip));
170     if (ip == NULL) {
171         fprintf (stderr, "out of memory...\n");
172         exit (1);
173     }
174     ip->time = time;
175     ip->next = 0;
176
177     if (ap->first == 0) {
178         ap->first = ip;
179         ap->last = ip;
180         ap->ninst = 1;
181     } else {
182         ap->last->next = ip;
183         ap->last = ip;
184         ap->ninst++;
185     }
186 }
187
188 #define NINSTANCE 200000
189
190 double x[NINSTANCE];
191 double y[NINSTANCE];
192
193 int actor_compare (const void *arg1, const void *arg2)
194 {
195     double e10k1, e10k2;
196     actor_t **a1 = (actor_t **)arg1;
197     actor_t **a2 = (actor_t **)arg2;
198     double ninst1, ninst2;
199
200     ninst1 = ((double)((*a1)->ninst));
201     ninst2 = ((double)((*a2)->ninst));
202     
203     e10k1 = ninst1 * ((*a1)->mean);
204     e10k2 = ninst2 * ((*a2)->mean);
205
206     if (e10k1 < e10k2)
207         return (1);
208     else if (e10k1 == e10k2)
209         return (0);
210     else
211         return (-1);
212 }
213
214 void report_actors (void)
215 {
216     int i;
217     actor_t *ap;
218     instance_t *ip;
219     int nactors = 0;
220     int ninstance;
221     actor_t **actor_vector;
222     double e10k;
223     extern void linreg (double *x, double *y, int nitems, double *a, double *b,
224                         double *minp, double *maxp, double *meanp, double *r);
225
226     for (i = 0; i < NBUCKETS; i++) {
227         ap = hash[i];
228         if (ap == NULL)
229             continue;
230         while (ap) {
231             nactors++;
232             ninstance = 0;
233
234             ip = ap->first;
235
236             while (ip) {
237                 if (ninstance < NINSTANCE) {
238                     x[ninstance] = ninstance;
239                     y[ninstance] = ((double)ip->time);
240                     ninstance++;
241                 }
242                 ip = ip->next;
243             }
244             if (ninstance > 1) {
245 #if DEBUG > 0
246                 int j;
247                 
248                 for (j = 0; j < ninstance; j++) {
249                     printf("x[%d] = %10.2f, y[%d] = %10.2f\n",
250                            j, x[j], j, y[j]);
251                 }
252 #endif                    
253                 
254                 linreg (x, y, ninstance, &ap->a, &ap->b, &ap->min,
255                         &ap->max, &ap->mean, &ap->r);
256             } else {
257                 ap->a = 0.00;
258                 ap->b = 0.00;
259             }
260             
261             ap = ap->next;
262         }
263     }
264             
265     actor_vector = (actor_t **)malloc (nactors*sizeof(*actor_vector));
266     nactors = 0;
267
268     for (i = 0; i < NBUCKETS; i++) {
269         ap = hash[i];
270         if (ap == NULL)
271             continue;
272         while (ap) {
273             if ((ap->a != 0.00) || (ap->b != 0.00)) {
274                 actor_vector[nactors++] = ap;
275             }
276             ap = ap->next;
277         }
278     }
279         
280     qsort (actor_vector, nactors, sizeof (actor_t *), actor_compare);
281
282     if (summary_stats)
283         printf("NInst       Offset       Slope    T(Ninst)         Min         Max         Avg   %%InstTime           R    Key");
284     else
285         printf("NInst       Offset       Slope    T(Ninst)    Key");
286
287     for (i = 0; i < model_index; i++) {
288         printf ("T @ %-8d ", model_these[i]);
289     }
290
291     printf ("\n");
292
293     for (i = 0; i < nactors; i++) {
294         int j;
295         double ninst;
296         double pcttot;
297         ap = actor_vector[i];
298         ninst = ap->ninst;
299
300         e10k = ninst * (ap->a + ap->b*((ninst-1.0)/2.0));
301
302         if (ap->ninst) {
303             if (summary_stats) {
304                 pcttot = (e10k / ((double)total_time)) * 100.0;
305                 printf ("%6ld %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f 0x%08lx ",
306                         ap->ninst, ap->a, ap->b, e10k, ap->min,
307                         ap->max, ap->mean, pcttot, ap->r, ap->key);
308             }
309             else
310                 printf ("%6ld %11.2f %11.2f %11.2f 0x%08lx ",
311                         ap->ninst, ap->a, ap->b, e10k, ap->key);
312
313             for (j = 0; j < model_index; j++) {
314                 ninst = model_these[j];
315                 e10k = ninst * (ap->a + ap->b*((ninst-1.0)/2.0));
316                 printf ("%10.2f ", e10k);
317             }
318             printf ("\n");
319         }
320     }
321 }
322
323 void scatterplot_data(void)
324 {
325     actor_t *ap;
326     int i;
327     instance_t *ip;
328     double time;
329     int count=0;
330
331     for (i = 0; i < NBUCKETS; i++) {
332         ap = hash[i];
333         if (ap == NULL)
334             continue;
335         while (ap) {
336             if (ap->key == scatterkey){
337                 ip = ap->first;
338                 while (ip) {
339                     time = ((double)ip->time);
340                     printf ("%d\t%.0f\n", count++, time);
341                     ip = ip->next;
342                 }
343                 return;
344             }
345             ap = ap->next;
346         }
347     }
348 }
349
350
351 void fatal(char *s)
352 {
353     fprintf(stderr, "%s", s);
354     fprintf(stderr, "\n");
355     exit(1);
356 }
357
358 typedef enum {
359     PASS1=1,
360 } pass_t;
361
362 typedef struct {
363     int (*pass1)(cpel_section_header_t *, int, FILE *);
364 } section_processor_t;
365
366 int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp)
367 {
368     fprintf(ofp, "Bad (type 0) section, skipped...\n");
369     return(0);
370 }
371
372 int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp)
373 {
374     return(0);
375 }
376
377 int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp)
378 {
379     if (verbose) {
380         fprintf(ofp, "Unsupported type %d section\n",
381                 ntohl(sh->section_type));
382     }
383     return(0);
384 }
385
386 int trackdef_pass(cpel_section_header_t *sh, int verbose, FILE *ofp)
387 {
388     int i, nevents;
389     track_definition_section_header_t *tdh;
390     track_definition_t *tp;
391     u32 track_code;
392     uword *p;
393     bound_track_t *btp;
394
395     tdh = (track_definition_section_header_t *)(sh+1);
396     nevents = ntohl(tdh->number_of_track_definitions);
397     
398     if (verbose) {
399         fprintf(stderr, "Track Definition Section: %d definitions\n",
400                 nevents);
401     }
402
403     tp = (track_definition_t *)(tdh+1);
404     
405     for (i = 0; i < nevents; i++) {
406         track_code = ntohl(tp->track);
407         p = hash_get(the_trackdef_hash, track_code);
408         if (p) {
409             fprintf(ofp, "track %d redefined, retain first definition\n",
410                     track_code);
411             continue;
412         }
413         vec_add2(bound_tracks, btp, 1);
414         btp->track_code = track_code;
415         hash_set(the_trackdef_hash, track_code, btp - bound_tracks);
416         tp++;
417     }
418     return (0);
419 }
420
421
422 int event_pass (cpel_section_header_t *sh, int verbose, FILE *ofp)
423 {
424     event_section_header_t *eh;
425     event_entry_t *ep;
426     f64 ticks_per_us;
427     long output_count;
428     long dup_events = 0;
429     ulonglong end_time = 0;
430     double t;
431     int sp, ancestor;
432     int nevents, i;
433     u64 now;
434     u64 time0, time1;
435     double d;
436     u32 last_track_code = 0xdeafb00b;
437     u32 track_code;
438     u32 event_code, event_datum;
439     bound_track_t *tp = 0;
440     uword *p;
441
442     output_count = 0;
443     total_time = 0;
444
445     eh = (event_section_header_t *)(sh+1);
446     nevents = ntohl(eh->number_of_events);
447     ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second))/1e6;
448
449     if (verbose) {
450         fprintf(ofp, "%.3f ticks_per_us\n", ticks_per_us);
451     }
452
453     ep = (event_entry_t *)(eh+1);
454
455     time0 = ntohl (ep->time[0]);
456     time1 = ntohl (ep->time[1]);
457     
458     now = (((u64) time0)<<32) | time1;
459     d = now;
460     d /= ticks_per_us;
461     first_start_time = d;
462
463     for (i = 0; i < nevents; i++) {
464         time0 = ntohl (ep->time[0]);
465         time1 = ntohl (ep->time[1]);
466
467         now = (((u64) time0)<<32) | time1;
468         
469         /* Convert from bus ticks to usec */
470         d = now;
471         d /= ticks_per_us;
472
473         now = d;
474
475         track_code = ntohl(ep->track);
476         event_code = ntohl(ep->event_code);
477         event_datum = ntohl(ep->event_datum);
478
479         if (track_code != last_track_code) {
480             if (tp) {
481                 tp->thread_timestamp += now - tp->time_thread_on_cpu;
482                 tp->time_thread_on_cpu = 0;
483             }
484             p = hash_get(the_trackdef_hash, track_code);
485             if (!p) {
486                 /* synthesize a new track */
487                 vec_add2(bound_tracks, tp, 1);
488                 tp->track_code = track_code;
489                 hash_set(the_trackdef_hash, track_code, tp - bound_tracks);
490             } else {
491                 tp = bound_tracks + p[0];
492             }
493             last_track_code = track_code;
494             tp->time_thread_on_cpu = now;
495         }
496
497         if (event_code != entry_event &&
498             event_code != exit_event) {
499             ep++;
500             continue;
501         }
502         
503     again:
504         switch (tp->state) {
505         case 0:                 /* not in state */
506             /* Another exit event? Stack pop */
507             if (event_code == exit_event) {
508                 /* Only if we have something on the stack */
509                 if (vec_len(tp->start_datum) > 0) {
510                     tp->state = 1;
511                     goto again;
512                 } else {
513                     fprintf (stderr, 
514                              "End event before start event, key 0x%x.", 
515                              ntohl(ep->event_datum));
516                     fprintf (stderr, " Interpret results carefully...\n");
517                 }
518             }
519
520             tp->state = 1;
521             if (vec_len(tp->start_datum) >= MAXSTACK) {
522                 int j;
523
524                 fprintf (stderr, "stack overflow..\n");
525                 for (j = vec_len(tp->start_datum)-1; j >= 0; j--) {
526                     fprintf(stderr, "stack[%d]: datum 0x%x\n", 
527                             j, tp->start_datum[j]);
528                 }
529                 fprintf (stderr, 
530                          "Stack overflow... This occurs when "
531                          "(start, datum)...(end, datum) events\n"
532                          "are not properly paired.\n\n"
533                          "A typical scenario looks like this:\n\n"
534                          "    ...\n"
535                          "    ELOG(..., START_EVENT, datum);\n"
536                          "    if (condition)\n"
537                          "       return; /*oops, forgot the end event*/\n"
538                          "    ELOG(..., END_EVENT, datum);\n"
539                          "    ...\n\n"
540                          "The datum stack dump (above) should make it clear\n"
541                          "where to start looking for a sneak path...\n");
542
543                 exit (1);
544             }
545             vec_add1(tp->start_datum, event_datum);
546             vec_add1(tp->start_time, (tp->thread_timestamp + (now - tp->time_thread_on_cpu)));
547 #ifdef HAVING_TROUBLE
548             printf ("sp %lld key 0x%x start time %llu\n", 
549                     (long long) vec_len(tp->start_time)-1, event_datum, 
550                     (unsigned long long) 
551                     tp->start_time [vec_len(tp->start_time)-1]);
552             printf ("timestamp %llu, now %llu, thread on cpu %llu\n",
553                     (unsigned long long) tp->thread_timestamp, 
554                     (unsigned long long) now, 
555                     (unsigned long long) tp->time_thread_on_cpu);
556 #endif
557             
558
559             
560             /* 
561              * Multiple identical enter events? If the user knows that
562              * gcc is producing bogus events due to inline functions,
563              * trash the duplicate.
564              */
565             if (inline_mokus 
566                 && vec_len (tp->start_datum) > 1
567                 && tp->start_datum [vec_len(tp->start_datum)-1] ==
568                 tp->start_datum [vec_len(tp->start_datum)-2]) {
569                 vec_add1 (tp->dup_event, 1);
570             } else {
571                 vec_add1 (tp->dup_event, 0);
572             }
573
574
575             ep++;
576             continue;
577
578         case 1:                 /* in state */
579             /* Another entry event? Stack push*/
580             if (event_code == entry_event) {
581                 tp->state = 0;
582                 goto again;
583             }
584             
585             if (vec_len(tp->start_datum) == 0) {
586                 fprintf (stderr, "Stack underflow...\n");
587                 exit (1);
588             }
589
590             sp = vec_len(tp->start_time)-1;
591
592             end_time = tp->thread_timestamp + (now - tp->time_thread_on_cpu);
593
594             if (!tp->dup_event[sp]) {
595 #ifdef HAVING_TROUBLE
596                 printf ("sp %d key 0x%x charged %llu\n", sp, 
597                         tp->start_datum[sp], end_time - tp->start_time[sp]);
598                 printf ("  start %llu, end %llu\n", (unsigned long long) tp->start_time[sp],
599                         (unsigned long long) end_time);
600 #endif
601             
602                 record_instance (tp->start_datum[sp], (end_time -
603                                                        tp->start_time[sp]));
604             
605                 /* Factor out our time from surrounding services, if any */
606                 for (ancestor = sp-1; ancestor >= 0; ancestor--) {
607 #ifdef HAVING_TROUBLE
608                     printf ("Factor out %lld from key 0x%08x\n",
609                             (end_time - tp->start_time[sp]), tp->start_datum[ancestor]);
610 #endif
611                     tp->start_time[ancestor] += (end_time - tp->start_time[sp]);
612                 }
613                 output_count++;
614                 total_time += (end_time - tp->start_time[sp]);
615                 tp->state = 0;
616             } else {
617                 dup_events++;
618             }
619             vec_set_len (tp->start_datum, sp);
620             vec_set_len (tp->start_time, sp);
621             vec_set_len (tp->dup_event, sp);
622         }
623
624         ep++;
625     }
626     last_end_time = now;
627
628     if (scatterkey) {
629         scatterplot_data();
630         exit (0);
631     }
632
633     if (output_count) {
634         t = (double)total_time;
635         printf ("%ld instances of state, %.2f microseconds average\n",
636                 output_count, t / output_count);
637
638         printf ("Total instrumented runtime: %.2f microseconds\n",
639                 ((double)total_time));
640         printf ("Total runtime: %lld microseconds\n",
641                 last_end_time - first_start_time);
642
643         t /= (double)(last_end_time - first_start_time);
644         t *= 100.0;
645
646         if (dup_events) {
647             printf ("Suppressed %ld duplicate state entry events\n",
648                     dup_events);
649         }
650         printf ("Instrumented code accounts for %.2f%% of total time.\n\n",
651                 t);
652         report_actors();
653     } else {
654         printf ("No instances of state...\n");
655     }
656
657     return(0);
658 }
659
660 /* 
661  * Note: If necessary, add passes / columns to this table to 
662  * handle section order dependencies.
663  */
664
665 section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] =
666 {
667     {unsupported_pass},         /* type 0 -- f**ked */
668     {noop_pass},                /* type 1 -- STRTAB */
669     {noop_pass},                /* type 2 -- SYMTAB */
670     {noop_pass},                /* type 3 -- EVTDEF */
671     {trackdef_pass},            /* type 4 -- TRACKDEF */
672     {event_pass},               /* type 5 -- EVENTS */
673 };
674
675 int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp,
676                     pass_t pass)
677 {
678     u32 type;
679     type = ntohl(sh->section_type);
680     int rv;
681     int (*fp)(cpel_section_header_t *, int, FILE *);
682
683     if (type > CPEL_NUM_SECTION_TYPES) {
684         fprintf(stderr, "Unknown section type %d\n", type);
685         return(1);
686     }
687     switch(pass) {
688     case PASS1:
689         fp = processors[type].pass1;
690         break;
691
692     default:
693         fprintf(stderr, "Unknown pass %d\n", pass);
694         return(1);
695     }
696
697     rv = (*fp)(sh, verbose, ofp);
698
699     return(rv);
700 }
701
702 char *mapfile (char *file)
703 {
704     struct stat statb;
705     char *rv;
706     int maphfile;
707     size_t mapfsize;
708     
709     maphfile = open (file, O_RDONLY);
710
711     if (maphfile < 0)
712     {
713         fprintf (stderr, "Couldn't read %s, skipping it...\n", file);
714         return (NULL);
715     }
716
717     if (fstat (maphfile, &statb) < 0)
718     {
719         fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file);
720         return (NULL);
721     }
722
723     /* Don't try to mmap directories, FIFOs, semaphores, etc. */
724     if (! (statb.st_mode & S_IFREG)) {
725         fprintf (stderr, "%s is not a regular file, skipping it...\n", file);
726         return (NULL);
727     }
728
729     mapfsize = statb.st_size;
730
731     if (mapfsize < 3)
732     {
733         fprintf (stderr, "%s zero-length, skipping it...\n", file);
734         close (maphfile);
735         return (NULL);
736     }
737
738     rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0);
739
740     if (rv == 0)
741     {
742         fprintf (stderr, "%s problem mapping, I quit...\n", file);
743         exit (-1);
744     }
745     close (maphfile);
746     return (rv);
747 }
748
749 int process_file (u8 *cpel, int verbose)
750 {
751     cpel_file_header_t *fh;
752     cpel_section_header_t *sh;
753     u16 nsections;
754     u32 section_size;
755     int i;
756     FILE *ofp = stderr;
757
758     /* First, the file header */
759     fh = (cpel_file_header_t *)cpel;
760     if (fh->endian_version != CPEL_FILE_VERSION) {
761         if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) {
762             fprintf(stderr, "Little endian data format not supported\n");
763             return(1);
764         }
765         fprintf(stderr, "Unsupported file version 0x%x\n", 
766                 fh->endian_version);
767         return(1);
768     }
769     nsections = ntohs(fh->nsections);
770
771     /*
772      * Take a passe through the file. 
773      */
774     sh = (cpel_section_header_t *)(fh+1);
775     for (i = 0; i < nsections; i++) {
776         section_size = ntohl(sh->data_length);
777
778         if(verbose) {
779             fprintf(ofp, "Section type %d, size %d\n", 
780                     ntohl(sh->section_type),
781                     section_size);
782         }
783
784         if(process_section(sh, verbose, ofp, PASS1))
785             return(1);
786
787         sh++;
788         sh = (cpel_section_header_t *)(((u8 *)sh)+section_size);
789     }
790
791     return(0);
792 }
793
794 /****************************************************************************
795 * main - 
796 ****************************************************************************/
797
798 int main (int argc, char **argv)
799 {
800     int curarg = 1;
801     u8 *cpel = 0;
802     int verbose = 0;
803
804     if (argc < 6)
805     {
806         fprintf (stderr, "usage: cpelinreg -i <file>\n");
807         fprintf (stderr, "       -s start-event --e end-event [-nokey]\n");
808         fprintf (stderr, "       [-m <ninst-to-model>][-xtra-stats]\n");
809         fprintf (stderr, "       [-keyscatterplot <hex-key>]\n\n");
810         fprintf (stderr, "%s\n", version);
811         exit (1);
812     }
813
814     while (curarg < argc) {
815         if (!strncmp (argv[curarg], "-ifile", 2)) {
816             curarg++;
817             g_ifile = argv[curarg++];
818             continue;
819         }
820         if (!strncmp (argv[curarg], "-start", 2)) {
821             curarg++;
822             entry_event = atol (argv [curarg++]);
823             continue;
824         }
825         if (!strncmp (argv[curarg], "-end", 2)) {
826             curarg++;
827             exit_event = atol (argv [curarg++]);
828             continue;
829         }
830
831         if (!strncmp(argv[curarg], "-badinlines", 2)) {
832             curarg++;
833             inline_mokus = 1;
834             continue;
835         }
836
837         if (!strncmp (argv[curarg], "-x", 2)) {
838             curarg++;
839             summary_stats=1;
840             continue;
841         }
842         if (!strncmp (argv[curarg], "-nokey", 2)) {
843             curarg++;
844             nokey = 1;
845             continue;
846         }
847         if (!strncmp (argv[curarg], "-keyscatterplot", 2)) {
848             curarg++;
849             sscanf (argv[curarg], "%lx", &scatterkey);
850             curarg++;
851             continue;
852         }
853
854         if (!strncmp (argv[curarg], "-model", 2)) {
855             if (model_index >= sizeof(model_these) / sizeof(int)) {
856                 fprintf (stderr, "Too many model requests\n");
857                 exit (1);
858             }
859             curarg++;
860             model_these[model_index++] = atol (argv [curarg++]);
861             continue;
862         }
863         if (!strncmp (argv[curarg], "-verbose", 2)) {
864             verbose++;
865             curarg++;
866             continue;
867         }
868
869         fprintf (stderr, "unknown switch '%s'\n", argv[curarg]);
870         exit (1);
871     }
872                 
873     cpel = (u8 *)mapfile(g_ifile);
874
875     if (cpel == NULL)
876     {
877         fprintf (stderr, "Couldn't open %s\n", g_ifile);
878         exit (1);
879     }
880
881     printf ("Extracting state info from %s\nentry_event %d, exit_event %d\n",
882             g_ifile, entry_event, exit_event);
883     if (nokey) {
884         printf ("All state instances mapped to a single actor chain\n");
885     }
886
887     the_trackdef_hash = hash_create (0, sizeof (uword));
888
889     process_file(cpel, verbose);
890     exit (0);
891 }