1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <inttypes.h>
5 #include "trace_reader.h"
6 #include "armdis.h"
7
8 struct MyStaticRec {
9 StaticRec bb;
10 uint32_t *insns;
11 uint32_t *cycles; // number of cycles for each insn
12 uint32_t elapsed; // number of cycles for basic block
13 int freq; // execution frequency
14 MyStaticRec *inner; // pointer to an inner basic block
15 int is_thumb;
16 };
17
18 MyStaticRec **assign_inner_blocks(int num_blocks, MyStaticRec *blocks);
19
20 // This function is called from quicksort to compare addresses of basic
21 // blocks.
cmp_inc_addr(const void * a,const void * b)22 int cmp_inc_addr(const void *a, const void *b) {
23 MyStaticRec *bb1, *bb2;
24
25 bb1 = *(MyStaticRec**)a;
26 bb2 = *(MyStaticRec**)b;
27 if (bb1->bb.bb_addr < bb2->bb.bb_addr)
28 return -1;
29 if (bb1->bb.bb_addr > bb2->bb.bb_addr)
30 return 1;
31 return bb1->bb.bb_num - bb2->bb.bb_num;
32 }
33
34 // This function is called from quicksort to compare the elapsed time
35 // of basic blocks.
cmp_dec_elapsed(const void * a,const void * b)36 int cmp_dec_elapsed(const void *a, const void *b) {
37 MyStaticRec *bb1, *bb2;
38
39 bb1 = *(MyStaticRec**)a;
40 bb2 = *(MyStaticRec**)b;
41 if (bb1->elapsed < bb2->elapsed)
42 return 1;
43 if (bb1->elapsed > bb2->elapsed)
44 return -1;
45 return bb1->bb.bb_num - bb2->bb.bb_num;
46 }
47
48 // This function is called from quicksort to compare frequencies of
49 // basic blocks.
cmp_dec_freq(const void * a,const void * b)50 int cmp_dec_freq(const void *a, const void *b) {
51 MyStaticRec *bb1, *bb2;
52
53 bb1 = *(MyStaticRec**)a;
54 bb2 = *(MyStaticRec**)b;
55 if (bb1->freq < bb2->freq)
56 return 1;
57 if (bb1->freq > bb2->freq)
58 return -1;
59 return bb1->bb.bb_num - bb2->bb.bb_num;
60 }
61
main(int argc,char ** argv)62 int main(int argc, char **argv)
63 {
64 if (argc != 2) {
65 fprintf(stderr, "Usage: %s trace_file\n", argv[0]);
66 exit(1);
67 }
68
69 char *trace_filename = argv[1];
70 TraceReaderBase *trace = new TraceReaderBase;
71 trace->Open(trace_filename);
72 TraceHeader *header = trace->GetHeader();
73 uint32_t num_static_bb = header->num_static_bb;
74
75 // Allocate space for all of the static blocks
76 MyStaticRec *blocks = new MyStaticRec[num_static_bb];
77
78 // Read in all the static blocks
79 for (uint32_t ii = 0; ii < num_static_bb; ++ii) {
80 trace->ReadStatic(&blocks[ii].bb);
81 blocks[ii].is_thumb = blocks[ii].bb.bb_addr & 1;
82 blocks[ii].bb.bb_addr &= ~1;
83 uint32_t num_insns = blocks[ii].bb.num_insns;
84 blocks[ii].insns = new uint32_t[num_insns];
85 blocks[ii].cycles = new uint32_t[num_insns];
86 memset(blocks[ii].cycles, 0, num_insns * sizeof(uint32_t));
87 trace->ReadStaticInsns(num_insns, blocks[ii].insns);
88 blocks[ii].elapsed = 0;
89 blocks[ii].freq = 0;
90 blocks[ii].inner = NULL;
91 }
92
93 MyStaticRec **sorted = assign_inner_blocks(num_static_bb, blocks);
94
95 uint32_t prev_time = 0;
96 uint32_t elapsed = 0;
97 uint32_t dummy;
98 uint32_t *cycle_ptr = &dummy;
99 uint32_t *bb_elapsed_ptr = &dummy;
100 while (1) {
101 BBEvent event;
102
103 if (trace->ReadBB(&event))
104 break;
105 // Assign frequencies to each basic block
106 uint64_t bb_num = event.bb_num;
107 int num_insns = event.num_insns;
108 blocks[bb_num].freq += 1;
109 for (MyStaticRec *bptr = blocks[bb_num].inner; bptr; bptr = bptr->inner)
110 bptr->freq += 1;
111
112 // Assign simulation time to each instruction
113 for (MyStaticRec *bptr = &blocks[bb_num]; bptr; bptr = bptr->inner) {
114 uint32_t bb_num_insns = bptr->bb.num_insns;
115 for (uint32_t ii = 0; num_insns && ii < bb_num_insns; ++ii, --num_insns) {
116 uint32_t sim_time = trace->ReadInsnTime(event.time);
117 elapsed = sim_time - prev_time;
118 prev_time = sim_time;
119
120 // Attribute the elapsed time to the previous instruction and
121 // basic block.
122 *cycle_ptr += elapsed;
123 *bb_elapsed_ptr += elapsed;
124 cycle_ptr = &bptr->cycles[ii];
125 bb_elapsed_ptr = &bptr->elapsed;
126 }
127 }
128 }
129 *cycle_ptr += 1;
130 *bb_elapsed_ptr += 1;
131
132 // Sort the basic blocks into decreasing elapsed time
133 qsort(sorted, num_static_bb, sizeof(MyStaticRec*), cmp_dec_elapsed);
134
135 char spaces[80];
136 memset(spaces, ' ', 79);
137 spaces[79] = 0;
138 for (uint32_t ii = 0; ii < num_static_bb; ++ii) {
139 printf("bb %lld addr: 0x%x, insns: %d freq: %u elapsed: %u\n",
140 sorted[ii]->bb.bb_num, sorted[ii]->bb.bb_addr,
141 sorted[ii]->bb.num_insns, sorted[ii]->freq,
142 sorted[ii]->elapsed);
143 int num_insns = sorted[ii]->bb.num_insns;
144 uint32_t addr = sorted[ii]->bb.bb_addr;
145 for (int jj = 0; jj < num_insns; ++jj) {
146 uint32_t elapsed = sorted[ii]->cycles[jj];
147 uint32_t insn = sorted[ii]->insns[jj];
148 if (insn_is_thumb(insn)) {
149 insn = insn_unwrap_thumb(insn);
150
151 // thumb_pair is true if this is the first of a pair of
152 // thumb instructions (BL or BLX).
153 bool thumb_pair = ((insn & 0xf800) == 0xf000);
154
155 // Get the next thumb instruction (if any) because we may need
156 // it for the case where insn is BL or BLX.
157 uint32_t insn2 = 0;
158 if (thumb_pair && (jj + 1 < num_insns)) {
159 insn2 = sorted[ii]->insns[jj + 1];
160 insn2 = insn_unwrap_thumb(insn2);
161 jj += 1;
162 }
163 char *disasm = disasm_insn_thumb(addr, insn, insn2, NULL);
164 if (thumb_pair) {
165 printf(" %4u %08x %04x %04x %s\n", elapsed, addr, insn,
166 insn2, disasm);
167 addr += 2;
168 } else {
169 printf(" %4u %08x %04x %s\n", elapsed, addr, insn,
170 disasm);
171 }
172 addr += 2;
173 } else {
174 char *disasm = Arm::disasm(addr, insn, NULL);
175 printf(" %4u %08x %08x %s\n", elapsed, addr, insn, disasm);
176 addr += 4;
177 }
178 }
179 }
180
181 delete[] sorted;
182 return 0;
183 }
184
185 // Find the basic blocks that are subsets of other basic blocks.
assign_inner_blocks(int num_blocks,MyStaticRec * blocks)186 MyStaticRec **assign_inner_blocks(int num_blocks, MyStaticRec *blocks)
187 {
188 int ii;
189 uint32_t addr_end, addr_diff;
190
191 // Create a list of pointers to the basic blocks that we can sort.
192 MyStaticRec **sorted = new MyStaticRec*[num_blocks];
193 for (ii = 0; ii < num_blocks; ++ii) {
194 sorted[ii] = &blocks[ii];
195 }
196
197 // Sort the basic blocks into increasing address order
198 qsort(sorted, num_blocks, sizeof(MyStaticRec*), cmp_inc_addr);
199
200 // Create pointers to inner blocks and break up the enclosing block
201 // so that there is no overlap.
202 for (ii = 0; ii < num_blocks - 1; ++ii) {
203 int num_bytes;
204 if (sorted[ii]->is_thumb)
205 num_bytes = sorted[ii]->bb.num_insns << 1;
206 else
207 num_bytes = sorted[ii]->bb.num_insns << 2;
208 addr_end = sorted[ii]->bb.bb_addr + num_bytes;
209 if (addr_end > sorted[ii + 1]->bb.bb_addr) {
210 sorted[ii]->inner = sorted[ii + 1];
211 addr_diff = sorted[ii + 1]->bb.bb_addr - sorted[ii]->bb.bb_addr;
212 uint32_t num_insns;
213 if (sorted[ii]->is_thumb)
214 num_insns = addr_diff >> 1;
215 else
216 num_insns = addr_diff >> 2;
217 sorted[ii]->bb.num_insns = num_insns;
218 }
219 }
220
221 return sorted;
222 }
223