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. 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. 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. 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 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. 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