1#include <stdio.h>
2#include <unistd.h>
3#include <stdlib.h>
4#include <string.h>
5#include <inttypes.h>
6#include "trace_reader.h"
7#include "parse_options.h"
8
9const int kMillion = 1000000;
10const int kMHz = 200 * kMillion;
11
12struct symbol {
13    int         count;      // number of times a function is executed
14    uint64_t    elapsed;    // elapsed time for this function
15};
16
17typedef TraceReader<symbol> TraceReaderType;
18
19#include "parse_options-inl.h"
20
21static const uint32_t kOffsetThreshold = 0x100000;
22
23// This comparison function is called from qsort() to sort
24// symbols into decreasing elapsed time.
25int cmp_sym_elapsed(const void *a, const void *b) {
26    const symbol_type *syma, *symb;
27    uint64_t elapsed1, elapsed2;
28
29    syma = static_cast<symbol_type const *>(a);
30    symb = static_cast<symbol_type const *>(b);
31    elapsed1 = syma->elapsed;
32    elapsed2 = symb->elapsed;
33    if (elapsed1 < elapsed2)
34        return 1;
35    if (elapsed1 == elapsed2)
36        return strcmp(syma->name, symb->name);
37    return -1;
38}
39
40void Usage(const char *program)
41{
42    fprintf(stderr, "Usage: %s [options] trace_file elf_file\n", program);
43    OptionsUsage();
44}
45
46int main(int argc, char **argv)
47{
48    ParseOptions(argc, argv);
49    if (argc - optind != 2) {
50        Usage(argv[0]);
51        exit(1);
52    }
53
54    char *trace_filename = argv[optind++];
55    char *elf_file = argv[optind++];
56    TraceReader<symbol> *trace = new TraceReader<symbol>;
57    trace->Open(trace_filename);
58    trace->SetDemangle(demangle);
59    trace->ReadKernelSymbols(elf_file);
60    trace->SetRoot(root);
61
62    symbol_type dummy;
63    dummy.count = 0;
64    dummy.elapsed = 0;
65    symbol_type *prev_sym = &dummy;
66    uint64_t prev_bb_time = 0;
67    while (1) {
68        symbol_type *sym;
69        BBEvent event;
70        BBEvent first_ignored_event;
71
72        bool eof = GetNextValidEvent(trace, &event, &first_ignored_event, &sym);
73
74        // Assign the elapsed time to the previous function symbol
75        uint64_t elapsed = 0;
76        if (first_ignored_event.time != 0)
77            elapsed = first_ignored_event.time - prev_bb_time;
78        else if (!eof)
79            elapsed = event.time - prev_bb_time;
80        prev_sym->elapsed += elapsed;
81
82        if (eof)
83            break;
84
85        prev_bb_time = event.time;
86        sym->count += 1;
87        prev_sym = sym;
88#if 0
89        printf("t%lld bb_num: %d, bb_addr: 0x%x func: %s, addr: 0x%x, count: %d\n",
90               bb_time, bb_num, bb_addr, sym->name, sym->addr, sym->count);
91#endif
92    }
93
94    int nsyms;
95    symbol_type *syms = trace->GetSymbols(&nsyms);
96
97    // Sort the symbols into decreasing order of elapsed time
98    qsort(syms, nsyms, sizeof(symbol_type), cmp_sym_elapsed);
99
100    // Add up all the cycles
101    uint64_t total = 0;
102    symbol_type *sym = syms;
103    for (int ii = 0; ii < nsyms; ++ii, ++sym) {
104        total += sym->elapsed;
105    }
106
107    double secs = 1.0 * total / kMHz;
108    printf("Total seconds: %.2f, total cycles: %lld, MHz: %d\n\n",
109           secs, total, kMHz / kMillion);
110
111    uint64_t sum = 0;
112    printf("Elapsed secs Elapsed cyc      %%      %%    Function\n");
113    sym = syms;
114    for (int ii = 0; ii < nsyms; ++ii, ++sym) {
115        if (sym->elapsed == 0)
116            break;
117        sum += sym->elapsed;
118        double per = 100.0 * sym->elapsed / total;
119        double sum_per = 100.0 * sum / total;
120        double secs = 1.0 * sym->elapsed / kMHz;
121        const char *ksym = " ";
122        if (sym->region->flags & region_type::kIsKernelRegion)
123            ksym = "k";
124        printf("%12.2f %11lld %6.2f %6.2f  %s %s\n",
125               secs, sym->elapsed, per, sum_per, ksym, sym->name);
126    }
127    delete[] syms;
128    delete trace;
129
130    return 0;
131}
132