Home | History | Annotate | Download | only in qtools
      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