155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project#include <stdio.h>
255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project#include <unistd.h>
355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project#include <stdlib.h>
455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project#include <string.h>
555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project#include <inttypes.h>
655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project#include "trace_reader.h"
755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project#include "parse_options.h"
855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectconst int kMillion = 1000000;
1055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectconst int kMHz = 200 * kMillion;
1155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
1255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectstruct symbol {
1355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    int         count;      // number of times a function is executed
1455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    uint64_t    elapsed;    // elapsed time for this function
1555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project};
1655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
1755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projecttypedef TraceReader<symbol> TraceReaderType;
1855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
1955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project#include "parse_options-inl.h"
2055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
2155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectstatic const uint32_t kOffsetThreshold = 0x100000;
2255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
2355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project// This comparison function is called from qsort() to sort
2455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project// symbols into decreasing elapsed time.
2555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectint cmp_sym_elapsed(const void *a, const void *b) {
2655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    const symbol_type *syma, *symb;
2755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    uint64_t elapsed1, elapsed2;
2855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
2955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    syma = static_cast<symbol_type const *>(a);
3055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    symb = static_cast<symbol_type const *>(b);
3155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    elapsed1 = syma->elapsed;
3255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    elapsed2 = symb->elapsed;
3355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    if (elapsed1 < elapsed2)
3455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        return 1;
3555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    if (elapsed1 == elapsed2)
3655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        return strcmp(syma->name, symb->name);
3755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    return -1;
3855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project}
3955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
4055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectvoid Usage(const char *program)
4155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project{
4255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    fprintf(stderr, "Usage: %s [options] trace_file elf_file\n", program);
4355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    OptionsUsage();
4455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project}
4555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
4655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Projectint main(int argc, char **argv)
4755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project{
4855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    ParseOptions(argc, argv);
4955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    if (argc - optind != 2) {
5055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        Usage(argv[0]);
5155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        exit(1);
5255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    }
5355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
5455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    char *trace_filename = argv[optind++];
5555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    char *elf_file = argv[optind++];
5655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    TraceReader<symbol> *trace = new TraceReader<symbol>;
5755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    trace->Open(trace_filename);
5855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    trace->SetDemangle(demangle);
5955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    trace->ReadKernelSymbols(elf_file);
6055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    trace->SetRoot(root);
6155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
6255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    symbol_type dummy;
6355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    dummy.count = 0;
6455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    dummy.elapsed = 0;
6555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    symbol_type *prev_sym = &dummy;
6655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    uint64_t prev_bb_time = 0;
6755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    while (1) {
6855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        symbol_type *sym;
6955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        BBEvent event;
7055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        BBEvent first_ignored_event;
7155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
7255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        bool eof = GetNextValidEvent(trace, &event, &first_ignored_event, &sym);
7355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
7455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        // Assign the elapsed time to the previous function symbol
7555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        uint64_t elapsed = 0;
7655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        if (first_ignored_event.time != 0)
7755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            elapsed = first_ignored_event.time - prev_bb_time;
7855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        else if (!eof)
7955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            elapsed = event.time - prev_bb_time;
8055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        prev_sym->elapsed += elapsed;
8155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
8255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        if (eof)
8355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            break;
8455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
8555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        prev_bb_time = event.time;
8655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        sym->count += 1;
8755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        prev_sym = sym;
8855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project#if 0
8955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        printf("t%lld bb_num: %d, bb_addr: 0x%x func: %s, addr: 0x%x, count: %d\n",
9055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project               bb_time, bb_num, bb_addr, sym->name, sym->addr, sym->count);
9155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project#endif
9255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    }
9355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
9455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    int nsyms;
9555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    symbol_type *syms = trace->GetSymbols(&nsyms);
9655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
9755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    // Sort the symbols into decreasing order of elapsed time
9855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    qsort(syms, nsyms, sizeof(symbol_type), cmp_sym_elapsed);
9955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
10055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    // Add up all the cycles
10155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    uint64_t total = 0;
10255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    symbol_type *sym = syms;
10355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    for (int ii = 0; ii < nsyms; ++ii, ++sym) {
10455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        total += sym->elapsed;
10555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    }
10655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
10755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    double secs = 1.0 * total / kMHz;
10855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    printf("Total seconds: %.2f, total cycles: %lld, MHz: %d\n\n",
10955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project           secs, total, kMHz / kMillion);
11055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
11155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    uint64_t sum = 0;
11255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    printf("Elapsed secs Elapsed cyc      %%      %%    Function\n");
11355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    sym = syms;
11455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    for (int ii = 0; ii < nsyms; ++ii, ++sym) {
11555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        if (sym->elapsed == 0)
11655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            break;
11755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        sum += sym->elapsed;
11855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        double per = 100.0 * sym->elapsed / total;
11955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        double sum_per = 100.0 * sum / total;
12055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        double secs = 1.0 * sym->elapsed / kMHz;
121d4d5b4f63a5760b2212166f539f906edda0bc4deJack Veenstra        const char *ksym = " ";
12255a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        if (sym->region->flags & region_type::kIsKernelRegion)
12355a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project            ksym = "k";
12455a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project        printf("%12.2f %11lld %6.2f %6.2f  %s %s\n",
12555a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project               secs, sym->elapsed, per, sum_per, ksym, sym->name);
12655a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    }
12755a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    delete[] syms;
12855a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    delete trace;
12955a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project
13055a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project    return 0;
13155a2c71f27d3e0b8344597c7f281e687cb7aeb1bThe Android Open Source Project}
132