-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlcomp
1690 lines (1683 loc) · 41.2 KB
/
lcomp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Subject: v20i082: "Cheap dynamic instruction counting"
Newsgroups: comp.sources.unix
Sender: sources
Approved: [email protected]
Submitted-by: Paul Haahr <[email protected]>
Posting-number: Volume 20, Issue 82
Archive-name: lcomp
[ This is a poor summary of Paul's excellent README; I'm not sure why
I think it's so great, but I do. /r$ ]
This package is based on Peter Weinberger's "Cheap Dynamic Instruction
Counting" from the AT&T Bell Labs Tech Journal Unix(tm) issue of a
few years ago (Vol 63, No 8, Oct 1984, pp 1815-1826). These programs
were written for a class taught by David Hanson at Princeton University
in Spring 1988. (Computer Science 596, Systems Programming Workshop)
This code runs on Sun-3s (68020s) and Vaxen (4.3 bsd and ultrix). The
files 68020.l and vax.l are lex programs that match the instructions in an
assembly program. I did the 68020 port in about an hour. If people are
interested, I will maintain a library of machine.l files.
paul haahr
princeton!haahr [email protected]
# to unbundle, sh this file
# bundled by haahr on elliot at Sun May 8 14:48:31 EDT 1988
echo README 1>&2
sed 's/^-//' > README <<'end of README'
-README for lcomp and lprint
-cheap dynamic instruction counting
-
-This package is based on Peter Weinberger's "Cheap Dynamic Instruction
-Counting" from the AT&T Bell Labs Tech Journal Unix(tm) issue of a
-few years ago (Vol 63, No 8, Oct 1984, pp 1815-1826). These programs
-were written for a class taught by David Hanson at Princeton University
-in Spring 1988. (Computer Science 596, Systems Programming Workshop)
-
-This code runs on Sun-3s (68020s) and Vaxen (4.3 bsd and ultrix). Since it
-works with the assembly language output of compilers, it needs to make
-some assumptions. The files 68020.l and vax.l are lex programs that match
-the instructions in an assembly program. For new machines, if the assembler
-is a unix-like assembler and the compiler doesn't do too many strange things,
-it should be possible to easily change one of the included .l files to work
-if you look at the code a bit and know the relevant assembly language. If
-people are interested, I will maintain a library of machine.l files.
-
-To get this working on a vax or a sun, edit the makefile to set TARGET
-to 68020 or vax, and change BIN, LIB, and MAN and do a make install.
-BIN, LIB, and MAN may not be the current directory. If you do not want
-to install the programs, edit lcomp to change the LIB directory to the
-current directory.
-
-See the enclosed manual page (and Weinberger's paper) for how to use
-and interpret the results of these programs.
-
-The interesting thing about this package is the use of lex to drive the
-instruction recognizer. I like this approach, and would defend it,
-because i did my port to the sun 68020 compiler in less than an hour by
-changing the patterns matched and the inserted assembly code (all in
-the lex source). Only two small changes had to be made to the machine
-independent code (bb.c) to support the sun, but this was just because
-of a few vax-centrist assumptions I had made when writing the original code.
-See the file INTERNALS for a description of how to write the driver for
-a new machine.
-
-lcomp functions as either cc or f77. I have not found a case where it
-breaks. Note that you must use -F when linking fortran .o files if
-there are no .f files listed as arguments.
-
-lprint is modelled on the Ninth Edition manual page for Weinberger's code,
-but I wrote it from memory and confused the meaning of all of his
-options. Since my lprint and his have different functionality and I
-thought my names made more sense for my program, I kept my version of
-the option names.
-
-For a different approach to writing a package like this, see Sun's tcov,
-which add profiling code to C source rather than compiler output.
-
-
-This code is wholly within the public domain. It is not copy(right|left)ed
-by anyone or any organization. Do with it what you wish.
-
-Paul Haahr
-princeton!haahr ([email protected])
end of README
echo makefile 1>&2
sed 's/^-//' > makefile <<'end of makefile'
-CFLAGS = -O
-LIBS = -ll
-TARGET = vax
-GENDEP = /lib/cpp -M # on ultrix, use /lib/cpp -Em
-
-SRC = README makefile INTERNALS lcomp.1 lcomp \
- bbexit.c bbfile.c \
- bb.h new.h bool.h \
- bb.c lprint.c ealloc.c efopen.c \
- vax.l 68020.l
-
-LPRINT = lprint.o ealloc.o efopen.o
-BB = bb.o ealloc.o efopen.o $(TARGET).o
-
-HOME = /u/haahr
-BIN = $(HOME)/bin
-LIB = $(HOME)/lib/bb
-MAN = $(HOME)/lib/man/man1
-
-# normal targets
-
-all : bb bbexit.o bbfile.o lprint
-
-bb : $(BB)
- $(CC) $(CFLAGS) -o bb $(BB) $(LIBS)
-
-lprint : $(LPRINT)
- $(CC) $(CFLAGS) -o lprint $(LPRINT)
-
-
-# c code checking
-
-# using V8 cyntax
-CYNTAX = cyntax
-CYN = O
-CYNLIB =
-
-# using sun system V lint
-#CYNTAX = /usr/5bin/lint
-#CYN = ln
-#CYNLIB = -ll
-
-
-CLPRINT = lprint.$(CYN) ealloc.$(CYN) efopen.$(CYN)
-CBB = bb.$(CYN) ealloc.$(CYN) efopen.$(CYN) $(TARGET).$(CYN)
-
-.SUFFIXES: .$(CYN)
-
-.c.$(CYN):
- -$(CYNTAX) $(CFLAGS) -c $*.c
-
-cyntax : Cbb Clprint bbexit.$(CYN) bbfile.$(CYN)
-
-Cbb : $(CBB)
- -$(CYNTAX) $(CFLAGS) $(CBB) $(CYNLIB)
-
-Clprint : $(CLPRINT)
- -$(CYNTAX) $(CFLAGS) $(CLPRINT)
-
-$(TARGET).$(CYN) : $(TARGET).l
- lex $(LFLAGS) -t $(TARGET).l > $(TARGET).c
- -$(CYNTAX) $(CFLAGS) -c $(TARGET).c
- rm -f $(TARGET).c
-
-
-# installation procedure
-
-install : bin lib man
-bin : $(BIN)/lprint $(BIN)/lcomp
-lib : $(LIB)/bb $(LIB)/bbexit.o $(LIB)/bbfile.o
-man : $(MAN)/lcomp.1
-
-$(BIN)/lcomp : lcomp
- sed 's+^LIB=.*$$+LIB='$(LIB)+ lcomp > $(BIN)/lcomp
-
-$(BIN)/lprint : lprint
- cp lprint $(BIN)
- strip $(BIN)/lprint
-
-$(LIB)/bb : bb
- cp bb $(LIB)
- strip $(LIB)/bb
-
-$(LIB)/bbexit.o : bbexit.o
- cp bbexit.o $(LIB)
-
-$(LIB)/bbfile.o : bbfile.o
- cp bbfile.o $(LIB)
-
-$(MAN)/lcomp.1 : lcomp.1
- sed 's+\$$LIB+'$(LIB)+g lcomp.1 > $(MAN)/lcomp.1
-
-bundle : $(SRC)
- @bundle $(SRC)
-
-wc :
- @wc $(SRC)
-
-delta : $(SRC)
- @echo "message for $?"
- @cat > .cimsg
- @ci -q -l -m"`cat .cimsg`" $?
- @rm -f .cimsg
- @touch delta
-
-clean :
- rm -f a.out prof.out bb lprint lex.yy.c makefile.dep *.sL *.[Oos] *%
-
-depend :
- sed '/^# --- cut here ---$$/q' makefile > makefile.dep
- for i in *.[cly]; do $(GENDEP) $$i; done >> makefile.dep
- mv makefile.dep makefile
-
-# --- cut here ---
-68020.o: 68020.l
-68020.o: /usr/include/stdio.h
-68020.o: /usr/include/ctype.h
-68020.o: /usr/include/string.h
-68020.o: ./bool.h
-68020.o: ./bb.h
-bb.o: bb.c
-bb.o: /usr/include/stdio.h
-bb.o: /usr/include/ctype.h
-bb.o: /usr/include/string.h
-bb.o: ./new.h
-bb.o: ./bool.h
-bb.o: ./bb.h
-bbexit.o: bbexit.c
-bbexit.o: /usr/include/stdio.h
-ealloc.o: ealloc.c
-ealloc.o: /usr/include/stdio.h
-ealloc.o: ./new.h
-ealloc.o: /usr/include/string.h
-efopen.o: efopen.c
-efopen.o: /usr/include/stdio.h
-lprint.o: lprint.c
-lprint.o: /usr/include/stdio.h
-lprint.o: /usr/include/string.h
-lprint.o: ./bool.h
-lprint.o: ./new.h
-max.o: max.c
-panic.o: panic.c
-panic.o: /usr/include/stdio.h
-vax.o: vax.l
-vax.o: /usr/include/stdio.h
-vax.o: /usr/include/ctype.h
-vax.o: /usr/include/string.h
-vax.o: ./bool.h
-vax.o: ./bb.h
end of makefile
echo INTERNALS 1>&2
sed 's/^-//' > INTERNALS <<'end of INTERNALS'
-INTERNALS for lcomp
-(or how to write a driver for a new instruction set)
-
-The driver for lcomp (actually, bb) is a lex program which matches the
-instruction field of a compiler's assembly output. General machine
-code for most architectures would be very hard to write basic block
-counting code for, as many things that one wants to be able to find are
-hard to identify (for example, can one tell the difference
-between a normal label and the start of a functions). Therefore, the
-driver for most machines will have to take advantage of the idiosyncratic
-nature of compiler output.
-
-The included drivers both are based on the output from the Portable C
-Compiler (PCC). 68020.l was written for the Sun 3; it has been tested
-with SunOS 3.3 throught 3.5. vax.l is for Digital Vaxen; it has been
-tested on BSD 4.3 and Ultrix 2.0. I have not tried using either with
-(and assume they will break on) the output of the GNU C compiler, but I
-am sure it would not take long to port from a PCC version to a GNU
-version. It would be very difficult to port this code to work with a
-compiler that directly generates object code with no provision for
-creating assembler source. Sorry.
-
-My approach for writing a new driver is to start with one of the
-existing drivers included in this package and modify it appropriately.
-A good way to become familiar with one of these drivers is to examine
-some compiler output for a vax or a sun and compare it with the output
-of bb for that machine. Reasonable knowledge of the machine you are
-working on and it's function call/return protocol is useful if not
-necessary for porting the driver.
-
-The driver reads one file (a .s file generated by the compiler) and
-generates two (a .s file with block counting code and a .sL file which
-maps basic blocks to line numbers). The generated code, when executed,
-appends to a file called prof.out which contains a counter for each
-basic block. (The -r option to lcomp and lprint picks a name other
-than prof.out. Using an absolute path name can be extremely useful for
-profiling a program that is run from a public bin directory, so that
-users don't get a prof.out file every time they run the program, and
-the developer of the program can get useful profiling data.)
-
-The prof.out file is a series of entries of the form
- <.sL file> <n>
- <count for block 0>
- <count for block 1>
- .
- .
- .
- <count for block n-1>
-One such entry is written for each file compiled with lcomp.
-
-A .sL file has two parts. The first part is a set of n (obtained from
-prof.out) lines, one per basic block, each with four whitespace
-separated records, containing the sourcefile name (these should all be
-the same in any one .sL if one does not make too creative use of the C
-preprocessor), first line of the basic block, last line of the block,
-and number of instructions in the block. This section is followed by a
-line of the form "<m> functions", followed by m lines, one for each
-function in the compilation unit (source file). Each function line is
-the name of the function and its first basic block.
-
-The .l file must match instructions and generate code to do the
-instruction counting (and link a file's count table with the routine that
-prints counts), and write a .sL file. Start with the vax or 68020 code
-and modify it appropriately. The following functions are predefined
-(in bb.c) to handle common cases:
-
- passline() -- pass a line through unchanged
- inst() -- a normal instruction that does not use
- the condition codes and does alter them
- safe() -- an instruction that uses the condition codes
- or does not change them
- branch() -- a jump or branch (conditional or unconditional)
- unconditional subroutine call does not go here
- stabd() -- handle unix .stabd or .stabn lines
- stabs() -- handle unix .stabs lines
- function(s, n) -- declare that function named s starts at block n
- functionmap() -- write the function map for the end of the .sL file
-
-stabd() and stabs() read the .stab directives put out by the compiler for
-debugger information. They should work with both dbx and sdb style compiler
-output.
-
-The following functions must be provided by the driver:
-
- labelstartsblock(label) -- return a non-zero value if the named label
- could be the target of a branch. if there
- is a systematic way of telling that a label
- only exists for a debugger, this function
- should return false (zero) in that case.
- this feature is used in the sun version
- increment() -- increment a basic block counter. output
- at the beginning of a basic block.
- safeincrement() -- same as increment(), but does not change condition
- codes. this is normally possible on most machines,
- but can require tricky code.
- epilogue() -- takes one argument, the name of a map file,
- which must be linked with count information into
- the counting table. see bbexit.c. the structures
- are normally defined here.
-
-
-There's more to it than what I have described here, but the best way to
-figure it out is to try to write a driver for some machine. I'll be
-glad to answer questions on how to write a driver. I will also be
-willing to keep an archive of drivers that other people have written
-for other machines, if there is interest.
-
-paul haahr
-princeton!haahr [email protected]
end of INTERNALS
echo lcomp.1 1>&2
sed 's/^-//' > lcomp.1 <<'end of lcomp.1'
-.TH LCOMP 1 "15 April 1988"
-.SH NAME
-lcomp, lprint \- statement and instruction counting
-.SH SYNOPSIS
-.B lcomp
-[
-.B \-r
-.I prof.out
-file
-]
-[
-.B \-FC
-]
-.I cc
-or
-.I f77
-arguments ...
-.PP
-.B lprint
-[
-.B \-blaipfc
-]
-[
-.B \-r
-.I prof.out
-file
-] [ srcfile ] ...
-.SH DESCRIPTION
-.LP
-.I Lcomp
-compiles a C or \s-2FORTRAN\s0 program into an executable that produces
-instruction counts. \fILcomp\fP behaves similarly to
-.I cc
-and \fIf77\fP,
-and accepts the same arguments and options as those programs, except that:
-.TP
-.B \-C
-All named .c files are C++ programs and should be compiled with
-.I CC
-instead of
-.I cc .
-.TP
-.B \-F
-Link with \s-2FORTRAN\s0 libraries. Implied if a named .f file is included,
-but necessary if only object files are listed.
-.TP
-.BI \-r " file"
-Generate code that puts the output in the named file, rather than
-\fIprof.out\fP.
-.LP
-For each .c or .f file named, a .sL file is created, which maps
-basic blocks to line numbers. The source is compiled into a .o
-file which is instrumented for counting basic blocks.
-.LP
-In the executable file, the function \fI_bbdump\fP(), which is called
-automatically be \fIexit\fP(), writes the
-.I prof.out
-file. \fI_bbdump\fP() clears it's data structures, so it is safe to
-call from a signal handler (as long as it is safe to I/O from a signal
-handler on your machine). This is useful for gethering statistics on
-a program that is not supposed to exit.
-.LP
-.I Lprint
-analyzes the results of executing a program compiled with
-.I lcomp .
-The default behavior is to print an execution count in the left margin
-of each named file for the first basic block on that line.
-If no files are listed on the command line,
-all that were executed are printed.
-.SH OPTIONS
-.TP
-.B \-b
-Print counts for basic blocks (default, unless one of
-.B \-ipf
-is selected).
-.TP
-.B \-l
-Print counts for all lines, not just the first line of each basic block.
-.TP
-.B \-a
-Print all basic blocks, not just the first one from a line.
-.TP
-.B \-i
-Print instruction counts. If a basic block is not executed, the
-number of instructions in that block is printed in parentheses.
-.TP
-.B \-f
-Summarize by file. For instructions and basic blocks, the number executed,
-the total number in the file, and the number not executed are printed.
-.TP
-.B \-p
-Summarize by function. As \fB-f\fP, but the number of times each
-function is called is also printed.
-.TP
-.B \-c
-Compresses the
-.I prof.out
-file. The file grows every time the profile program is executed.
-.TP
-.BI \-r " file"
-Read counting data from the named file, instead of \fIprof.out\fP.
-.SH "EXAMPLES"
-.ta 2.0i
-.nf
-$ lcomp file.c # compile with counting code
-$ a.out # generate instruction counts
-$ lprint file.c # print statement counts for file.c
-.PP
-$ lcomp -o prog *.f # compile all fortran programs in directory
-$ prog ... # generate instruction counts
-$ lprint -fp # print summary information for all files
-.PP
-$ make "CC=lcomp" # tell make to use count generating compiler
-.fi
-.SH "SEE ALSO"
-cc(1), f77(1), prof(1), gprof(1), exit(2)
-.br
-tcov(1) in SunOS
-.PP
-Peter J. Weinberger, ``Cheap Dynamic Instruction Counting,''
-in \fIAT&T Bell Laboratories Technical Journal\fP,
-Volume 63, No. 8, October 1984.
-.SH FILES
-.PD 0
-.TP 1.5i
-.I file .sL
-mapping from basic blocks to lines and functions
-.TP
-.I prof.out
-default output file for counts
-.TP
-$LIB/bb
-assembly language post-processor to insert statement counts
-.TP
-$LIB/bbexit.o
-exit routine for statement counting
-.TP
-$LIB/bbfile.o
-contains name of file to dump to, normally
-.I prof.out
-.PD
-.SH BUGS
-.LP
-The analyzed program must call
-.I exit (2),
-either explictly or implictly by returning from
-\fImain\fP() for the coverage information to be written to the
-.I prof.out
-file.
-.LP
-The order that \fIlprint\fP prints files in if no names are
-mentioned on the command line is determinate but not too useful.
-.LP
-Profiling the kernel is possible, but some code must be written
-to grab the data out of kernel memory,
-rather than using \fI_bbdump\fP().
end of lcomp.1
echo lcomp 1>&2
sed 's/^-//' > lcomp <<'end of lcomp'
-#! /bin/sh
-
-LIB=$HOME/cs/596/lcomp
-PATH=$LIB:$PATH
-export PATH
-CC=cc
-
-CFILES=
-FFILES=
-SFILES=
-OFILES=
-RMFILES=
-
-LIBS=
-FLIBS=
-PROF=prof.out
-LINK=true
-EXEC=a.out
-FFLAGS='-u _MAIN_'
-FORTRAN='-lF77 -lI77 -lU77 -lm'
-
-while [ $# != 0 ]
-do
- case "$1" in
- *.c) CFILES="$CFILES $1" ;;
- *.[fF]) FFILES="$FFILES $1" ; FLIBS="$FORTRAN" ;;
- *.[sS]) SFILES="$SFILES $1" ;;
- *.o) OFILES="$OFILES $1" ;;
- -r) shift ; PROF=$1 ;;
- -C) CC=CC ;;
- -F) FLIBS="$FORTRAN" ;;
- -O) ;;
- -c) LINK=false ;;
- -o) shift ; EXEC=$1 ;;
- -l*|*.a)LIBS="$LIBS $1" ;;
- -*) FLAGS="$FLAGS $1" ;;
- esac
- shift
-done
-
-for i in $CFILES
-do
- file=`echo $i | sed 's/\.c$//'`
- $CC -g -S $FLAGS $file.c || exit $?
- bb $file.s || exit $?
- SFILES="$SFILES $file.s"
- RMFILES="$RMFILES $file.s"
-done
-
-for i in $FFILES
-do
- file=`echo $i | sed 's/\.[fF]$//'`
- f77 -g -S $FLAGS $i || exit $?
- bb $file.s || exit $?
- SFILES="$SFILES $file.s"
- RMFILES="$RMFILES $file.s"
-done
-
-for i in $SFILES
-do
- file=`echo $i | sed 's/\.[sS]$//'`
- $CC -c $FLAGS $i || exit $?
- OFILES="$OFILES $file.o"
-done
-
-if $LINK
-then
- if [ "$PROF" = prof.out ]
- then
- OFILES="$OFILES $LIB/bbfile.o"
- else
- echo "char *_bbfile = \"$PROF\";" > $$bbfile.c
- $CC -c $$bbfile.c
- OFILES="$OFILES $$bbfile.o"
- RMFILES="$RMFILES $$bbfile.c $$bbfile.o"
- fi
-
- if [ "$FLIBS" != "" ]
- then
- FLAGS="$FLAGS $FFLAGS"
- fi
- $CC -o $EXEC $FLAGS $OFILES $LIB/bbexit.o $LIBS $FLIBS || exit $?
-fi
-rm -f $RMFILES
end of lcomp
chmod +x lcomp
echo bbexit.c 1>&2
sed 's/^-//' > bbexit.c <<'end of bbexit.c'
-/* bbexit.c -- exit routine for basic block counting */
-
-#include <stdio.h>
-
-typedef struct Entry Entry;
-struct Entry {
- Entry *next;
- int len, *counts;
- char *mapfile;
-};
-
-Entry *_bblist = NULL;
-extern char *_bbfile;
-
-extern char *malloc();
-
-_bbdump()
-{
- Entry *e;
- FILE *fp = fopen(_bbfile, "a");
- if (fp == NULL) {
- fprintf(stderr, "couldn't open %s\n", _bbfile);
- return;
- }
- for (e = _bblist; e != NULL; e = e->next) {
- int i;
- fprintf(fp, "%s %d\n", e->mapfile, e->len);
- for (i = 0; i < e->len; i++) {
- fprintf(fp, "%d\n", e->counts[i]);
- e->counts[i] = 0;
- }
- }
- fclose(fp);
-}
-
-exit(status)
- int status;
-{
- _bbdump();
- _cleanup();
- _exit(status);
-}
end of bbexit.c
echo bbfile.c 1>&2
sed 's/^-//' > bbfile.c <<'end of bbfile.c'
-char *_bbfile = "prof.out";
end of bbfile.c
echo bb.h 1>&2
sed 's/^-//' > bb.h <<'end of bb.h'
-/* bb.h -- basic block counting definitions */
-
-#define WORDSIZE 256
-#define NOPRINT -1000
-
-#define streq(s, t) (strcmp((s), (t)) == 0)
-#define atoi(s) strtol((s), (char *) NULL, 0)
-
-
-extern FILE *out; /* generated .s file */
-extern FILE *map; /* generated .sL file */
-
-extern int lineno; /* original source line number */
-extern char filename[]; /* original source filename */
-
-extern char *yystring; /* input to lex */
-extern char *tail; /* tail of line (everything after opcode) */
-extern char line[]; /* input line */
-extern char label[]; /* most recent label */
-
-extern bool text; /* in text segment? */
-extern bool newblock; /* started new basic block? */
-extern int block; /* current basic block number */
-extern int instructions; /* counter of instructions */
-extern int reached; /* last line reached in basic block */
-
-
-extern void inst(); /* normal instruction */
-extern void safe(); /* instruction that uses condition codes */
-extern void branch(); /* any flow of control */
-extern void stabd(), stabs(); /* debugger symbol table */
-extern void passline(); /* no-op */
-
-
-extern bool labelstartsblock(); /* supplied in $TARGET.l */
-
-
-#ifdef YYLERR /* lex */
-
-#undef output
-#undef input
-#undef unput
-
-#define input() (*yystring == '\0' ? 0 : *yystring++)
-#define unput(c) (*--yystring = (c))
-#define output(c) (c) /* force evaluation */
-
-#endif
end of bb.h
echo new.h 1>&2
sed 's/^-//' > new.h <<'end of new.h'
-/* new.h -- dynamic memory allocation */
-
-extern char *malloc(), *ealloc(), *realloc(), *erealloc(), *strdup();
-extern int free();
-extern void panic();
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#define new(t, n) ((t *) ealloc((n) * sizeof (t)))
-#define renew(t, p, n) (((p) == NULL) \
- ? new(t, n) \
- : ((t *) erealloc((char *) (p), (n) * sizeof (t))))
-#define delete(p) (((p) == NULL) ? 0 : free(p))
end of new.h
echo bool.h 1>&2
sed 's/^-//' > bool.h <<'end of bool.h'
-/* bool.h -- boolean type */
-
-typedef int bool;
-#define FALSE 0
-#define TRUE 1
-
-#define strbool(t) ((t) ? "TRUE" : "FALSE")
end of bool.h
echo bb.c 1>&2
sed 's/^-//' > bb.c <<'end of bb.c'
-/* bb.c -- insert basic block counting code */
-
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include "new.h"
-#include "bool.h"
-#include "bb.h"
-
-extern FILE *efopen();
-extern char *memcpy();
-
-char *progname = "bb";
-
-static void usage()
-{
- fprintf(stderr, "usage: %s file.s ...\n", progname);
- exit(1);
-}
-
-
-/* globals shared with $TARGET.l */
-
-FILE *out = NULL; /* generated .s file */
-FILE *map = NULL; /* generated .sL file */
-
-int lineno = 0; /* original source line number */
-char filename[WORDSIZE]; /* original source filename */
-
-char *yystring; /* input to lex */
-char *tail; /* tail of line (everything after opcode) */
-char line[BUFSIZ]; /* input line */
-char label[WORDSIZE]; /* most recent label */
-
-bool text = TRUE; /* in text segment? */
-bool newblock = TRUE; /* started new basic block? */
-int block = 0; /* current basic block number */
-int instructions = NOPRINT; /* counter of instructions */
-int reached = 0; /* last line reached in basic block */
-
-
-/* associate functions with basic blocks*/
-
-#define MAXFUNC 1000
-int nfunc;
-struct {
- char *name;
- int bb;
-} func[MAXFUNC];
-
-function(s, bb)
- char *s;
- int bb;
-{
- if (nfunc >= MAXFUNC)
- panic("too many functions (>%d), on %s\n", MAXFUNC, s);
- func[nfunc].name = strdup(s);
- func[nfunc].bb = bb;
- nfunc++;
-}
-
-functionmap()
-{
- int i;
- fprintf(map, "%d functions\n", nfunc);
- for (i = 0; i < nfunc; i++) {
- fprintf(map, "%s %d\n", func[i].name, func[i].bb);
- free(func[i].name);
- func[i].name = NULL;
- }
- nfunc = 0;
-}
-
-
-/* parse file, pass to yylex from $TARGET.l */
-void bb(infile)
- char *infile;
-{
- char outfile[BUFSIZ], mapfile[BUFSIZ];
- static char pid[10] = "";
- FILE *in;
-
- in = efopen(infile, "r");
-
- strcpy(mapfile, infile);
- strcat(mapfile, "L");
- map = efopen(mapfile, "w");
-
- if (pid[0] == '\0')
- sprintf(pid, ".%d", getpid());
- strcpy(outfile, infile);
- strcat(outfile, pid);
- out = efopen(outfile, "w");
-
- lineno = 0;
- filename[0] = '\0';
-
- while (fgets(line, sizeof line, in) != NULL) {
- char *s = line, opcode[WORDSIZE];
- int i;
-startofline:
- for (; isspace(*s); s++)
- ;
- if (*s == '\0') {
- fputs(line, out);
- continue;
- }
- for (i = 0; isgraph(s[i]); i++)
- if (s[i] == ':') {
- if (text) {
- memcpy(label, s, i);
- label[i] = '\0';
- if (labelstartsblock(label))
- newblock = TRUE;
- }
- s += i + 1;
- goto startofline;
- }
- tail = s + i;
- memcpy(opcode, s, i);
- opcode[i] = '\n';
- opcode[i + 1] = '\0';
- yystring = opcode;
- yylex();
- }
-
- epilogue(mapfile);
- functionmap();
-
- fclose(in);
- fclose(out);
- fclose(map);
- map = out = NULL;
-
- if (unlink(infile) == -1)
- panic("couldn't unlink %s -- output in %s\n", infile, outfile);
- if (rename(outfile, infile) == -1)
- panic("couldn't rename %s to %s\n", outfile, infile);
-}
-
-int main(argc, argv)
- int argc;
- char *argv[];
-{
- progname = argv[0];
- if (argc == 1)
- usage();
- for (--argc, ++argv; argc != 0; --argc, ++argv)
- bb(*argv);
- return 0;
-}
-
-/* functions for use in $TARGET.l -- common to most machines */
-
-void passline()
-{
- fputs(line, out);
-}
-
-void inst()
-{
- if (text) {
- if (newblock)
- increment();
- reached = lineno;
- instructions++;
- }
- passline();
-}
-
-void safe()
-{
- if (text) {
- if (newblock)
- safeincrement();
- reached = lineno;
- instructions++;
- }
- passline();
-}
-
-void branch()
-{
- if (text) {
- if (newblock)
- safeincrement();
- reached = lineno;
- instructions++;
- newblock = TRUE;
- }
- passline();
-}
-
-#define STAB_LINE 0104 /* N_SLINE from <stab.h> */
-#define STAB_FILE 0144 /* N_SO from <stab.h> */
-
-void stabd()
-{
- char *s;
- passline();
- if (atoi(tail) != STAB_LINE)
- return;
- if ((s = strchr(line, ',')) == NULL || (s = strchr(s + 1, ',')) == NULL)
- panic("bad directive: .stabn%s", tail);
- lineno = atoi(s + 1);
-}
-
-void stabs()
-{
- char *s, *t;
- int len;
- passline();
- if ((s = strchr(tail, ',')) == NULL)
- panic("bad directive: .stabs%s", tail);
- if (atoi(s + 1) != STAB_FILE)
- return;
- if ((s = strchr(tail, '"')) == NULL || (t = strchr(s + 1, '"')) == NULL)
- panic("bad directive: .stabs%s", tail);
- len = t - s - 1;
- memcpy(filename, s + 1, len);
- filename[len] = '\0';
-}
end of bb.c
echo lprint.c 1>&2
sed 's/^-//' > lprint.c <<'end of lprint.c'
-/* lprint.c -- print out statement counts */
-
-#include <stdio.h>
-#include <string.h>
-#include "bool.h"
-#include "new.h"
-
-#define streq(s, t) (strcmp((s), (t)) == 0)
-
-extern FILE *efopen();
-
-char *progname = "lprint";
-
-void usage()
-{
- fprintf(stderr, "usage: %s [-blaipf] [-c] [-r file] [file ...]\n", progname);
- fprintf(stderr, " -b print basic block counts (default)\n");
- fprintf(stderr, " -l print counts for all lines\n");
- fprintf(stderr, " -a print all basic blocks\n");
- fprintf(stderr, " -i print instruction counts\n");
- fprintf(stderr, " -p print function summaries\n");
- fprintf(stderr, " -f print file summaries\n");
- fprintf(stderr, " -c compress prof.out file\n");
- fprintf(stderr, " -r select alternate prof.out file\n");
- exit(1);
-}
-
-int flags = 0;
-
-#define BLOCKS 0x01
-#define LINES 0x02
-#define ALL 0x04
-#define INST 0x08
-#define FILESUM 0x10
-#define FUNCSUM 0x20
-
-#define DEFAULT BLOCKS
-
-typedef struct Mapfile Mapfile;
-typedef struct Mapblock Mapblock;
-typedef struct Sourcefile Sourcefile;
-typedef struct Block Block;
-typedef struct Func Func;
-
-struct Mapfile {
- char *name;
- int n, nfunc;