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 * '<' < 2460ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * '>' > 2470ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao * '&' & 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(" "); 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\"> </span> "); 17180ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printf("Cycles %%/total Cumul.%% Calls+Recur 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\"> </span>"); 17840ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao sprintf(buf, "%" PRIu64, method->elapsedExclusive); 17850ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printHtmlField(buf, 9); 17860ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printf(" "); 17870ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao sprintf(buf, "%" PRIu64, method->elapsedInclusive); 17880ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printHtmlField(buf, 9); 17890ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printf(" "); 17900ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao sprintf(buf, "%.1f", per); 17910ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printHtmlField(buf, 7); 17920ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printf(" "); 17930ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao sprintf(buf, "%.1f", sum_per); 17940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printHtmlField(buf, 7); 17950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printf(" "); 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(" "); 18020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printf("<a href=\"#m%d\">[%d]</a> %s %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\"> </span> "); 19280ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printf("Cycles %%/total Cumul.%% Calls+Recur 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\"> </span>"); 19940ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao sprintf(buf, "%" PRIu64, method->elapsedExclusive); 19950ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printHtmlField(buf, 9); 19960ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printf(" "); 19970ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao sprintf(buf, "%" PRIu64, method->elapsedInclusive); 19980ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printHtmlField(buf, 9); 19990ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printf(" "); 20000ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao sprintf(buf, "%.1f", per); 20010ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printHtmlField(buf, 7); 20020ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printf(" "); 20030ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao sprintf(buf, "%.1f", sum_per); 20040ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printHtmlField(buf, 7); 20050ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printf(" "); 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(" "); 20120ccc341cfa5c31d3b7ed99602bcb4837f6897e6aJeff Hao printf("<a href=\"#m%d\">[%d]</a> %s.%s %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, ¤tTime)) 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