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#include "opcode.h"
9
10const int kMillion = 1000000;
11const int kMHz = 200 * kMillion;
12
13struct symbol {
14    int    numCalls;    // number of times this function is called
15};
16
17typedef TraceReader<symbol> TraceReaderType;
18
19#include "parse_options-inl.h"
20#include "callstack.h"
21
22class MyFrame : public StackFrame<symbol_type> {
23  public:
24    void    push(int stackLevel, uint64_t time, CallStackBase *base) {
25        function->numCalls += 1;
26    }
27    void    pop(int stackLevel, uint64_t time, CallStackBase *base) {
28    }
29};
30
31typedef CallStack<MyFrame> CallStackType;
32
33static const int kNumStackFrames = 500;
34static const int kMaxThreads = (32 * 1024);
35CallStackType *stacks[kMaxThreads];
36
37// This comparison function is called from qsort() to sort symbols
38// into decreasing number of calls.
39int cmp_sym_calls(const void *a, const void *b) {
40    const symbol_type *syma, *symb;
41    uint64_t calls1, calls2;
42
43    syma = static_cast<symbol_type const *>(a);
44    symb = static_cast<symbol_type const *>(b);
45    calls1 = syma->numCalls;
46    calls2 = symb->numCalls;
47    if (calls1 < calls2)
48        return 1;
49    if (calls1 == calls2) {
50        int cmp = strcmp(syma->name, symb->name);
51        if (cmp == 0)
52            cmp = strcmp(syma->region->path, symb->region->path);
53        return cmp;
54    }
55    return -1;
56}
57
58// This comparison function is called from qsort() to sort symbols
59// into alphabetical order.
60int cmp_sym_names(const void *a, const void *b) {
61    const symbol_type *syma, *symb;
62
63    syma = static_cast<symbol_type const *>(a);
64    symb = static_cast<symbol_type const *>(b);
65    int cmp = strcmp(syma->region->path, symb->region->path);
66    if (cmp == 0)
67        cmp = strcmp(syma->name, symb->name);
68    return cmp;
69}
70
71void Usage(const char *program)
72{
73    fprintf(stderr, "Usage: %s [options] trace_file elf_file\n", program);
74    OptionsUsage();
75}
76
77int main(int argc, char **argv)
78{
79    ParseOptions(argc, argv);
80    if (argc - optind != 2) {
81        Usage(argv[0]);
82        exit(1);
83    }
84
85    char *trace_filename = argv[optind++];
86    char *elf_file = argv[optind++];
87    TraceReader<symbol> *trace = new TraceReader<symbol>;
88    trace->Open(trace_filename);
89    trace->SetDemangle(demangle);
90    trace->ReadKernelSymbols(elf_file);
91    trace->SetRoot(root);
92
93    BBEvent event;
94    while (1) {
95        BBEvent ignored;
96        symbol_type *function;
97
98        if (GetNextValidEvent(trace, &event, &ignored, &function))
99            break;
100        if (event.bb_num == 0)
101            break;
102
103        // Get the stack for the current thread
104        CallStackType *pStack = stacks[event.pid];
105
106        // If the stack does not exist, then allocate a new one.
107        if (pStack == NULL) {
108            pStack = new CallStackType(event.pid, kNumStackFrames, trace);
109            stacks[event.pid] = pStack;
110        }
111
112        // Update the stack
113        pStack->updateStack(&event, function);
114    }
115
116    for (int ii = 0; ii < kMaxThreads; ++ii) {
117        if (stacks[ii])
118            stacks[ii]->popAll(event.time);
119    }
120
121    int nsyms;
122    symbol_type *syms = trace->GetSymbols(&nsyms);
123
124    // Sort the symbols into decreasing number of calls
125    qsort(syms, nsyms, sizeof(symbol_type), cmp_sym_names);
126
127    symbol_type *psym = syms;
128    for (int ii = 0; ii < nsyms; ++ii, ++psym) {
129        // Ignore functions with non-zero calls
130        if (psym->numCalls)
131            continue;
132
133        // Ignore some symbols
134        if (strcmp(psym->name, "(end)") == 0)
135            continue;
136        if (strcmp(psym->name, "(unknown)") == 0)
137            continue;
138        if (strcmp(psym->name, ".plt") == 0)
139            continue;
140        const char *ksym = " ";
141        if (psym->region->flags & region_type::kIsKernelRegion)
142            ksym = "k";
143        printf("%s %s %s\n", ksym, psym->name, psym->region->path);
144#if 0
145        printf("#%d %5d %s %s %s\n", ii + 1, psym->numCalls, ksym, psym->name,
146               psym->region->path);
147#endif
148    }
149    delete[] syms;
150    delete trace;
151
152    return 0;
153}
154