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