10ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
20ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Copyright (C) 2015 The Android Open Source Project
30ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao *
40ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Licensed under the Apache License, Version 2.0 (the "License");
50ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * you may not use this file except in compliance with the License.
60ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * You may obtain a copy of the License at
70ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao *
80ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao *      http://www.apache.org/licenses/LICENSE-2.0
90ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao *
100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Unless required by applicable law or agreed to in writing, software
110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * distributed under the License is distributed on an "AS IS" BASIS,
120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * See the License for the specific language governing permissions and
140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * limitations under the License.
150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Process dmtrace output.
190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao *
200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * This is the wrong way to go about it -- C is a clumsy language for
210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * shuffling data around.  It'll do for a first pass.
220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#include "profile.h"  // from VM header
240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#include <assert.h>
260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#include <errno.h>
270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#include <inttypes.h>
280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#include <stdint.h>
290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#include <stdio.h>
300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#include <stdlib.h>
310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#include <string.h>
320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#include <time.h>
330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#include <unistd.h>
340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/* Version number in the key file.
360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Version 1 uses one byte for the thread id.
370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Version 2 uses two bytes for the thread ids.
380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Version 3 encodes the record size and adds an optional extra timestamp field.
390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t versionNumber;
410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/* arbitrarily limit indentation */
430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#define MAX_STACK_DEPTH 10000
440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/* thread list in key file is not reliable, so just max out */
460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#define MAX_THREADS 32768
470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/* Size of temporary buffers for escaping html strings */
490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#define HTML_BUFSIZE 10240
500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoconst char* htmlHeader =
520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<html>\n<head>\n<script type=\"text/javascript\" "
530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "src=\"%ssortable.js\"></script>\n"
540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<script langugage=\"javascript\">\n"
550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "function toggle(item) {\n"
560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "    obj=document.getElementById(item);\n"
570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "    visible=(obj.style.display!=\"none\" && obj.style.display!=\"\");\n"
580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "    key=document.getElementById(\"x\" + item);\n"
590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "    if (visible) {\n"
600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "        obj.style.display=\"none\";\n"
610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "        key.innerHTML=\"+\";\n"
620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "    } else {\n"
630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "        obj.style.display=\"block\";\n"
640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "        key.innerHTML=\"-\";\n"
650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "    }\n"
660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "}\n"
670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "function onMouseOver(obj) {\n"
680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "    obj.style.background=\"lightblue\";\n"
690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "}\n"
700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "function onMouseOut(obj) {\n"
710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "    obj.style.background=\"white\";\n"
720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "}\n"
730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "</script>\n"
740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<style type=\"text/css\">\n"
750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "div { font-family: courier; font-size: 13 }\n"
760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "div.parent { margin-left: 15; display: none }\n"
770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "div.leaf { margin-left: 10 }\n"
780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "div.header { margin-left: 10 }\n"
790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "div.link { margin-left: 10; cursor: move }\n"
800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "span.parent { padding-right: 10; }\n"
810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "span.leaf { padding-right: 10; }\n"
820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "a img { border: 0;}\n"
830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "table.sortable th { border-width: 0px 1px 1px 1px; background-color: "
840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "#ccc;}\n"
850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "a { text-decoration: none; }\n"
860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "a:hover { text-decoration: underline; }\n"
870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "table.sortable th, table.sortable td { text-align: left;}"
880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "table.sortable tr.odd td { background-color: #ddd; }\n"
890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "table.sortable tr.even td { background-color: #fff; }\n"
900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "</style>\n"
910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "</head><body>\n\n";
920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoconst char* htmlFooter = "\n</body>\n</html>\n";
940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoconst char* profileSeparator =
950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "======================================================================";
960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoconst char* tableHeader =
980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<table class='sortable' id='%s'><tr>\n"
990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<th>Method</th>\n"
1000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<th>Run 1 (us)</th>\n"
1010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<th>Run 2 (us)</th>\n"
1020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<th>Diff (us)</th>\n"
1030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<th>Diff (%%)</th>\n"
1040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<th>1: # calls</th>\n"
1050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<th>2: # calls</th>\n"
1060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "</tr>\n";
1070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
1080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoconst char* tableHeaderMissing =
1090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<table class='sortable' id='%s'>\n"
1100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<th>Method</th>\n"
1110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<th>Exclusive</th>\n"
1120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<th>Inclusive</th>\n"
1130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    "<th># calls</th>\n";
1140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
1150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#define GRAPH_LABEL_VISITED 0x0001
1160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#define GRAPH_NODE_VISITED 0x0002
1170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
1180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
1190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Values from the header of the data file.
1200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
1210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haotypedef struct DataHeader {
1220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint32_t magic;
1230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int16_t version;
1240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int16_t offsetToData;
1250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int64_t startWhen;
1260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int16_t recordSize;
1270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao} DataHeader;
1280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
1290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
1300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Entry from the thread list.
1310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
1320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haotypedef struct ThreadEntry {
1330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t threadId;
1340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* threadName;
1350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao} ThreadEntry;
1360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
1370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haostruct MethodEntry;
1380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haotypedef struct TimedMethod {
1390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  struct TimedMethod* next;
1400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t elapsedInclusive;
1410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t numCalls;
1420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  struct MethodEntry* method;
1430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao} TimedMethod;
1440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
1450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haotypedef struct ClassEntry {
1460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* className;
1470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t elapsedExclusive;
1480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t numMethods;
1490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  struct MethodEntry** methods; /* list of methods in this class */
1500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t numCalls[2];              /* 0=normal, 1=recursive */
1510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao} ClassEntry;
1520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
1530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haotypedef struct UniqueMethodEntry {
1540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t elapsedExclusive;
1550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t numMethods;
1560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  struct MethodEntry** methods; /* list of methods with same name */
1570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t numCalls[2];              /* 0=normal, 1=recursive */
1580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao} UniqueMethodEntry;
1590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
1600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
1610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Entry from the method list.
1620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
1630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haotypedef struct MethodEntry {
1640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int64_t methodId;
1650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* className;
1660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* methodName;
1670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* signature;
1680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* fileName;
1690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t lineNum;
1700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t elapsedExclusive;
1710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t elapsedInclusive;
1720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t topExclusive; /* non-recursive exclusive time */
1730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t recursiveInclusive;
1740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  struct TimedMethod* parents[2];  /* 0=normal, 1=recursive */
1750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  struct TimedMethod* children[2]; /* 0=normal, 1=recursive */
1760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t numCalls[2];             /* 0=normal, 1=recursive */
1770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t index;                   /* used after sorting to number methods */
1780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t recursiveEntries;        /* number of entries on the stack */
1790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t graphState; /* used when graphing to see if this method has been visited before */
1800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao} MethodEntry;
1810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
1820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
1830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * The parsed contents of the key file.
1840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
1850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haotypedef struct DataKeys {
1860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char* fileData; /* contents of the entire file */
1870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int64_t fileLen;
1880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t numThreads;
1890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  ThreadEntry* threads;
1900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t numMethods;
1910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  MethodEntry* methods; /* 2 extra methods: "toplevel" and "unknown" */
1920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao} DataKeys;
1930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
1940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#define TOPLEVEL_INDEX 0
1950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#define UNKNOWN_INDEX 1
1960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
1970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haotypedef struct StackEntry {
1980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  MethodEntry* method;
1990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t entryTime;
2000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao} StackEntry;
2010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
2020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haotypedef struct CallStack {
2030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t top;
2040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  StackEntry calls[MAX_STACK_DEPTH];
2050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t lastEventTime;
2060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t threadStartTime;
2070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao} CallStack;
2080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
2090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haotypedef struct DiffEntry {
2100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  MethodEntry* method1;
2110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  MethodEntry* method2;
2120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int64_t differenceExclusive;
2130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int64_t differenceInclusive;
2140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  double differenceExclusivePercentage;
2150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  double differenceInclusivePercentage;
2160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao} DiffEntry;
2170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
2180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao// Global options
2190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haotypedef struct Options {
2200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* traceFileName;
2210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* diffFileName;
2220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* graphFileName;
2230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t keepDotFile;
2240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t dump;
2250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t outputHtml;
2260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* sortableUrl;
2270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t threshold;
2280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao} Options;
2290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
2300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haotypedef struct TraceData {
2310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t numClasses;
2320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  ClassEntry* classes;
2330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  CallStack* stacks[MAX_THREADS];
2340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t depth[MAX_THREADS];
2350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t numUniqueMethods;
2360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  UniqueMethodEntry* uniqueMethods;
2370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao} TraceData;
2380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
2390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haostatic Options gOptions;
2400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
2410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/* Escapes characters in the source string that are html special entities.
2420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * The escaped string is written to "dest" which must be large enough to
2430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * hold the result.  A pointer to "dest" is returned.  The characters and
2440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * their corresponding escape sequences are:
2450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao *  '<'  &lt;
2460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao *  '>'  &gt;
2470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao *  '&'  &amp;
2480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
2490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haochar* htmlEscape(const char* src, char* dest, int32_t len) {
2500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char* destStart = dest;
2510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
2520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (src == nullptr) return nullptr;
2530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
2540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t nbytes = 0;
2550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  while (*src) {
2560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (*src == '<') {
2570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      nbytes += 4;
2580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (nbytes >= len) break;
2590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      *dest++ = '&';
2600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      *dest++ = 'l';
2610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      *dest++ = 't';
2620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      *dest++ = ';';
2630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    } else if (*src == '>') {
2640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      nbytes += 4;
2650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (nbytes >= len) break;
2660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      *dest++ = '&';
2670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      *dest++ = 'g';
2680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      *dest++ = 't';
2690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      *dest++ = ';';
2700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    } else if (*src == '&') {
2710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      nbytes += 5;
2720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (nbytes >= len) break;
2730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      *dest++ = '&';
2740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      *dest++ = 'a';
2750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      *dest++ = 'm';
2760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      *dest++ = 'p';
2770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      *dest++ = ';';
2780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    } else {
2790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      nbytes += 1;
2800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (nbytes >= len) break;
2810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      *dest++ = *src;
2820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
2830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    src += 1;
2840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
2850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (nbytes >= len) {
2860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fprintf(stderr, "htmlEscape(): buffer overflow\n");
2870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    exit(1);
2880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
2890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  *dest = 0;
2900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
2910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return destStart;
2920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
2930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
2940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/* Initializes a MethodEntry
2950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
2960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid initMethodEntry(MethodEntry* method, int64_t methodId, const char* className,
2970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                     const char* methodName, const char* signature, const char* fileName,
2980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                     const char* lineNumStr) {
2990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->methodId = methodId;
3000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->className = className;
3010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->methodName = methodName;
3020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->signature = signature;
3030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->fileName = fileName;
3040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->lineNum = (lineNumStr != nullptr) ? atoi(lineNumStr) : -1;
3050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->elapsedExclusive = 0;
3060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->elapsedInclusive = 0;
3070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->topExclusive = 0;
3080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->recursiveInclusive = 0;
3090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->parents[0] = nullptr;
3100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->parents[1] = nullptr;
3110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->children[0] = nullptr;
3120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->children[1] = nullptr;
3130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->numCalls[0] = 0;
3140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->numCalls[1] = 0;
3150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->index = 0;
3160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->recursiveEntries = 0;
3170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
3180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
3190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
3200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * This comparison function is called from qsort() to sort
3210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * methods into decreasing order of exclusive elapsed time.
3220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
3230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t compareElapsedExclusive(const void* a, const void* b) {
3240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const MethodEntry* methodA = *(const MethodEntry**) a;
3250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const MethodEntry* methodB = *(const MethodEntry**) b;
3260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t elapsed1 = methodA->elapsedExclusive;
3270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t elapsed2 = methodB->elapsedExclusive;
3280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (elapsed1 < elapsed2) return 1;
3290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (elapsed1 > elapsed2) return -1;
3300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
3310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* If the elapsed times of two methods are equal, then sort them
3320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * into alphabetical order.
3330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
3340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t result = strcmp(methodA->className, methodB->className);
3350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (result == 0) {
3360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (methodA->methodName == nullptr || methodB->methodName == nullptr) {
3370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      int64_t idA = methodA->methodId;
3380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      int64_t idB = methodB->methodId;
3390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (idA < idB) return -1;
3400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (idA > idB) return 1;
3410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      return 0;
3420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
3430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    result = strcmp(methodA->methodName, methodB->methodName);
3440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (result == 0) result = strcmp(methodA->signature, methodB->signature);
3450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
3460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return result;
3470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
3480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
3490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
3500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * This comparison function is called from qsort() to sort
3510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * methods into decreasing order of inclusive elapsed time.
3520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
3530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t compareElapsedInclusive(const void* a, const void* b) {
3540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const MethodEntry* methodA = *(MethodEntry const**) a;
3550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const MethodEntry* methodB = *(MethodEntry const**) b;
3560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t elapsed1 = methodA->elapsedInclusive;
3570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t elapsed2 = methodB->elapsedInclusive;
3580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (elapsed1 < elapsed2) return 1;
3590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (elapsed1 > elapsed2) return -1;
3600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
3610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* If the elapsed times of two methods are equal, then sort them
3620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * into alphabetical order.
3630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
3640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t result = strcmp(methodA->className, methodB->className);
3650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (result == 0) {
3660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (methodA->methodName == nullptr || methodB->methodName == nullptr) {
3670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      int64_t idA = methodA->methodId;
3680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      int64_t idB = methodB->methodId;
3690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (idA < idB) return -1;
3700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (idA > idB) return 1;
3710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      return 0;
3720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
3730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    result = strcmp(methodA->methodName, methodB->methodName);
3740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (result == 0) result = strcmp(methodA->signature, methodB->signature);
3750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
3760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return result;
3770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
3780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
3790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
3800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * This comparison function is called from qsort() to sort
3810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * TimedMethods into decreasing order of inclusive elapsed time.
3820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
3830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t compareTimedMethod(const void* a, const void* b) {
3840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const TimedMethod* timedA = (TimedMethod const*) a;
3850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const TimedMethod* timedB = (TimedMethod const*) b;
3860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t elapsed1 = timedA->elapsedInclusive;
3870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t elapsed2 = timedB->elapsedInclusive;
3880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (elapsed1 < elapsed2) return 1;
3890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (elapsed1 > elapsed2) return -1;
3900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
3910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* If the elapsed times of two methods are equal, then sort them
3920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * into alphabetical order.
3930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
3940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  MethodEntry* methodA = timedA->method;
3950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  MethodEntry* methodB = timedB->method;
3960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t result = strcmp(methodA->className, methodB->className);
3970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (result == 0) {
3980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (methodA->methodName == nullptr || methodB->methodName == nullptr) {
3990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      int64_t idA = methodA->methodId;
4000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      int64_t idB = methodB->methodId;
4010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (idA < idB) return -1;
4020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (idA > idB) return 1;
4030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      return 0;
4040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
4050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    result = strcmp(methodA->methodName, methodB->methodName);
4060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (result == 0) result = strcmp(methodA->signature, methodB->signature);
4070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
4080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return result;
4090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
4100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
4110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
4120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * This comparison function is called from qsort() to sort
4130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * MethodEntry pointers into alphabetical order of class names.
4140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
4150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t compareClassNames(const void* a, const void* b) {
4160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const MethodEntry* methodA = *(const MethodEntry**) a;
4170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const MethodEntry* methodB = *(const MethodEntry**) b;
4180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t result = strcmp(methodA->className, methodB->className);
4190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (result == 0) {
4200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int64_t idA = methodA->methodId;
4210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int64_t idB = methodB->methodId;
4220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (idA < idB) return -1;
4230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (idA > idB) return 1;
4240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return 0;
4250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
4260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return result;
4270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
4280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
4290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
4300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * This comparison function is called from qsort() to sort
4310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * classes into decreasing order of exclusive elapsed time.
4320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
4330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t compareClassExclusive(const void* a, const void* b) {
4340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const ClassEntry* classA = *(const ClassEntry**) a;
4350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const ClassEntry* classB = *(const ClassEntry**) b;
4360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t elapsed1 = classA->elapsedExclusive;
4370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t elapsed2 = classB->elapsedExclusive;
4380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (elapsed1 < elapsed2) return 1;
4390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (elapsed1 > elapsed2) return -1;
4400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
4410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* If the elapsed times of two classs are equal, then sort them
4420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * into alphabetical order.
4430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
4440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t result = strcmp(classA->className, classB->className);
4450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (result == 0) {
4460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Break ties with the first method id.  This is probably not
4470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao     * needed.
4480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao     */
4490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int64_t idA = classA->methods[0]->methodId;
4500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int64_t idB = classB->methods[0]->methodId;
4510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (idA < idB) return -1;
4520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (idA > idB) return 1;
4530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return 0;
4540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
4550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return result;
4560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
4570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
4580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
4590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * This comparison function is called from qsort() to sort
4600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * MethodEntry pointers into alphabetical order by method name,
4610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * then by class name.
4620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
4630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t compareMethodNames(const void* a, const void* b) {
4640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const MethodEntry* methodA = *(const MethodEntry**) a;
4650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const MethodEntry* methodB = *(const MethodEntry**) b;
4660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (methodA->methodName == nullptr || methodB->methodName == nullptr) {
4670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return compareClassNames(a, b);
4680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
4690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t result = strcmp(methodA->methodName, methodB->methodName);
4700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (result == 0) {
4710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    result = strcmp(methodA->className, methodB->className);
4720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (result == 0) {
4730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      int64_t idA = methodA->methodId;
4740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      int64_t idB = methodB->methodId;
4750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (idA < idB) return -1;
4760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (idA > idB) return 1;
4770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      return 0;
4780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
4790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
4800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return result;
4810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
4820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
4830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
4840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * This comparison function is called from qsort() to sort
4850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * unique methods into decreasing order of exclusive elapsed time.
4860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
4870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t compareUniqueExclusive(const void* a, const void* b) {
4880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const UniqueMethodEntry* uniqueA = *(const UniqueMethodEntry**) a;
4890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const UniqueMethodEntry* uniqueB = *(const UniqueMethodEntry**) b;
4900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t elapsed1 = uniqueA->elapsedExclusive;
4910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t elapsed2 = uniqueB->elapsedExclusive;
4920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (elapsed1 < elapsed2) return 1;
4930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (elapsed1 > elapsed2) return -1;
4940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
4950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* If the elapsed times of two methods are equal, then sort them
4960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * into alphabetical order.
4970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
4980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t result = strcmp(uniqueA->methods[0]->className, uniqueB->methods[0]->className);
4990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (result == 0) {
5000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int64_t idA = uniqueA->methods[0]->methodId;
5010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int64_t idB = uniqueB->methods[0]->methodId;
5020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (idA < idB) return -1;
5030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (idA > idB) return 1;
5040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return 0;
5050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
5060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return result;
5070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
5080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
5100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Free a DataKeys struct.
5110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
5120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid freeDataKeys(DataKeys* pKeys) {
5130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (pKeys == nullptr) return;
5140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  free(pKeys->fileData);
5160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  free(pKeys->threads);
5170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  free(pKeys->methods);
5180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  free(pKeys);
5190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
5200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
5220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Find the offset to the next occurrence of the specified character.
5230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao *
5240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * "data" should point somewhere within the current line.  "len" is the
5250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * number of bytes left in the buffer.
5260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao *
5270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Returns -1 if we hit the end of the buffer.
5280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
5290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t findNextChar(const char* data, int32_t len, char lookFor) {
5300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* start = data;
5310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  while (len > 0) {
5330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (*data == lookFor) return data - start;
5340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    data++;
5360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    len--;
5370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
5380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return -1;
5400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
5410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
5430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Count the number of lines until the next token.
5440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao *
5450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Returns -1 if none found before EOF.
5460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
5470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t countLinesToToken(const char* data, int32_t len) {
5480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t count = 0;
5490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t next;
5500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  while (*data != TOKEN_CHAR) {
5520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    next = findNextChar(data, len, '\n');
5530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (next < 0) return -1;
5540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    count++;
5550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    data += next + 1;
5560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    len -= next + 1;
5570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
5580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return count;
5600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
5610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
5630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Make sure we're at the start of the right section.
5640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao *
5650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Returns the length of the token line, or -1 if something is wrong.
5660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
5670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t checkToken(const char* data, int32_t len, const char* cmpStr) {
5680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t cmpLen = strlen(cmpStr);
5690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t next;
5700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (*data != TOKEN_CHAR) {
5720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fprintf(stderr, "ERROR: not at start of %s (found '%.10s')\n", cmpStr, data);
5730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return -1;
5740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
5750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  next = findNextChar(data, len, '\n');
5770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (next < cmpLen + 1) return -1;
5780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (strncmp(data + 1, cmpStr, cmpLen) != 0) {
5800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fprintf(stderr, "ERROR: '%s' not found (got '%.7s')\n", cmpStr, data + 1);
5810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return -1;
5820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
5830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return next + 1;
5850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
5860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
5880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Parse the "*version" section.
5890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
5900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint64_t parseVersion(DataKeys* pKeys, int64_t offset, int32_t verbose) {
5910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (offset < 0) return -1;
5920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char* data = pKeys->fileData + offset;
5940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char* dataEnd = pKeys->fileData + pKeys->fileLen;
5950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t next = checkToken(data, dataEnd - data, "version");
5960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (next <= 0) return -1;
5970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
5980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  data += next;
5990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /*
6010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * Count the number of items in the "version" section.
6020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
6030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t count = countLinesToToken(data, dataEnd - data);
6040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (count <= 0) {
6050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fprintf(stderr, "ERROR: failed while reading version (found %d)\n", count);
6060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return -1;
6070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
6080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* find the end of the line */
6100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  next = findNextChar(data, dataEnd - data, '\n');
6110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (next < 0) return -1;
6120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  data[next] = '\0';
6140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  versionNumber = strtoul(data, nullptr, 0);
6150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (verbose) printf("VERSION: %d\n", versionNumber);
6160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  data += next + 1;
6180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* skip over the rest of the stuff, which is "name=value" lines */
6200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t i = 1; i < count; i++) {
6210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    next = findNextChar(data, dataEnd - data, '\n');
6220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (next < 0) return -1;
6230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    // data[next] = '\0';
6240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    // printf("IGNORING: '%s'\n", data);
6250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    data += next + 1;
6260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
6270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return data - pKeys->fileData;
6290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
6300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
6320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Parse the "*threads" section.
6330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
6340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint64_t parseThreads(DataKeys* pKeys, int64_t offset) {
6350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (offset < 0) return -1;
6360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char* data = pKeys->fileData + offset;
6380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char* dataEnd = pKeys->fileData + pKeys->fileLen;
6390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t next = checkToken(data, dataEnd - data, "threads");
6400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  data += next;
6420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /*
6440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * Count the number of thread entries (one per line).
6450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
6460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t count = countLinesToToken(data, dataEnd - data);
6470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (count <= 0) {
6480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fprintf(stderr, "ERROR: failed while reading threads (found %d)\n", count);
6490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return -1;
6500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
6510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  // printf("+++ found %d threads\n", count);
6530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pKeys->threads = new ThreadEntry[count];
6540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (pKeys->threads == nullptr) return -1;
6550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /*
6570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * Extract all entries.
6580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
6590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t i = 0; i < count; i++) {
6600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    next = findNextChar(data, dataEnd - data, '\n');
6610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    assert(next > 0);
6620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    data[next] = '\0';
6630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t tab = findNextChar(data, next, '\t');
6650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    data[tab] = '\0';
6660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pKeys->threads[i].threadId = atoi(data);
6680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pKeys->threads[i].threadName = data + tab + 1;
6690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    data += next + 1;
6710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
6720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pKeys->numThreads = count;
6740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return data - pKeys->fileData;
6750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
6760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
6780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Parse the "*methods" section.
6790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
6800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint64_t parseMethods(DataKeys* pKeys, int64_t offset) {
6810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (offset < 0) return -1;
6820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char* data = pKeys->fileData + offset;
6840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char* dataEnd = pKeys->fileData + pKeys->fileLen;
6850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t next = checkToken(data, dataEnd - data, "methods");
6860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (next < 0) return -1;
6870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  data += next;
6890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /*
6910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * Count the number of method entries (one per line).
6920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
6930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t count = countLinesToToken(data, dataEnd - data);
6940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (count <= 0) {
6950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fprintf(stderr, "ERROR: failed while reading methods (found %d)\n", count);
6960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return -1;
6970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
6980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
6990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Reserve an extra method at location 0 for the "toplevel" method,
7000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * and another extra method for all other "unknown" methods.
7010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
7020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  count += 2;
7030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pKeys->methods = new MethodEntry[count];
7040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (pKeys->methods == nullptr) return -1;
7050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  initMethodEntry(&pKeys->methods[TOPLEVEL_INDEX], -2, "(toplevel)", nullptr, nullptr,
7060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                  nullptr, nullptr);
7070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  initMethodEntry(&pKeys->methods[UNKNOWN_INDEX], -1, "(unknown)", nullptr, nullptr,
7080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                  nullptr, nullptr);
7090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
7100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /*
7110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * Extract all entries, starting with index 2.
7120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
7130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t i = UNKNOWN_INDEX + 1; i < count; i++) {
7140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    next = findNextChar(data, dataEnd - data, '\n');
7150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    assert(next > 0);
7160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    data[next] = '\0';
7170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
7180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t tab1 = findNextChar(data, next, '\t');
7190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t tab2 = findNextChar(data + (tab1 + 1), next - (tab1 + 1), '\t');
7200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t tab3 = findNextChar(data + (tab1 + tab2 + 2), next - (tab1 + tab2 + 2), '\t');
7210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t tab4 = findNextChar(data + (tab1 + tab2 + tab3 + 3),
7220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                                next - (tab1 + tab2 + tab3 + 3), '\t');
7230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t tab5 = findNextChar(data + (tab1 + tab2 + tab3 + tab4 + 4),
7240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                                next - (tab1 + tab2 + tab3 + tab4 + 4), '\t');
7250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (tab1 < 0) {
7260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      fprintf(stderr, "ERROR: missing field on method line: '%s'\n", data);
7270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      return -1;
7280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
7290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    assert(data[tab1] == '\t');
7300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    data[tab1] = '\0';
7310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
7320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    char* endptr;
7330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int64_t id = strtoul(data, &endptr, 0);
7340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (*endptr != '\0') {
7350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      fprintf(stderr, "ERROR: bad method ID '%s'\n", data);
7360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      return -1;
7370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
7380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
7390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    // Allow files that specify just a function name, instead of requiring
7400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    // "class \t method \t signature"
7410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (tab2 > 0 && tab3 > 0) {
7420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      tab2 += tab1 + 1;
7430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      tab3 += tab2 + 1;
7440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      assert(data[tab2] == '\t');
7450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      assert(data[tab3] == '\t');
7460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      data[tab2] = data[tab3] = '\0';
7470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
7480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      // This is starting to get awkward.  Allow filename and line #.
7490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (tab4 > 0 && tab5 > 0) {
7500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        tab4 += tab3 + 1;
7510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        tab5 += tab4 + 1;
7520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
7530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        assert(data[tab4] == '\t');
7540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        assert(data[tab5] == '\t');
7550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        data[tab4] = data[tab5] = '\0';
7560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
7570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        initMethodEntry(&pKeys->methods[i], id, data + tab1 + 1,
7580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                        data + tab2 + 1, data + tab3 + 1, data + tab4 + 1,
7590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                        data + tab5 + 1);
7600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      } else {
7610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        initMethodEntry(&pKeys->methods[i], id, data + tab1 + 1,
7620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                        data + tab2 + 1, data + tab3 + 1, nullptr, nullptr);
7630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      }
7640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    } else {
7650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      initMethodEntry(&pKeys->methods[i], id, data + tab1 + 1, nullptr, nullptr, nullptr,
7660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                      nullptr);
7670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
7680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
7690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    data += next + 1;
7700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
7710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
7720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pKeys->numMethods = count;
7730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return data - pKeys->fileData;
7740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
7750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
7760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
7770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Parse the "*end" section.
7780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
7790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint64_t parseEnd(DataKeys* pKeys, int64_t offset) {
7800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (offset < 0) return -1;
7810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
7820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char* data = pKeys->fileData + offset;
7830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char* dataEnd = pKeys->fileData + pKeys->fileLen;
7840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t next = checkToken(data, dataEnd - data, "end");
7850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (next < 0) return -1;
7860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
7870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  data += next;
7880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
7890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return data - pKeys->fileData;
7900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
7910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
7920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
7930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Sort the thread list entries.
7940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
7950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haostatic int32_t compareThreads(const void* thread1, const void* thread2) {
7960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return ((const ThreadEntry*) thread1)->threadId -
7970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao         ((const ThreadEntry*) thread2)->threadId;
7980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
7990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
8000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid sortThreadList(DataKeys* pKeys) {
8010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  qsort(pKeys->threads, pKeys->numThreads, sizeof(pKeys->threads[0]), compareThreads);
8020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
8030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
8040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
8050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Sort the method list entries.
8060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
8070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haostatic int32_t compareMethods(const void* meth1, const void* meth2) {
8080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int64_t id1 = ((const MethodEntry*) meth1)->methodId;
8090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int64_t id2 = ((const MethodEntry*) meth2)->methodId;
8100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (id1 < id2) return -1;
8110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (id1 > id2) return 1;
8120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return 0;
8130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
8140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
8150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid sortMethodList(DataKeys* pKeys) {
8160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  qsort(pKeys->methods, pKeys->numMethods, sizeof(MethodEntry), compareMethods);
8170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
8180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
8190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
8200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Parse the key section, and return a copy of the parsed contents.
8210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
8220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff HaoDataKeys* parseKeys(FILE* fp, int32_t verbose) {
8230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int64_t offset;
8240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  DataKeys* pKeys = new DataKeys();
8250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  memset(pKeys, 0, sizeof(DataKeys));
8260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (pKeys == nullptr) return nullptr;
8270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
8280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /*
8290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * We load the entire file into memory.  We do this, rather than memory-
8300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * mapping it, because we want to change some whitespace to NULs.
8310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
8320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (fseek(fp, 0L, SEEK_END) != 0) {
8330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    perror("fseek");
8340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    freeDataKeys(pKeys);
8350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return nullptr;
8360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
8370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pKeys->fileLen = ftell(fp);
8380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (pKeys->fileLen == 0) {
8390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fprintf(stderr, "Key file is empty.\n");
8400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    freeDataKeys(pKeys);
8410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return nullptr;
8420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
8430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  rewind(fp);
8440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
8450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pKeys->fileData = new char[pKeys->fileLen];
8460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (pKeys->fileData == nullptr) {
8470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fprintf(stderr, "ERROR: unable to alloc %" PRIu64 " bytes\n", pKeys->fileLen);
8480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    freeDataKeys(pKeys);
8490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return nullptr;
8500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
8510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
8520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (fread(pKeys->fileData, 1, pKeys->fileLen, fp) != (size_t)pKeys->fileLen) {
8530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fprintf(stderr, "ERROR: unable to read %" PRIu64 " bytes from trace file\n", pKeys->fileLen);
8540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    freeDataKeys(pKeys);
8550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return nullptr;
8560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
8570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
8580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  offset = 0;
8590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  offset = parseVersion(pKeys, offset, verbose);
8600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  offset = parseThreads(pKeys, offset);
8610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  offset = parseMethods(pKeys, offset);
8620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  offset = parseEnd(pKeys, offset);
8630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (offset < 0) {
8640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    freeDataKeys(pKeys);
8650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return nullptr;
8660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
8670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
8680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Reduce our allocation now that we know where the end of the key section is. */
8690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pKeys->fileData = reinterpret_cast<char*>(realloc(pKeys->fileData, offset));
8700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pKeys->fileLen = offset;
8710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Leave fp pointing to the beginning of the data section. */
8720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fseek(fp, offset, SEEK_SET);
8730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
8740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  sortThreadList(pKeys);
8750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  sortMethodList(pKeys);
8760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
8770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /*
8780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * Dump list of threads.
8790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
8800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (verbose) {
8810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("Threads (%d):\n", pKeys->numThreads);
8820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    for (int32_t i = 0; i < pKeys->numThreads; i++) {
8830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("%2d %s\n", pKeys->threads[i].threadId, pKeys->threads[i].threadName);
8840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
8850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
8860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
8870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#if 0
8880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /*
8890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * Dump list of methods.
8900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
8910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (verbose) {
8920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("Methods (%d):\n", pKeys->numMethods);
8930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    for (int32_t i = 0; i < pKeys->numMethods; i++) {
8940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("0x%08x %s : %s : %s\n",
8950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             pKeys->methods[i].methodId, pKeys->methods[i].className,
8960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             pKeys->methods[i].methodName, pKeys->methods[i].signature);
8970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
8980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
8990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#endif
9000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
9010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return pKeys;
9020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
9030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
9040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
9050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Read values from the binary data file.
9060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
9070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
9080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
9090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Make the return value "uint32_t" instead of "uint16_t" so that we can detect EOF.
9100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
9110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haouint32_t read2LE(FILE* fp) {
9120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint32_t val = getc(fp);
9130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  val |= getc(fp) << 8;
9140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return val;
9150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
9160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haouint32_t read4LE(FILE* fp) {
9170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint32_t val = getc(fp);
9180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  val |= getc(fp) << 8;
9190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  val |= getc(fp) << 16;
9200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  val |= getc(fp) << 24;
9210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return val;
9220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
9230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haouint64_t read8LE(FILE* fp) {
9240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t val = getc(fp);
9250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  val |= (uint64_t) getc(fp) << 8;
9260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  val |= (uint64_t) getc(fp) << 16;
9270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  val |= (uint64_t) getc(fp) << 24;
9280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  val |= (uint64_t) getc(fp) << 32;
9290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  val |= (uint64_t) getc(fp) << 40;
9300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  val |= (uint64_t) getc(fp) << 48;
9310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  val |= (uint64_t) getc(fp) << 56;
9320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return val;
9330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
9340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
9350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
9360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Parse the header of the data section.
9370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao *
9380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Returns with the file positioned at the start of the record data.
9390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
9400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t parseDataHeader(FILE* fp, DataHeader* pHeader) {
9410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pHeader->magic = read4LE(fp);
9420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pHeader->version = read2LE(fp);
9430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pHeader->offsetToData = read2LE(fp);
9440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pHeader->startWhen = read8LE(fp);
9450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t bytesToRead = pHeader->offsetToData - 16;
9460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (pHeader->version == 1) {
9470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pHeader->recordSize = 9;
9480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  } else if (pHeader->version == 2) {
9490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pHeader->recordSize = 10;
9500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  } else if (pHeader->version == 3) {
9510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pHeader->recordSize = read2LE(fp);
9520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    bytesToRead -= 2;
9530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  } else {
9540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fprintf(stderr, "Unsupported trace file version: %d\n", pHeader->version);
9550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return -1;
9560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
9570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
9580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (fseek(fp, bytesToRead, SEEK_CUR) != 0) {
9590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return -1;
9600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
9610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
9620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return 0;
9630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
9640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
9650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
9660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Look up a method by it's method ID.
9670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao *
9680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Returns nullptr if no matching method was found.
9690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
9700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff HaoMethodEntry* lookupMethod(DataKeys* pKeys, int64_t methodId) {
9710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t lo = 0;
9720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t hi = pKeys->numMethods - 1;
9730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
9740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  while (hi >= lo) {
9750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t mid = (hi + lo) / 2;
9760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
9770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int64_t id = pKeys->methods[mid].methodId;
9780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (id == methodId) /* match */
9790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      return &pKeys->methods[mid];
9800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    else if (id < methodId) /* too low */
9810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      lo = mid + 1;
9820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    else /* too high */
9830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      hi = mid - 1;
9840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
9850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
9860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return nullptr;
9870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
9880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
9890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
9900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Reads the next data record, and assigns the data values to threadId,
9910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * methodVal and elapsedTime.  On end-of-file, the threadId, methodVal,
9920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * and elapsedTime are unchanged.  Returns 1 on end-of-file, otherwise
9930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * returns 0.
9940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
9950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t readDataRecord(FILE* dataFp, DataHeader* dataHeader, int32_t* threadId,
9960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                   uint32_t* methodVal, uint64_t* elapsedTime) {
9970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t id;
9980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t bytesToRead = dataHeader->recordSize;
9990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (dataHeader->version == 1) {
10000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    id = getc(dataFp);
10010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    bytesToRead -= 1;
10020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  } else {
10030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    id = read2LE(dataFp);
10040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    bytesToRead -= 2;
10050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
10060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (id == EOF) return 1;
10070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  *threadId = id;
10080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  *methodVal = read4LE(dataFp);
10100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  *elapsedTime = read4LE(dataFp);
10110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  bytesToRead -= 8;
10120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  while (bytesToRead-- > 0) {
10140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    getc(dataFp);
10150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
10160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (feof(dataFp)) {
10180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fprintf(stderr, "WARNING: hit EOF mid-record\n");
10190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return 1;
10200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
10210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return 0;
10220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
10230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
10250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Read the key file and use it to produce formatted output from the
10260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * data file.
10270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
10280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid dumpTrace() {
10290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  static const char* actionStr[] = {"ent", "xit", "unr", "???"};
10300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  MethodEntry bogusMethod = {
10310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      0, "???", "???",        "???",        "???",  -1, 0, 0,
10320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      0, 0,     {nullptr, nullptr}, {nullptr, nullptr}, {0, 0}, 0,  0, -1};
10330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char bogusBuf[80];
10340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  TraceData traceData;
10350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  // printf("Dumping '%s' '%s'\n", dataFileName, keyFileName);
10370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char spaces[MAX_STACK_DEPTH + 1];
10390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  memset(spaces, '.', MAX_STACK_DEPTH);
10400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  spaces[MAX_STACK_DEPTH] = '\0';
10410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t i = 0; i < MAX_THREADS; i++)
10430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    traceData.depth[i] = 2;  // adjust for return from start function
10440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  FILE* dataFp = fopen(gOptions.traceFileName, "rb");
10460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (dataFp == nullptr) return;
10470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  DataKeys* pKeys = parseKeys(dataFp, 1);
10490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (pKeys == nullptr) {
10500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fclose(dataFp);
10510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return;
10520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
10530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  DataHeader dataHeader;
10550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (parseDataHeader(dataFp, &dataHeader) < 0) {
10560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fclose(dataFp);
10570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    freeDataKeys(pKeys);
10580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return;
10590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
10600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("Trace (threadID action usecs class.method signature):\n");
10620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  while (1) {
10640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /*
10650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao     * Extract values from file.
10660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao     */
10670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t threadId;
10680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    uint32_t methodVal;
10690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    uint64_t elapsedTime;
10700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (readDataRecord(dataFp, &dataHeader, &threadId, &methodVal, &elapsedTime))
10710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      break;
10720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t action = METHOD_ACTION(methodVal);
10740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int64_t methodId = METHOD_ID(methodVal);
10750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /*
10770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao     * Generate a line of output.
10780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao     */
10790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int64_t lastEnter = 0;
10800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t mismatch = 0;
10810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (action == METHOD_TRACE_ENTER) {
10820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      traceData.depth[threadId]++;
10830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      lastEnter = methodId;
10840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    } else {
10850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      /* quick test for mismatched adjacent enter/exit */
10860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (lastEnter != 0 && lastEnter != methodId) mismatch = 1;
10870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
10880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t printDepth = traceData.depth[threadId];
10900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    char depthNote = ' ';
10910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (printDepth < 0) {
10920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printDepth = 0;
10930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      depthNote = '-';
10940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    } else if (printDepth > MAX_STACK_DEPTH) {
10950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printDepth = MAX_STACK_DEPTH;
10960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      depthNote = '+';
10970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
10980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
10990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    MethodEntry* method = lookupMethod(pKeys, methodId);
11000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (method == nullptr) {
11010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      method = &bogusMethod;
11020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sprintf(bogusBuf, "methodId: %#" PRIx64 "", methodId);
11030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      method->signature = bogusBuf;
11040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
11050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
11060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (method->methodName) {
11070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("%2d %s%c %8" PRIu64 "%c%s%s.%s %s\n", threadId, actionStr[action],
11080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             mismatch ? '!' : ' ', elapsedTime, depthNote,
11090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             spaces + (MAX_STACK_DEPTH - printDepth), method->className,
11100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             method->methodName, method->signature);
11110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    } else {
11120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("%2d %s%c %8" PRIu64 "%c%s%s\n", threadId, actionStr[action],
11130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             mismatch ? '!' : ' ', elapsedTime, depthNote,
11140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             spaces + (MAX_STACK_DEPTH - printDepth), method->className);
11150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
11160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
11170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (action != METHOD_TRACE_ENTER) {
11180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      traceData.depth[threadId]--; /* METHOD_TRACE_EXIT or METHOD_TRACE_UNROLL */
11190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      lastEnter = 0;
11200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
11210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
11220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    mismatch = 0;
11230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
11240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
11250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fclose(dataFp);
11260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  freeDataKeys(pKeys);
11270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
11280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
11290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/* This routine adds the given time to the parent and child methods.
11300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * This is called when the child routine exits, after the child has
11310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * been popped from the stack.  The elapsedTime parameter is the
11320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * duration of the child routine, including time spent in called routines.
11330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
11340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid addInclusiveTime(MethodEntry* parent, MethodEntry* child, uint64_t elapsedTime) {
11350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#if 0
11360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  bool verbose = false;
11370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (strcmp(child->className, debugClassName) == 0)
11380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    verbose = true;
11390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#endif
11400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
11410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t childIsRecursive = (child->recursiveEntries > 0);
11420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t parentIsRecursive = (parent->recursiveEntries > 1);
11430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
11440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (child->recursiveEntries == 0) {
11450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    child->elapsedInclusive += elapsedTime;
11460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  } else if (child->recursiveEntries == 1) {
11470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    child->recursiveInclusive += elapsedTime;
11480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
11490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  child->numCalls[childIsRecursive] += 1;
11500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
11510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#if 0
11520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (verbose) {
11530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fprintf(stderr,
11540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao            "%s %d elapsedTime: %lld eI: %lld, rI: %lld\n",
11550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao            child->className, child->recursiveEntries,
11560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao            elapsedTime, child->elapsedInclusive,
11570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao            child->recursiveInclusive);
11580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
11590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#endif
11600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
11610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Find the child method in the parent */
11620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  TimedMethod* pTimed;
11630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  TimedMethod* children = parent->children[parentIsRecursive];
11640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (pTimed = children; pTimed; pTimed = pTimed->next) {
11650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (pTimed->method == child) {
11660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pTimed->elapsedInclusive += elapsedTime;
11670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pTimed->numCalls += 1;
11680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      break;
11690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
11700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
11710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (pTimed == nullptr) {
11720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Allocate a new TimedMethod */
11730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pTimed = new TimedMethod();
11740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pTimed->elapsedInclusive = elapsedTime;
11750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pTimed->numCalls = 1;
11760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pTimed->method = child;
11770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
11780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Add it to the front of the list */
11790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pTimed->next = children;
11800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    parent->children[parentIsRecursive] = pTimed;
11810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
11820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
11830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Find the parent method in the child */
11840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  TimedMethod* parents = child->parents[childIsRecursive];
11850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (pTimed = parents; pTimed; pTimed = pTimed->next) {
11860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (pTimed->method == parent) {
11870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pTimed->elapsedInclusive += elapsedTime;
11880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pTimed->numCalls += 1;
11890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      break;
11900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
11910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
11920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (pTimed == nullptr) {
11930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Allocate a new TimedMethod */
11940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pTimed = new TimedMethod();
11950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pTimed->elapsedInclusive = elapsedTime;
11960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pTimed->numCalls = 1;
11970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pTimed->method = parent;
11980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
11990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Add it to the front of the list */
12000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pTimed->next = parents;
12010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    child->parents[childIsRecursive] = pTimed;
12020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
12030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
12040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#if 0
12050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (verbose) {
12060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fprintf(stderr,
12070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao            "  %s %d eI: %lld\n",
12080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao            parent->className, parent->recursiveEntries,
12090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao            pTimed->elapsedInclusive);
12100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
12110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#endif
12120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
12130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
12140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/* Sorts a linked list and returns a newly allocated array containing
12150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * the sorted entries.
12160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
12170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff HaoTimedMethod* sortTimedMethodList(TimedMethod* list, int32_t* num) {
12180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Count the elements */
12190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  TimedMethod* pTimed;
12200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t num_entries = 0;
12210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (pTimed = list; pTimed; pTimed = pTimed->next) num_entries += 1;
12220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  *num = num_entries;
12230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (num_entries == 0) return nullptr;
12240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
12250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Copy all the list elements to a new array and sort them */
12260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t ii;
12270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  TimedMethod* sorted = new TimedMethod[num_entries];
12280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (ii = 0, pTimed = list; pTimed; pTimed = pTimed->next, ++ii)
12290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    memcpy(&sorted[ii], pTimed, sizeof(TimedMethod));
12300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  qsort(sorted, num_entries, sizeof(TimedMethod), compareTimedMethod);
12310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
12320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Fix up the "next" pointers so that they work. */
12330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (ii = 0; ii < num_entries - 1; ++ii) sorted[ii].next = &sorted[ii + 1];
12340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  sorted[num_entries - 1].next = nullptr;
12350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
12360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return sorted;
12370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
12380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
12390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/* Define flag values for printInclusiveMethod() */
12400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haostatic const int32_t kIsRecursive = 1;
12410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
12420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/* This prints the inclusive stats for all the parents or children of a
12430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * method, depending on the list that is passed in.
12440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
12450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid printInclusiveMethod(MethodEntry* method, TimedMethod* list, int32_t numCalls, int32_t flags) {
12460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char buf[80];
12470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* anchor_close = "";
12480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* spaces = "      "; /* 6 spaces */
12490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t num_spaces = strlen(spaces);
12500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* space_ptr = &spaces[num_spaces];
12510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char classBuf[HTML_BUFSIZE], methodBuf[HTML_BUFSIZE];
12520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char signatureBuf[HTML_BUFSIZE];
12530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
12540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) anchor_close = "</a>";
12550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
12560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t num;
12570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  TimedMethod* sorted = sortTimedMethodList(list, &num);
12580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  double methodTotal = method->elapsedInclusive;
12590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (TimedMethod* pTimed = sorted; pTimed; pTimed = pTimed->next) {
12600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    MethodEntry* relative = pTimed->method;
12610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    const char* className = relative->className;
12620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    const char* methodName = relative->methodName;
12630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    const char* signature = relative->signature;
12640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    double per = 100.0 * pTimed->elapsedInclusive / methodTotal;
12650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    sprintf(buf, "[%d]", relative->index);
12660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) {
12670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      int32_t len = strlen(buf);
12680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (len > num_spaces) len = num_spaces;
12690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sprintf(buf, "<a href=\"#m%d\">[%d]", relative->index, relative->index);
12700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      space_ptr = &spaces[len];
12710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      className = htmlEscape(className, classBuf, HTML_BUFSIZE);
12720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      methodName = htmlEscape(methodName, methodBuf, HTML_BUFSIZE);
12730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      signature = htmlEscape(signature, signatureBuf, HTML_BUFSIZE);
12740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
12750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t nCalls = numCalls;
12760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (nCalls == 0) nCalls = relative->numCalls[0] + relative->numCalls[1];
12770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (relative->methodName) {
12780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (flags & kIsRecursive) {
12790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        // Don't display percentages for recursive functions
12800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("%6s %5s   %6s %s%6s%s %6d/%-6d %9" PRIu64 " %s.%s %s\n", "", "",
12810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               "", space_ptr, buf, anchor_close, pTimed->numCalls, nCalls,
12820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               pTimed->elapsedInclusive, className, methodName, signature);
12830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      } else {
12840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("%6s %5s   %5.1f%% %s%6s%s %6d/%-6d %9" PRIu64 " %s.%s %s\n", "",
12850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               "", per, space_ptr, buf, anchor_close, pTimed->numCalls, nCalls,
12860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               pTimed->elapsedInclusive, className, methodName, signature);
12870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      }
12880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    } else {
12890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (flags & kIsRecursive) {
12900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        // Don't display percentages for recursive functions
12910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("%6s %5s   %6s %s%6s%s %6d/%-6d %9" PRIu64 " %s\n", "", "", "",
12920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               space_ptr, buf, anchor_close, pTimed->numCalls, nCalls,
12930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               pTimed->elapsedInclusive, className);
12940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      } else {
12950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("%6s %5s   %5.1f%% %s%6s%s %6d/%-6d %9" PRIu64 " %s\n", "", "",
12960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               per, space_ptr, buf, anchor_close, pTimed->numCalls, nCalls,
12970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               pTimed->elapsedInclusive, className);
12980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      }
12990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
13000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
13010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
13020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
13030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid countRecursiveEntries(CallStack* pStack, int32_t top, MethodEntry* method) {
13040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->recursiveEntries = 0;
13050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < top; ++ii) {
13060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (pStack->calls[ii].method == method) method->recursiveEntries += 1;
13070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
13080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
13090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
13100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid stackDump(CallStack* pStack, int32_t top) {
13110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < top; ++ii) {
13120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    MethodEntry* method = pStack->calls[ii].method;
13130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    uint64_t entryTime = pStack->calls[ii].entryTime;
13140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (method->methodName) {
13150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      fprintf(stderr, "  %2d: %8" PRIu64 " %s.%s %s\n", ii, entryTime,
13160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao              method->className, method->methodName, method->signature);
13170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    } else {
13180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      fprintf(stderr, "  %2d: %8" PRIu64 " %s\n", ii, entryTime, method->className);
13190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
13200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
13210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
13220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
13230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid outputTableOfContents() {
13240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("<a name=\"contents\"></a>\n");
13250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("<h2>Table of Contents</h2>\n");
13260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("<ul>\n");
13270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("  <li><a href=\"#exclusive\">Exclusive profile</a></li>\n");
13280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("  <li><a href=\"#inclusive\">Inclusive profile</a></li>\n");
13290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("  <li><a href=\"#class\">Class/method profile</a></li>\n");
13300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("  <li><a href=\"#method\">Method/class profile</a></li>\n");
13310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("</ul>\n\n");
13320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
13330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
13340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid outputNavigationBar() {
13350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("<a href=\"#contents\">[Top]</a>\n");
13360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("<a href=\"#exclusive\">[Exclusive]</a>\n");
13370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("<a href=\"#inclusive\">[Inclusive]</a>\n");
13380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("<a href=\"#class\">[Class]</a>\n");
13390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("<a href=\"#method\">[Method]</a>\n");
13400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("<br><br>\n");
13410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
13420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
13430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid printExclusiveProfile(MethodEntry** pMethods, int32_t numMethods, uint64_t sumThreadTime) {
13440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char classBuf[HTML_BUFSIZE], methodBuf[HTML_BUFSIZE];
13450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char signatureBuf[HTML_BUFSIZE];
13460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* anchor_close = "";
13470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char anchor_buf[80];
13480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  anchor_buf[0] = 0;
13490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
13500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    anchor_close = "</a>";
13510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<a name=\"exclusive\"></a>\n");
13520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<hr>\n");
13530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    outputNavigationBar();
13540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  } else {
13550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("\n%s\n", profileSeparator);
13560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
13570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
13580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* First, sort the methods into decreasing order of inclusive
13590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * elapsed time so that we can assign the method indices.
13600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
13610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  qsort(pMethods, numMethods, sizeof(MethodEntry*), compareElapsedInclusive);
13620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
13630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < numMethods; ++ii) pMethods[ii]->index = ii;
13640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
13650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Sort the methods into decreasing order of exclusive elapsed time. */
13660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  qsort(pMethods, numMethods, sizeof(MethodEntry*), compareElapsedExclusive);
13670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
13680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("Total cycles: %" PRIu64 "\n\n", sumThreadTime);
13690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
13700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<br><br>\n");
13710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
13720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("Exclusive elapsed times for each method, not including time spent in\n");
13730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("children, sorted by exclusive time.\n\n");
13740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
13750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<br><br>\n<pre>\n");
13760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
13770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
13780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("    Usecs  self %%  sum %%  Method\n");
13790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
13800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  double sum = 0;
13810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  double total = sumThreadTime;
13820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < numMethods; ++ii) {
13830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    MethodEntry* method = pMethods[ii];
13840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Don't show methods with zero cycles */
13850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (method->elapsedExclusive == 0) break;
13860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    const char* className = method->className;
13870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    const char* methodName = method->methodName;
13880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    const char* signature = method->signature;
13890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    sum += method->elapsedExclusive;
13900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    double per = 100.0 * method->elapsedExclusive / total;
13910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    double sum_per = 100.0 * sum / total;
13920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) {
13930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sprintf(anchor_buf, "<a href=\"#m%d\">", method->index);
13940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      className = htmlEscape(className, classBuf, HTML_BUFSIZE);
13950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      methodName = htmlEscape(methodName, methodBuf, HTML_BUFSIZE);
13960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      signature = htmlEscape(signature, signatureBuf, HTML_BUFSIZE);
13970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
13980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (method->methodName) {
13990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("%9" PRIu64 "  %6.2f %6.2f  %s[%d]%s %s.%s %s\n",
14000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             method->elapsedExclusive, per, sum_per, anchor_buf, method->index,
14010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             anchor_close, className, methodName, signature);
14020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    } else {
14030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("%9" PRIu64 "  %6.2f %6.2f  %s[%d]%s %s\n",
14040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             method->elapsedExclusive, per, sum_per, anchor_buf, method->index,
14050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             anchor_close, className);
14060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
14070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
14080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
14090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("</pre>\n");
14100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
14110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
14120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/* check to make sure that the child method meets the threshold of the parent */
14140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t checkThreshold(MethodEntry* parent, MethodEntry* child) {
14150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  double parentTime = parent->elapsedInclusive;
14160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  double childTime = child->elapsedInclusive;
14170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int64_t percentage = (childTime / parentTime) * 100.0;
14180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return (percentage < gOptions.threshold) ? 0 : 1;
14190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
14200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid createLabels(FILE* file, MethodEntry* method) {
14220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fprintf(file,
14230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "node%d[label = \"[%d] %s.%s (%" PRIu64 ", %" PRIu64 ", %d)\"]\n",
14240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          method->index, method->index, method->className, method->methodName,
14250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          method->elapsedInclusive / 1000, method->elapsedExclusive / 1000,
14260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          method->numCalls[0]);
14270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->graphState = GRAPH_LABEL_VISITED;
14290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (TimedMethod* child = method->children[0]; child; child = child->next) {
14310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    MethodEntry* childMethod = child->method;
14320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if ((childMethod->graphState & GRAPH_LABEL_VISITED) == 0 &&
14340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        checkThreshold(method, childMethod)) {
14350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      createLabels(file, child->method);
14360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
14370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
14380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
14390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid createLinks(FILE* file, MethodEntry* method) {
14410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  method->graphState |= GRAPH_NODE_VISITED;
14420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (TimedMethod* child = method->children[0]; child; child = child->next) {
14440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    MethodEntry* childMethod = child->method;
14450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (checkThreshold(method, child->method)) {
14460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      fprintf(file, "node%d -> node%d\n", method->index, child->method->index);
14470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      // only visit children that haven't been visited before
14480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if ((childMethod->graphState & GRAPH_NODE_VISITED) == 0) {
14490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        createLinks(file, child->method);
14500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      }
14510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
14520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
14530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
14540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid createInclusiveProfileGraphNew(DataKeys* dataKeys) {
14560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  // create a temporary file in /tmp
14570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char path[FILENAME_MAX];
14580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.keepDotFile) {
14590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    snprintf(path, FILENAME_MAX, "%s.dot", gOptions.graphFileName);
14600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  } else {
14610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    snprintf(path, FILENAME_MAX, "dot-%d-%d.dot", (int32_t)time(nullptr), rand());
14620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
14630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  FILE* file = fopen(path, "w+");
14650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fprintf(file, "digraph g {\nnode [shape = record,height=.1];\n");
14670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  createLabels(file, dataKeys->methods);
14690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  createLinks(file, dataKeys->methods);
14700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fprintf(file, "}");
14720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fclose(file);
14730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  // now that we have the dot file generate the image
14750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char command[1024];
14760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  snprintf(command, 1024, "dot -Tpng -o \"%s\" \"%s\"", gOptions.graphFileName, path);
14770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  system(command);
14790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (!gOptions.keepDotFile) {
14810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    remove(path);
14820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
14830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
14840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
14850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid printInclusiveProfile(MethodEntry** pMethods, int32_t numMethods, uint64_t sumThreadTime) {
14860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char classBuf[HTML_BUFSIZE], methodBuf[HTML_BUFSIZE];
14870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char signatureBuf[HTML_BUFSIZE];
14880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char anchor_buf[80];
14890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* anchor_close = "";
14900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  anchor_buf[0] = 0;
14910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
14920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    anchor_close = "</a>";
14930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<a name=\"inclusive\"></a>\n");
14940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<hr>\n");
14950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    outputNavigationBar();
14960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  } else {
14970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("\n%s\n", profileSeparator);
14980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
14990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Sort the methods into decreasing order of inclusive elapsed time. */
15010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  qsort(pMethods, numMethods, sizeof(MethodEntry*), compareElapsedInclusive);
15020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("\nInclusive elapsed times for each method and its parents and children,\n");
15040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("sorted by inclusive time.\n\n");
15050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
15070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<br><br>\n<pre>\n");
15080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
15090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("index  %%/total %%/self  index     calls         usecs name\n");
15110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  double total = sumThreadTime;
15130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < numMethods; ++ii) {
15140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    char buf[40];
15150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    MethodEntry* method = pMethods[ii];
15170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Don't show methods with zero cycles */
15180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (method->elapsedInclusive == 0) break;
15190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    const char* className = method->className;
15210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    const char* methodName = method->methodName;
15220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    const char* signature = method->signature;
15230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) {
15250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("<a name=\"m%d\"></a>", method->index);
15260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      className = htmlEscape(className, classBuf, HTML_BUFSIZE);
15270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      methodName = htmlEscape(methodName, methodBuf, HTML_BUFSIZE);
15280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      signature = htmlEscape(signature, signatureBuf, HTML_BUFSIZE);
15290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
15300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("----------------------------------------------------\n");
15310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Sort and print the parents */
15330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t numCalls = method->numCalls[0] + method->numCalls[1];
15340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printInclusiveMethod(method, method->parents[0], numCalls, 0);
15350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (method->parents[1]) {
15360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("               +++++++++++++++++++++++++\n");
15370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printInclusiveMethod(method, method->parents[1], numCalls, kIsRecursive);
15380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
15390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    double per = 100.0 * method->elapsedInclusive / total;
15410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    sprintf(buf, "[%d]", ii);
15420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (method->methodName) {
15430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("%-6s %5.1f%%   %5s %6s %6d+%-6d %9" PRIu64 " %s.%s %s\n", buf,
15440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             per, "", "", method->numCalls[0], method->numCalls[1],
15450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             method->elapsedInclusive, className, methodName, signature);
15460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    } else {
15470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("%-6s %5.1f%%   %5s %6s %6d+%-6d %9" PRIu64 " %s\n", buf, per, "",
15480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             "", method->numCalls[0], method->numCalls[1],
15490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             method->elapsedInclusive, className);
15500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
15510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    double excl_per = 100.0 * method->topExclusive / method->elapsedInclusive;
15520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%6s %5s   %5.1f%% %6s %6s %6s %9" PRIu64 "\n", "", "", excl_per,
15530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao           "excl", "", "", method->topExclusive);
15540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Sort and print the children */
15560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printInclusiveMethod(method, method->children[0], 0, 0);
15570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (method->children[1]) {
15580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("               +++++++++++++++++++++++++\n");
15590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printInclusiveMethod(method, method->children[1], 0, kIsRecursive);
15600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
15610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
15620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
15630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("</pre>\n");
15640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
15650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
15660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid createClassList(TraceData* traceData, MethodEntry** pMethods, int32_t numMethods) {
15680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Sort the methods into alphabetical order to find the unique class
15690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * names.
15700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
15710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  qsort(pMethods, numMethods, sizeof(MethodEntry*), compareClassNames);
15720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Count the number of unique class names. */
15740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* currentClassName = "";
15750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* firstClassName = nullptr;
15760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  traceData->numClasses = 0;
15770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < numMethods; ++ii) {
15780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (pMethods[ii]->methodName == nullptr) {
15790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      continue;
15800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
15810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (strcmp(pMethods[ii]->className, currentClassName) != 0) {
15820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      // Remember the first one
15830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (firstClassName == nullptr) {
15840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        firstClassName = pMethods[ii]->className;
15850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      }
15860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      traceData->numClasses += 1;
15870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      currentClassName = pMethods[ii]->className;
15880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
15890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
15900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (traceData->numClasses == 0) {
15920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    traceData->classes = nullptr;
15930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return;
15940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
15950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Allocate space for all of the unique class names */
15970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  traceData->classes = new ClassEntry[traceData->numClasses];
15980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
15990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Initialize the classes array */
16000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  memset(traceData->classes, 0, sizeof(ClassEntry) * traceData->numClasses);
16010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  ClassEntry* pClass = traceData->classes;
16020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pClass->className = currentClassName = firstClassName;
16030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t prevNumMethods = 0;
16040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < numMethods; ++ii) {
16050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (pMethods[ii]->methodName == nullptr) {
16060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      continue;
16070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
16080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (strcmp(pMethods[ii]->className, currentClassName) != 0) {
16090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pClass->numMethods = prevNumMethods;
16100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      (++pClass)->className = currentClassName = pMethods[ii]->className;
16110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      prevNumMethods = 0;
16120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
16130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    prevNumMethods += 1;
16140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
16150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pClass->numMethods = prevNumMethods;
16160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
16170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Create the array of MethodEntry pointers for each class */
16180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pClass = nullptr;
16190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  currentClassName = "";
16200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t nextMethod = 0;
16210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < numMethods; ++ii) {
16220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (pMethods[ii]->methodName == nullptr) {
16230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      continue;
16240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
16250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (strcmp(pMethods[ii]->className, currentClassName) != 0) {
16260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      currentClassName = pMethods[ii]->className;
16270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (pClass == nullptr)
16280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        pClass = traceData->classes;
16290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      else
16300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        pClass++;
16310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      /* Allocate space for the methods array */
16320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pClass->methods = new MethodEntry*[pClass->numMethods];
16330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      nextMethod = 0;
16340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
16350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pClass->methods[nextMethod++] = pMethods[ii];
16360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
16370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
16380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
16390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/* Prints a number of html non-breaking spaces according so that the length
16400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * of the string "buf" is at least "width" characters wide.  If width is
16410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * negative, then trailing spaces are added instead of leading spaces.
16420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
16430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid printHtmlField(char* buf, int32_t width) {
16440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t leadingSpaces = 1;
16450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (width < 0) {
16460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    width = -width;
16470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    leadingSpaces = 0;
16480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
16490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t len = strlen(buf);
16500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t numSpaces = width - len;
16510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (numSpaces <= 0) {
16520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%s", buf);
16530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return;
16540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
16550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (leadingSpaces == 0) printf("%s", buf);
16560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < numSpaces; ++ii) printf("&nbsp;");
16570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (leadingSpaces == 1) printf("%s", buf);
16580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
16590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
16600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid printClassProfiles(TraceData* traceData, uint64_t sumThreadTime) {
16610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char classBuf[HTML_BUFSIZE];
16620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char methodBuf[HTML_BUFSIZE];
16630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char signatureBuf[HTML_BUFSIZE];
16640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
16650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
16660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<a name=\"class\"></a>\n");
16670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<hr>\n");
16680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    outputNavigationBar();
16690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  } else {
16700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("\n%s\n", profileSeparator);
16710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
16720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
16730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (traceData->numClasses == 0) {
16740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("\nNo classes.\n");
16750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) {
16760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("<br><br>\n");
16770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
16780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return;
16790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
16800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
16810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("\nExclusive elapsed time for each class, summed over all the methods\n");
16820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("in the class.\n\n");
16830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
16840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<br><br>\n");
16850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
16860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
16870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* For each class, sum the exclusive times in all of the methods
16880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * in that class.  Also sum the number of method calls.  Also
16890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * sort the methods so the most expensive appear at the top.
16900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
16910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  ClassEntry* pClass = traceData->classes;
16920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < traceData->numClasses; ++ii, ++pClass) {
16930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    // printf("%s %d methods\n", pClass->className, pClass->numMethods);
16940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t numMethods = pClass->numMethods;
16950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    for (int32_t jj = 0; jj < numMethods; ++jj) {
16960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      MethodEntry* method = pClass->methods[jj];
16970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pClass->elapsedExclusive += method->elapsedExclusive;
16980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pClass->numCalls[0] += method->numCalls[0];
16990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pClass->numCalls[1] += method->numCalls[1];
17000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
17010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
17020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Sort the methods into decreasing order of exclusive time */
17030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    qsort(pClass->methods, numMethods, sizeof(MethodEntry*), compareElapsedExclusive);
17040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
17050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
17060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Allocate an array of pointers to the classes for more efficient sorting. */
17070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  ClassEntry** pClasses = new ClassEntry*[traceData->numClasses];
17080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < traceData->numClasses; ++ii)
17090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pClasses[ii] = &traceData->classes[ii];
17100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
17110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Sort the classes into decreasing order of exclusive time */
17120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  qsort(pClasses, traceData->numClasses, sizeof(ClassEntry*), compareClassExclusive);
17130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
17140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
17150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf(
17160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        "<div class=\"header\"><span "
17170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        "class=\"parent\">&nbsp;</span>&nbsp;&nbsp;&nbsp;");
17180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("Cycles %%/total Cumul.%% &nbsp;Calls+Recur&nbsp; Class</div>\n");
17190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  } else {
17200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("   Cycles %%/total Cumul.%%  Calls+Recur  Class\n");
17210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
17220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
17230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  double sum = 0;
17240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  double total = sumThreadTime;
17250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < traceData->numClasses; ++ii) {
17260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Skip classes with zero cycles */
17270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pClass = pClasses[ii];
17280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (pClass->elapsedExclusive == 0) break;
17290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
17300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    sum += pClass->elapsedExclusive;
17310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    double per = 100.0 * pClass->elapsedExclusive / total;
17320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    double sum_per = 100.0 * sum / total;
17330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    const char* className = pClass->className;
17340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) {
17350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      char buf[80];
17360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
17370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      className = htmlEscape(className, classBuf, HTML_BUFSIZE);
17380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf(
17390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "<div class=\"link\" onClick=\"javascript:toggle('d%d')\" "
17400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "onMouseOver=\"javascript:onMouseOver(this)\" "
17410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "onMouseOut=\"javascript:onMouseOut(this)\"><span class=\"parent\" "
17420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "id=\"xd%d\">+</span>",
17430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          ii, ii);
17440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sprintf(buf, "%" PRIu64, pClass->elapsedExclusive);
17450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printHtmlField(buf, 9);
17460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf(" ");
17470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sprintf(buf, "%.1f", per);
17480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printHtmlField(buf, 7);
17490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf(" ");
17500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sprintf(buf, "%.1f", sum_per);
17510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printHtmlField(buf, 7);
17520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf(" ");
17530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sprintf(buf, "%d", pClass->numCalls[0]);
17540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printHtmlField(buf, 6);
17550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("+");
17560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sprintf(buf, "%d", pClass->numCalls[1]);
17570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printHtmlField(buf, -6);
17580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf(" ");
17590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("%s", className);
17600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("</div>\n");
17610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("<div class=\"parent\" id=\"d%d\">\n", ii);
17620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    } else {
17630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("---------------------------------------------\n");
17640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("%9" PRIu64 " %7.1f %7.1f %6d+%-6d %s\n", pClass->elapsedExclusive,
17650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             per, sum_per, pClass->numCalls[0], pClass->numCalls[1], className);
17660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
17670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
17680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t numMethods = pClass->numMethods;
17690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    double classExclusive = pClass->elapsedExclusive;
17700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    double sumMethods = 0;
17710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    for (int32_t jj = 0; jj < numMethods; ++jj) {
17720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      MethodEntry* method = pClass->methods[jj];
17730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      const char* methodName = method->methodName;
17740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      const char* signature = method->signature;
17750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      per = 100.0 * method->elapsedExclusive / classExclusive;
17760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sumMethods += method->elapsedExclusive;
17770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sum_per = 100.0 * sumMethods / classExclusive;
17780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (gOptions.outputHtml) {
17790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        char buf[80];
17800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
17810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        methodName = htmlEscape(methodName, methodBuf, HTML_BUFSIZE);
17820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        signature = htmlEscape(signature, signatureBuf, HTML_BUFSIZE);
17830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("<div class=\"leaf\"><span class=\"leaf\">&nbsp;</span>");
17840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        sprintf(buf, "%" PRIu64, method->elapsedExclusive);
17850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printHtmlField(buf, 9);
17860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("&nbsp;");
17870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        sprintf(buf, "%" PRIu64, method->elapsedInclusive);
17880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printHtmlField(buf, 9);
17890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("&nbsp;");
17900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        sprintf(buf, "%.1f", per);
17910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printHtmlField(buf, 7);
17920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("&nbsp;");
17930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        sprintf(buf, "%.1f", sum_per);
17940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printHtmlField(buf, 7);
17950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("&nbsp;");
17960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        sprintf(buf, "%d", method->numCalls[0]);
17970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printHtmlField(buf, 6);
17980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("+");
17990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        sprintf(buf, "%d", method->numCalls[1]);
18000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printHtmlField(buf, -6);
18010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("&nbsp;");
18020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("<a href=\"#m%d\">[%d]</a>&nbsp;%s&nbsp;%s", method->index,
18030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               method->index, methodName, signature);
18040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("</div>\n");
18050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      } else {
18060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("%9" PRIu64 " %9" PRIu64 " %7.1f %7.1f %6d+%-6d [%d] %s %s\n",
18070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               method->elapsedExclusive, method->elapsedInclusive, per, sum_per,
18080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               method->numCalls[0], method->numCalls[1], method->index,
18090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               methodName, signature);
18100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      }
18110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
18120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) {
18130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("</div>\n");
18140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
18150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
18160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
18170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
18180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid createUniqueMethodList(TraceData* traceData, MethodEntry** pMethods, int32_t numMethods) {
18190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Sort the methods into alphabetical order of method names
18200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * to find the unique method names.
18210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
18220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  qsort(pMethods, numMethods, sizeof(MethodEntry*), compareMethodNames);
18230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
18240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Count the number of unique method names, ignoring class and signature. */
18250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const char* currentMethodName = "";
18260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  traceData->numUniqueMethods = 0;
18270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < numMethods; ++ii) {
18280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (pMethods[ii]->methodName == nullptr) continue;
18290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (strcmp(pMethods[ii]->methodName, currentMethodName) != 0) {
18300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      traceData->numUniqueMethods += 1;
18310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      currentMethodName = pMethods[ii]->methodName;
18320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
18330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
18340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (traceData->numUniqueMethods == 0) return;
18350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
18360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Allocate space for pointers to all of the unique methods */
18370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  traceData->uniqueMethods = new UniqueMethodEntry[traceData->numUniqueMethods];
18380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
18390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Initialize the uniqueMethods array */
18400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  memset(traceData->uniqueMethods, 0, sizeof(UniqueMethodEntry) * traceData->numUniqueMethods);
18410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  UniqueMethodEntry* pUnique = traceData->uniqueMethods;
18420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  currentMethodName = nullptr;
18430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t prevNumMethods = 0;
18440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < numMethods; ++ii) {
18450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (pMethods[ii]->methodName == nullptr) continue;
18460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (currentMethodName == nullptr) currentMethodName = pMethods[ii]->methodName;
18470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (strcmp(pMethods[ii]->methodName, currentMethodName) != 0) {
18480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      currentMethodName = pMethods[ii]->methodName;
18490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pUnique->numMethods = prevNumMethods;
18500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pUnique++;
18510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      prevNumMethods = 0;
18520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
18530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    prevNumMethods += 1;
18540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
18550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pUnique->numMethods = prevNumMethods;
18560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
18570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Create the array of MethodEntry pointers for each unique method */
18580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  pUnique = nullptr;
18590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  currentMethodName = "";
18600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t nextMethod = 0;
18610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < numMethods; ++ii) {
18620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (pMethods[ii]->methodName == nullptr) continue;
18630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (strcmp(pMethods[ii]->methodName, currentMethodName) != 0) {
18640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      currentMethodName = pMethods[ii]->methodName;
18650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (pUnique == nullptr)
18660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        pUnique = traceData->uniqueMethods;
18670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      else
18680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        pUnique++;
18690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      /* Allocate space for the methods array */
18700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pUnique->methods = new MethodEntry*[pUnique->numMethods];
18710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      nextMethod = 0;
18720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
18730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pUnique->methods[nextMethod++] = pMethods[ii];
18740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
18750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
18760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
18770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid printMethodProfiles(TraceData* traceData, uint64_t sumThreadTime) {
18780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char classBuf[HTML_BUFSIZE], methodBuf[HTML_BUFSIZE];
18790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char signatureBuf[HTML_BUFSIZE];
18800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
18810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (traceData->numUniqueMethods == 0) return;
18820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
18830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
18840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<a name=\"method\"></a>\n");
18850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<hr>\n");
18860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    outputNavigationBar();
18870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  } else {
18880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("\n%s\n", profileSeparator);
18890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
18900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
18910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("\nExclusive elapsed time for each method, summed over all the classes\n");
18920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("that contain a method with the same name.\n\n");
18930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
18940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<br><br>\n");
18950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
18960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
18970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* For each unique method, sum the exclusive times in all of the methods
18980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * with the same name.  Also sum the number of method calls.  Also
18990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * sort the methods so the most expensive appear at the top.
19000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
19010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  UniqueMethodEntry* pUnique = traceData->uniqueMethods;
19020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < traceData->numUniqueMethods; ++ii, ++pUnique) {
19030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t numMethods = pUnique->numMethods;
19040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    for (int32_t jj = 0; jj < numMethods; ++jj) {
19050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      MethodEntry* method = pUnique->methods[jj];
19060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pUnique->elapsedExclusive += method->elapsedExclusive;
19070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pUnique->numCalls[0] += method->numCalls[0];
19080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pUnique->numCalls[1] += method->numCalls[1];
19090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
19100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
19110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Sort the methods into decreasing order of exclusive time */
19120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    qsort(pUnique->methods, numMethods, sizeof(MethodEntry*), compareElapsedExclusive);
19130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
19140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
19150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Allocate an array of pointers to the methods for more efficient sorting. */
19160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  UniqueMethodEntry** pUniqueMethods = new UniqueMethodEntry*[traceData->numUniqueMethods];
19170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < traceData->numUniqueMethods; ++ii)
19180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pUniqueMethods[ii] = &traceData->uniqueMethods[ii];
19190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
19200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Sort the methods into decreasing order of exclusive time */
19210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  qsort(pUniqueMethods, traceData->numUniqueMethods, sizeof(UniqueMethodEntry*),
19220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        compareUniqueExclusive);
19230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
19240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
19250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf(
19260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        "<div class=\"header\"><span "
19270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        "class=\"parent\">&nbsp;</span>&nbsp;&nbsp;&nbsp;");
19280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("Cycles %%/total Cumul.%% &nbsp;Calls+Recur&nbsp; Method</div>\n");
19290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  } else {
19300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("   Cycles %%/total Cumul.%%  Calls+Recur  Method\n");
19310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
19320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
19330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  double sum = 0;
19340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  double total = sumThreadTime;
19350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < traceData->numUniqueMethods; ++ii) {
19360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Skip methods with zero cycles */
19370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pUnique = pUniqueMethods[ii];
19380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (pUnique->elapsedExclusive == 0) break;
19390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
19400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    sum += pUnique->elapsedExclusive;
19410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    double per = 100.0 * pUnique->elapsedExclusive / total;
19420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    double sum_per = 100.0 * sum / total;
19430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    const char* methodName = pUnique->methods[0]->methodName;
19440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) {
19450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      char buf[80];
19460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
19470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      methodName = htmlEscape(methodName, methodBuf, HTML_BUFSIZE);
19480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf(
19490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "<div class=\"link\" onClick=\"javascript:toggle('e%d')\" "
19500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "onMouseOver=\"javascript:onMouseOver(this)\" "
19510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "onMouseOut=\"javascript:onMouseOut(this)\"><span class=\"parent\" "
19520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "id=\"xe%d\">+</span>",
19530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          ii, ii);
19540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sprintf(buf, "%" PRIu64, pUnique->elapsedExclusive);
19550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printHtmlField(buf, 9);
19560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf(" ");
19570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sprintf(buf, "%.1f", per);
19580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printHtmlField(buf, 7);
19590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf(" ");
19600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sprintf(buf, "%.1f", sum_per);
19610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printHtmlField(buf, 7);
19620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf(" ");
19630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sprintf(buf, "%d", pUnique->numCalls[0]);
19640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printHtmlField(buf, 6);
19650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("+");
19660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sprintf(buf, "%d", pUnique->numCalls[1]);
19670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printHtmlField(buf, -6);
19680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf(" ");
19690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("%s", methodName);
19700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("</div>\n");
19710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("<div class=\"parent\" id=\"e%d\">\n", ii);
19720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    } else {
19730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("---------------------------------------------\n");
19740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("%9" PRIu64 " %7.1f %7.1f %6d+%-6d %s\n",
19750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             pUnique->elapsedExclusive, per, sum_per, pUnique->numCalls[0],
19760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao             pUnique->numCalls[1], methodName);
19770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
19780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t numMethods = pUnique->numMethods;
19790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    double methodExclusive = pUnique->elapsedExclusive;
19800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    double sumMethods = 0;
19810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    for (int32_t jj = 0; jj < numMethods; ++jj) {
19820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      MethodEntry* method = pUnique->methods[jj];
19830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      const char* className = method->className;
19840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      const char* signature = method->signature;
19850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      per = 100.0 * method->elapsedExclusive / methodExclusive;
19860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sumMethods += method->elapsedExclusive;
19870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      sum_per = 100.0 * sumMethods / methodExclusive;
19880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (gOptions.outputHtml) {
19890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        char buf[80];
19900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
19910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        className = htmlEscape(className, classBuf, HTML_BUFSIZE);
19920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        signature = htmlEscape(signature, signatureBuf, HTML_BUFSIZE);
19930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("<div class=\"leaf\"><span class=\"leaf\">&nbsp;</span>");
19940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        sprintf(buf, "%" PRIu64, method->elapsedExclusive);
19950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printHtmlField(buf, 9);
19960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("&nbsp;");
19970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        sprintf(buf, "%" PRIu64, method->elapsedInclusive);
19980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printHtmlField(buf, 9);
19990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("&nbsp;");
20000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        sprintf(buf, "%.1f", per);
20010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printHtmlField(buf, 7);
20020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("&nbsp;");
20030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        sprintf(buf, "%.1f", sum_per);
20040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printHtmlField(buf, 7);
20050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("&nbsp;");
20060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        sprintf(buf, "%d", method->numCalls[0]);
20070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printHtmlField(buf, 6);
20080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("+");
20090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        sprintf(buf, "%d", method->numCalls[1]);
20100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printHtmlField(buf, -6);
20110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("&nbsp;");
20120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("<a href=\"#m%d\">[%d]</a>&nbsp;%s.%s&nbsp;%s", method->index,
20130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               method->index, className, methodName, signature);
20140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("</div>\n");
20150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      } else {
20160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        printf("%9" PRIu64 " %9" PRIu64 " %7.1f %7.1f %6d+%-6d [%d] %s.%s %s\n",
20170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               method->elapsedExclusive, method->elapsedInclusive, per, sum_per,
20180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               method->numCalls[0], method->numCalls[1], method->index,
20190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao               className, methodName, signature);
20200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      }
20210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
20220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) {
20230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printf("</div>\n");
20240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
20250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
20260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
20270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
20280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
20290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Read the key and data files and return the MethodEntries for those files
20300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
20310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff HaoDataKeys* parseDataKeys(TraceData* traceData, const char* traceFileName, uint64_t* threadTime) {
20320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  MethodEntry* caller;
20330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
20340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  FILE* dataFp = fopen(traceFileName, "rb");
20350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (dataFp == nullptr) return nullptr;
20360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
20370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  DataKeys* dataKeys = parseKeys(dataFp, 0);
20380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (dataKeys == nullptr) {
20390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fclose(dataFp);
20400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return nullptr;
20410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
20420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
20430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  DataHeader dataHeader;
20440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (parseDataHeader(dataFp, &dataHeader) < 0) {
20450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fclose(dataFp);
20460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return dataKeys;
20470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
20480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
20490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#if 0
20500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  FILE* dumpStream = fopen("debug", "w");
20510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#endif
20520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  while (1) {
20530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /*
20540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao     * Extract values from file.
20550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao     */
20560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t threadId;
20570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    uint32_t methodVal;
20580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    uint64_t currentTime;
20590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (readDataRecord(dataFp, &dataHeader, &threadId, &methodVal, &currentTime))
20600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      break;
20610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
20620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t action = METHOD_ACTION(methodVal);
20630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int64_t methodId = METHOD_ID(methodVal);
20640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
20650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Get the call stack for this thread */
20660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    CallStack* pStack = traceData->stacks[threadId];
20670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
20680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* If there is no call stack yet for this thread, then allocate one */
20690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (pStack == nullptr) {
20700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pStack = new CallStack();
20710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pStack->top = 0;
20720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pStack->lastEventTime = currentTime;
20730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pStack->threadStartTime = currentTime;
20740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      traceData->stacks[threadId] = pStack;
20750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
20760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
20770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Lookup the current method */
20780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    MethodEntry* method = lookupMethod(dataKeys, methodId);
20790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (method == nullptr) method = &dataKeys->methods[UNKNOWN_INDEX];
20800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
20810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#if 0
20820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (method->methodName) {
20830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      fprintf(dumpStream, "%2d %-8llu %d %8llu r %d c %d %s.%s %s\n",
20840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao              threadId, currentTime, action, pStack->threadStartTime,
20850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao              method->recursiveEntries,
20860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao              pStack->top, method->className, method->methodName,
20870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao              method->signature);
20880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    } else {
20890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      fprintf(dumpStream, "%2d %-8llu %d %8llu r %d c %d %s\n",
20900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao              threadId, currentTime, action, pStack->threadStartTime,
20910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao              method->recursiveEntries,
20920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao              pStack->top, method->className);
20930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
20940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#endif
20950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
20960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (action == METHOD_TRACE_ENTER) {
20970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      /* This is a method entry */
20980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (pStack->top >= MAX_STACK_DEPTH) {
20990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        fprintf(stderr, "Stack overflow (exceeded %d frames)\n",
21000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                MAX_STACK_DEPTH);
21010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        exit(1);
21020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      }
21030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
21040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      /* Get the caller method */
21050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (pStack->top >= 1)
21060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        caller = pStack->calls[pStack->top - 1].method;
21070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      else
21080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        caller = &dataKeys->methods[TOPLEVEL_INDEX];
21090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      countRecursiveEntries(pStack, pStack->top, caller);
21100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      caller->elapsedExclusive += currentTime - pStack->lastEventTime;
21110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#if 0
21120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (caller->elapsedExclusive > 10000000)
21130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        fprintf(dumpStream, "%llu current %llu last %llu diff %llu\n",
21140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                caller->elapsedExclusive, currentTime,
21150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                pStack->lastEventTime,
21160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                currentTime - pStack->lastEventTime);
21170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#endif
21180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (caller->recursiveEntries <= 1) {
21190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        caller->topExclusive += currentTime - pStack->lastEventTime;
21200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      }
21210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
21220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      /* Push the method on the stack for this thread */
21230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pStack->calls[pStack->top].method = method;
21240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      pStack->calls[pStack->top++].entryTime = currentTime;
21250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    } else {
21260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      /* This is a method exit */
21270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      uint64_t entryTime = 0;
21280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
21290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      /* Pop the method off the stack for this thread */
21300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (pStack->top > 0) {
21310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        pStack->top -= 1;
21320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        entryTime = pStack->calls[pStack->top].entryTime;
21330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        if (method != pStack->calls[pStack->top].method) {
21340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          if (method->methodName) {
21350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao            fprintf(stderr, "Exit from method %s.%s %s does not match stack:\n",
21360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                    method->className, method->methodName, method->signature);
21370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          } else {
21380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao            fprintf(stderr, "Exit from method %s does not match stack:\n",
21390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                    method->className);
21400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          }
21410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          stackDump(pStack, pStack->top + 1);
21420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          exit(1);
21430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        }
21440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      }
21450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
21460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      /* Get the caller method */
21470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (pStack->top >= 1)
21480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        caller = pStack->calls[pStack->top - 1].method;
21490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      else
21500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        caller = &dataKeys->methods[TOPLEVEL_INDEX];
21510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      countRecursiveEntries(pStack, pStack->top, caller);
21520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      countRecursiveEntries(pStack, pStack->top, method);
21530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      uint64_t elapsed = currentTime - entryTime;
21540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      addInclusiveTime(caller, method, elapsed);
21550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      method->elapsedExclusive += currentTime - pStack->lastEventTime;
21560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (method->recursiveEntries == 0) {
21570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        method->topExclusive += currentTime - pStack->lastEventTime;
21580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      }
21590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
21600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Remember the time of the last entry or exit event */
21610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pStack->lastEventTime = currentTime;
21620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
21630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
21640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* If we have calls on the stack when the trace ends, then clean
21650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * up the stack and add time to the callers by pretending that we
21660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * are exiting from their methods now.
21670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
21680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t sumThreadTime = 0;
21690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t threadId = 0; threadId < MAX_THREADS; ++threadId) {
21700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    CallStack* pStack = traceData->stacks[threadId];
21710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
21720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* If this thread never existed, then continue with next thread */
21730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (pStack == nullptr) continue;
21740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
21750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    /* Also, add up the time taken by all of the threads */
21760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    sumThreadTime += pStack->lastEventTime - pStack->threadStartTime;
21770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
21780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    for (int32_t ii = 0; ii < pStack->top; ++ii) {
21790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (ii == 0)
21800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        caller = &dataKeys->methods[TOPLEVEL_INDEX];
21810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      else
21820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        caller = pStack->calls[ii - 1].method;
21830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      MethodEntry* method = pStack->calls[ii].method;
21840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      countRecursiveEntries(pStack, ii, caller);
21850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      countRecursiveEntries(pStack, ii, method);
21860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
21870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      uint64_t entryTime = pStack->calls[ii].entryTime;
21880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      uint64_t elapsed = pStack->lastEventTime - entryTime;
21890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      addInclusiveTime(caller, method, elapsed);
21900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
21910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
21920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  caller = &dataKeys->methods[TOPLEVEL_INDEX];
21930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  caller->elapsedInclusive = sumThreadTime;
21940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
21950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#if 0
21960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fclose(dumpStream);
21970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao#endif
21980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
21990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (threadTime != nullptr) {
22000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    *threadTime = sumThreadTime;
22010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
22020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fclose(dataFp);
22040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return dataKeys;
22050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
22060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff HaoMethodEntry** parseMethodEntries(DataKeys* dataKeys) {
22080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Create a new array of pointers to the methods and sort the pointers
22090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * instead of the actual MethodEntry structs.  We need to do this
22100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * because there are other lists that contain pointers to the
22110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   * MethodEntry structs.
22120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao   */
22130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  MethodEntry** pMethods = new MethodEntry*[dataKeys->numMethods];
22140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t ii = 0; ii < dataKeys->numMethods; ++ii) {
22150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    MethodEntry* entry = &dataKeys->methods[ii];
22160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    pMethods[ii] = entry;
22170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
22180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return pMethods;
22200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
22210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
22230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Produce a function profile from the following methods
22240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
22250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid profileTrace(TraceData* traceData, MethodEntry** pMethods, int32_t numMethods,
22260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                  uint64_t sumThreadTime) {
22270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  /* Print the html header, if necessary */
22280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
22290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf(htmlHeader, gOptions.sortableUrl);
22300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    outputTableOfContents();
22310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
22320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printExclusiveProfile(pMethods, numMethods, sumThreadTime);
22340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printInclusiveProfile(pMethods, numMethods, sumThreadTime);
22350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  createClassList(traceData, pMethods, numMethods);
22370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printClassProfiles(traceData, sumThreadTime);
22380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  createUniqueMethodList(traceData, pMethods, numMethods);
22400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printMethodProfiles(traceData, sumThreadTime);
22410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
22430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%s", htmlFooter);
22440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
22450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
22460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t compareMethodNamesForDiff(const void* a, const void* b) {
22480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const MethodEntry* methodA = *(const MethodEntry**) a;
22490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const MethodEntry* methodB = *(const MethodEntry**) b;
22500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (methodA->methodName == nullptr || methodB->methodName == nullptr) {
22510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return compareClassNames(a, b);
22520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
22530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t result = strcmp(methodA->methodName, methodB->methodName);
22540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (result == 0) {
22550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    result = strcmp(methodA->signature, methodB->signature);
22560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (result == 0) {
22570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      return strcmp(methodA->className, methodB->className);
22580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
22590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
22600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return result;
22610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
22620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t findMatch(MethodEntry** methods, int32_t size, MethodEntry* matchThis) {
22640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t i = 0; i < size; i++) {
22650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    MethodEntry* method = methods[i];
22660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (method != nullptr && !compareMethodNamesForDiff(&method, &matchThis)) {
22680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      // printf("%s.%s == %s.%s<br>\n", matchThis->className, matchThis->methodName,
22690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      //        method->className, method->methodName);
22700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      return i;
22720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      // if (!compareMethodNames(&method, &matchThis)) return i;
22730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
22740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
22750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return -1;
22770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
22780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t compareDiffEntriesExculsive(const void* a, const void* b) {
22800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const DiffEntry* entryA = (const DiffEntry*) a;
22810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const DiffEntry* entryB = (const DiffEntry*) b;
22820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (entryA->differenceExclusive < entryB->differenceExclusive) {
22840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return 1;
22850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  } else if (entryA->differenceExclusive > entryB->differenceExclusive) {
22860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return -1;
22870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
22880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return 0;
22900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
22910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t compareDiffEntriesInculsive(const void* a, const void* b) {
22930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const DiffEntry* entryA = (const DiffEntry*) a;
22940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  const DiffEntry* entryB = (const DiffEntry*) b;
22950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
22960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (entryA->differenceInclusive < entryB->differenceInclusive) {
22970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return 1;
22980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  } else if (entryA->differenceInclusive > entryB->differenceInclusive) {
22990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return -1;
23000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
23010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return 0;
23030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
23040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid printMissingMethod(MethodEntry* method) {
23060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char classBuf[HTML_BUFSIZE];
23070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char methodBuf[HTML_BUFSIZE];
23080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char* className = htmlEscape(method->className, classBuf, HTML_BUFSIZE);
23100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char* methodName = htmlEscape(method->methodName, methodBuf, HTML_BUFSIZE);
23110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) printf("<tr><td>\n");
23130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("%s.%s ", className, methodName);
23150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) printf("</td><td>");
23160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("%" PRIu64 " ", method->elapsedExclusive);
23180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) printf("</td><td>");
23190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("%" PRIu64 " ", method->elapsedInclusive);
23210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) printf("</td><td>");
23220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  printf("%d\n", method->numCalls[0]);
23240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) printf("</td><td>\n");
23250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
23260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haovoid createDiff(DataKeys* d1, DataKeys* d2) {
23280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  MethodEntry** methods1 = parseMethodEntries(d1);
23290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  MethodEntry** methods2 = parseMethodEntries(d2);
23300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  // sort and assign the indicies
23320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  qsort(methods1, d1->numMethods, sizeof(MethodEntry*), compareElapsedInclusive);
23330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t i = 0; i < d1->numMethods; ++i) {
23340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    methods1[i]->index = i;
23350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
23360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  qsort(methods2, d2->numMethods, sizeof(MethodEntry*), compareElapsedInclusive);
23380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t i = 0; i < d2->numMethods; ++i) {
23390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    methods2[i]->index = i;
23400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
23410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t max = (d1->numMethods < d2->numMethods) ? d2->numMethods : d1->numMethods;
23430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  max++;
23440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  DiffEntry* diffs = new DiffEntry[max];
23450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  memset(diffs, 0, max * sizeof(DiffEntry));
23460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  DiffEntry* ptr = diffs;
23470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  // printf("<br>d1->numMethods: %d d1->numMethods: %d<br>\n",
23490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  //        d1->numMethods, d2->numMethods);
23500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  int32_t matches = 0;
23520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t i = 0; i < d1->numMethods; i++) {
23540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t match = findMatch(methods2, d2->numMethods, methods1[i]);
23550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (match >= 0) {
23560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      ptr->method1 = methods1[i];
23570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      ptr->method2 = methods2[match];
23580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      uint64_t e1 = ptr->method1->elapsedExclusive;
23600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      uint64_t e2 = ptr->method2->elapsedExclusive;
23610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (e1 > 0) {
23620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        ptr->differenceExclusive = e2 - e1;
23630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        ptr->differenceExclusivePercentage = (static_cast<double>(e2) /
23640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                                              static_cast<double>(e1)) * 100.0;
23650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      }
23660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      uint64_t i1 = ptr->method1->elapsedInclusive;
23680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      uint64_t i2 = ptr->method2->elapsedInclusive;
23690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      if (i1 > 0) {
23700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        ptr->differenceInclusive = i2 - i1;
23710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        ptr->differenceInclusivePercentage = (static_cast<double>(i2) /
23720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao                                              static_cast<double>(i1)) * 100.0;
23730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      }
23740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      // clear these out so we don't find them again and we know which ones
23760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      // we have left over
23770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      methods1[i] = nullptr;
23780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      methods2[match] = nullptr;
23790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      ptr++;
23800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      matches++;
23820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
23830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
23840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  ptr->method1 = nullptr;
23850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  ptr->method2 = nullptr;
23860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  qsort(diffs, matches, sizeof(DiffEntry), compareDiffEntriesExculsive);
23880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  ptr = diffs;
23890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
23900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
23910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf(htmlHeader, gOptions.sortableUrl);
23920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<h3>Table of Contents</h3>\n");
23930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<ul>\n");
23940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<li><a href='#exclusive'>Exclusive</a>\n");
23950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<li><a href='#inclusive'>Inclusive</a>\n");
23960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("</ul>\n");
23970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("Run 1: %s<br>\n", gOptions.diffFileName);
23980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("Run 2: %s<br>\n", gOptions.traceFileName);
23990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<a name=\"exclusive\"></a><h3 id=\"exclusive\">Exclusive</h3>\n");
24000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf(tableHeader, "exclusive_table");
24010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
24020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char classBuf[HTML_BUFSIZE];
24040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  char methodBuf[HTML_BUFSIZE];
24050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  while (ptr->method1 != nullptr && ptr->method2 != nullptr) {
24060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("<tr><td>\n");
24070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    char* className = htmlEscape(ptr->method1->className, classBuf, HTML_BUFSIZE);
24090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    char* methodName = htmlEscape(ptr->method1->methodName, methodBuf, HTML_BUFSIZE);
24100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%s.%s ", className, methodName);
24120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("</td><td>");
24130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%" PRIu64 " ", ptr->method1->elapsedExclusive);
24150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("</td><td>");
24160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%" PRIu64 " ", ptr->method2->elapsedExclusive);
24180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("</td><td>");
24190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%" PRIu64 " ", ptr->differenceExclusive);
24210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("</td><td>");
24220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%.2f\n", ptr->differenceExclusivePercentage);
24240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("</td><td>\n");
24250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%d\n", ptr->method1->numCalls[0]);
24270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("</td><td>\n");
24280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%d\n", ptr->method2->numCalls[0]);
24300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("</td></tr>\n");
24310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    ptr++;
24330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
24340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) printf("</table>\n");
24360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
24380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf(htmlHeader, gOptions.sortableUrl);
24390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("Run 1: %s<br>\n", gOptions.diffFileName);
24400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("Run 2: %s<br>\n", gOptions.traceFileName);
24410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<a name=\"inclusive\"></a><h3 id=\"inculisve\">Inclusive</h3>\n");
24420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf(tableHeader, "inclusive_table");
24430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
24440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  qsort(diffs, matches, sizeof(DiffEntry), compareDiffEntriesInculsive);
24460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  ptr = diffs;
24470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  while (ptr->method1 != nullptr && ptr->method2 != nullptr) {
24490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("<tr><td>\n");
24500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    char* className = htmlEscape(ptr->method1->className, classBuf, HTML_BUFSIZE);
24520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    char* methodName = htmlEscape(ptr->method1->methodName, methodBuf, HTML_BUFSIZE);
24530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%s.%s ", className, methodName);
24550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("</td><td>");
24560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%" PRIu64 " ", ptr->method1->elapsedInclusive);
24580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("</td><td>");
24590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%" PRIu64 " ", ptr->method2->elapsedInclusive);
24610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("</td><td>");
24620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%" PRIu64 " ", ptr->differenceInclusive);
24640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("</td><td>");
24650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%.2f\n", ptr->differenceInclusivePercentage);
24670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("</td><td>\n");
24680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%d\n", ptr->method1->numCalls[0]);
24700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("</td><td>\n");
24710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("%d\n", ptr->method2->numCalls[0]);
24730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.outputHtml) printf("</td></tr>\n");
24740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    ptr++;
24760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
24770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
24790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("</table>\n");
24800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<h3>Run 1 methods not found in Run 2</h3>");
24810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf(tableHeaderMissing, "?");
24820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
24830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t i = 0; i < d1->numMethods; ++i) {
24850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (methods1[i] != nullptr) {
24860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printMissingMethod(methods1[i]);
24870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
24880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
24890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) {
24910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("</table>\n");
24920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf("<h3>Run 2 methods not found in Run 1</h3>");
24930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    printf(tableHeaderMissing, "?");
24940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
24950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
24960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  for (int32_t i = 0; i < d2->numMethods; ++i) {
24970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (methods2[i] != nullptr) {
24980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      printMissingMethod(methods2[i]);
24990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
25000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
25010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
25020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.outputHtml) printf("</body></html\n");
25030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
25040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
25050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t usage(const char* program) {
25060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fprintf(stderr, "Copyright (C) 2006 The Android Open Source Project\n\n");
25070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fprintf(stderr,
25080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "usage: %s [-ho] [-s sortable] [-d trace-file-name] [-g outfile] "
25090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "trace-file-name\n",
25100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          program);
25110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fprintf(stderr, "  -d trace-file-name  - Diff with this trace\n");
25120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fprintf(stderr, "  -g outfile          - Write graph to 'outfile'\n");
25130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fprintf(stderr,
25140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "  -k                  - When writing a graph, keep the intermediate "
25150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "DOT file\n");
25160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fprintf(stderr, "  -h                  - Turn on HTML output\n");
25170ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fprintf(
25180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      stderr,
25190ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      "  -o                  - Dump the dmtrace file instead of profiling\n");
25200ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fprintf(stderr,
25210ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "  -s                  - URL base to where the sortable javascript "
25220ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "file\n");
25230ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  fprintf(stderr,
25240ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "  -t threshold        - Threshold percentage for including nodes in "
25250ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao          "the graph\n");
25260ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return 2;
25270ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
25280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
25290ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao// Returns true if there was an error
25300ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t parseOptions(int32_t argc, char** argv) {
25310ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  while (1) {
25320ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    int32_t opt = getopt(argc, argv, "d:hg:kos:t:");
25330ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (opt == -1) break;
25340ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    switch (opt) {
25350ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      case 'd':
25360ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        gOptions.diffFileName = optarg;
25370ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        break;
25380ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      case 'g':
25390ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        gOptions.graphFileName = optarg;
25400ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        break;
25410ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      case 'k':
25420ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        gOptions.keepDotFile = 1;
25430ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        break;
25440ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      case 'h':
25450ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        gOptions.outputHtml = 1;
25460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        break;
25470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      case 'o':
25480ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        gOptions.dump = 1;
25490ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        break;
25500ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      case 's':
25510ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        gOptions.sortableUrl = optarg;
25520ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        break;
25530ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      case 't':
25540ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        gOptions.threshold = atoi(optarg);
25550ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        break;
25560ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      default:
25570ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao        return 1;
25580ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
25590ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
25600ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return 0;
25610ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
25620ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
25630ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao/*
25640ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * Parse args.
25650ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao */
25660ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Haoint32_t main(int32_t argc, char** argv) {
25670ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  gOptions.threshold = -1;
25680ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
25690ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  // Parse the options
25700ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (parseOptions(argc, argv) || argc - optind != 1) return usage(argv[0]);
25710ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
25720ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  gOptions.traceFileName = argv[optind];
25730ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
25740ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.threshold < 0 || 100 <= gOptions.threshold) {
25750ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    gOptions.threshold = 20;
25760ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
25770ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
25780ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.dump) {
25790ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    dumpTrace();
25800ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    return 0;
25810ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
25820ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
25830ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  uint64_t sumThreadTime = 0;
25840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
25850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  TraceData data1;
25860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  DataKeys* dataKeys = parseDataKeys(&data1, gOptions.traceFileName, &sumThreadTime);
25870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (dataKeys == nullptr) {
25880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    fprintf(stderr, "Cannot read \"%s\".\n", gOptions.traceFileName);
25890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    exit(1);
25900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
25910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
25920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  if (gOptions.diffFileName != nullptr) {
25930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    uint64_t sum2;
25940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    TraceData data2;
25950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    DataKeys* d2 = parseDataKeys(&data2, gOptions.diffFileName, &sum2);
25960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (d2 == nullptr) {
25970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      fprintf(stderr, "Cannot read \"%s\".\n", gOptions.diffFileName);
25980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      exit(1);
25990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
26000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
26010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    createDiff(d2, dataKeys);
26020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
26030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    freeDataKeys(d2);
26040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  } else {
26050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    MethodEntry** methods = parseMethodEntries(dataKeys);
26060ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    profileTrace(&data1, methods, dataKeys->numMethods, sumThreadTime);
26070ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    if (gOptions.graphFileName != nullptr) {
26080ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao      createInclusiveProfileGraphNew(dataKeys);
26090ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    }
26100ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao    free(methods);
26110ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  }
26120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
26130ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  freeDataKeys(dataKeys);
26140ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao
26150ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao  return 0;
26160ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao}
2617