blob: 115afad7fb25c1f58cc03646f34f0745027caac4 [file] [log] [blame]
Dave Barach52642c32016-02-11 19:28:19 -05001/*
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
42FILE *g_ifp;
43char *g_ifile;
44
45typedef unsigned long long ulonglong;
46
47void process_traces (void);
48void record_instance (ulong tag, ulonglong time);
49void report_actors (void);
50void scatterplot_data(void);
51int entry_event, exit_event;
52int nokey;
53char *version = "cpelinreg 2.0";
54int model_these[10];
55int model_index;
56int summary_stats;
57ulonglong first_start_time;
58ulonglong last_end_time;
59ulonglong total_time;
60ulong scatterkey;
61int inline_mokus;
62
63typedef 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
73bound_track_t *bound_tracks;
74uword *the_trackdef_hash;
75
76
77#define MAXSTACK 128
78
79typedef struct instance_ {
80 struct instance_ *next;
81 ulonglong time;
82}instance_t;
83
84typedef 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
100actor_t *hash[NBUCKETS];
101
102actor_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
160void 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
191double x[NINSTANCE];
192double y[NINSTANCE];
193
194int 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
215void 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
324void 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
352void fatal(char *s)
353{
354 fprintf(stderr, "%s", s);
355 fprintf(stderr, "\n");
356 exit(1);
357}
358
359typedef enum {
360 PASS1=1,
361} pass_t;
362
363typedef struct {
364 int (*pass1)(cpel_section_header_t *, int, FILE *);
365} section_processor_t;
366
367int 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
373int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp)
374{
375 return(0);
376}
377
378int 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
387int 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
423int 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
666section_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
676int 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
703char *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
750int 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
799int 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}