Skip to content

Commit 50dfba7

Browse files
committed
kram-profile - demangle backend names, remove updateFileCache, store totalFronted/Backend times
1 parent 7451ad2 commit 50dfba7

File tree

4 files changed

+163
-31
lines changed

4 files changed

+163
-31
lines changed

Diff for: kram-profile/Source/KramZipHelper.cpp

+41
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,47 @@
1818
#include <compression.h>
1919
#endif
2020

21+
// Throwing this in for now, since it's the only .cpp file
22+
#if KRAM_MAC || KRAM_IOS
23+
#include <cxxabi.h> // demangle
24+
#include <unordered_map>
25+
#include <mutex>
26+
#endif
27+
28+
extern "C" const char* _Nonnull demangleSymbolName(const char* _Nonnull symbolName_) {
29+
using namespace NAMESPACE_STL;
30+
31+
// serialize to multiple threads
32+
static mutex sMutex;
33+
static unordered_map<string, const char*> sSymbolToDemangleName;
34+
lock_guard<mutex> lock(sMutex);
35+
36+
string symbolName(symbolName_);
37+
auto it = sSymbolToDemangleName.find(symbolName);
38+
if (it != sSymbolToDemangleName.end()) {
39+
return it->second;
40+
}
41+
42+
// see CBA if want a generalized demangle for Win/Linux
43+
size_t size = 0;
44+
int status = 0;
45+
char* symbol = abi::__cxa_demangle(symbolName.c_str(), nullptr, &size, &status);
46+
const char* result = nullptr;
47+
if (status == 0) {
48+
49+
sSymbolToDemangleName[symbolName] = symbol;
50+
result = symbol;
51+
// not freeing the symbols here
52+
//free(symbol);
53+
}
54+
else {
55+
// This will do repeated demangle though. Maybe should add to table?
56+
result = symbolName_;
57+
}
58+
59+
return result;
60+
}
61+
2162
namespace kram {
2263
using namespace NAMESPACE_STL;
2364

Diff for: kram-profile/Source/KramZipHelperW.h

+6
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,9 @@ typedef struct ZipEntryW {
3535

3636
@end
3737

38+
// This is only needed for OptFunction and backend names
39+
// Can't prepend extern "C" onto the call.
40+
extern "C" {
41+
const char* _Nonnull demangleSymbolName(const char* _Nonnull symbolName_);
42+
}
43+

Diff for: kram-profile/kram-profile/File.swift

+6-7
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,16 @@ class File: Identifiable, /*Hashable, */ Equatable, Comparable
3535
let containerType: ContainerType
3636
var archive: Archive?
3737

38-
var duration = 0.0
38+
var duration = 0.0 // in seconds
3939

4040
var fileContent: Data?
4141
var modStamp: Date?
4242
var loadStamp: Date?
4343

4444
// This is only updated for Build fileType
4545
var buildTimings: [String:BuildTiming] = [:]
46+
var totalFrontend = 0 // in micros
47+
var totalBackend = 0
4648

4749
// only available for memory file type right now
4850
var threadInfo = ""
@@ -155,7 +157,7 @@ func generateNavigationTitle(_ sel: String?) -> String {
155157
var text = generateDuration(file: f) + " " + f.name
156158

157159
if let fileArchive = f.archive {
158-
text += "in (" + fileArchive.name + ")"
160+
text += " in (" + fileArchive.name + ")"
159161
}
160162

161163
return text
@@ -195,11 +197,6 @@ func lookupFile(selection: String) -> File {
195197
return lookupFile(url:URL(string:selection)!)
196198
}
197199

198-
// This one won't be one in the list, though
199-
func updateFileCache(file: File) {
200-
fileCache[file.url] = file
201-
}
202-
203200
//-------------
204201

205202
class Archive: Identifiable, /*Hashable, */ Equatable, Comparable {
@@ -303,6 +300,8 @@ func lookupArchive(_ url: URL) -> Archive {
303300
// release other calcs (f.e. duration, histogram, etc)
304301
// can point to new archive content here
305302
file.buildTimings.removeAll()
303+
file.totalFrontend = 0
304+
file.totalBackend = 0
306305
}
307306
}
308307
}

Diff for: kram-profile/kram-profile/kram_profileApp.swift

+110-24
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,33 @@ import UniformTypeIdentifiers
3131
// then can focus on the bigger values.
3232
// TODO: Sort by name and convert to count - can then see common counts
3333
// so keep the json loaded in Swift. Can json be cloned and modded?
34-
// TODO: option to colesce to count and name with sort
34+
// TODO: option to coalesce to count and name with sort
3535

3636
// Build traces
3737
// TODO: parse totals from build traces, what CBA is doing
3838
// TODO: present total time, and % of total in the nav panel
3939

40-
// TODO: import zip, and run cba on contents, mmap and decompress each
41-
// can use incremental mode?
42-
// TODO: can't mmap web link, but can load zip off server with timings
40+
// Perf traces
41+
// TODO: ...
42+
43+
// TODO: track kram-profile memory use, jettison Data that isn't needed after have built up timings.
44+
// can re-decompress from zip mmap.
45+
46+
// TODO: background process to compute duration and buildTimings across all files
47+
// how to refresh the list as these are updated. Use Swift Task? Or could do on C++ side with TaskSystem.
48+
49+
// DONE: import zip
4350
// DONE: add/update recent document list (need to hold onto dropped/opened folder)
44-
// TODO: save/load the duration and modstamps for File, and any other metadata (totals per section)
45-
// TODO: add jump to source, but path would need to be correct (sandbox block?)
51+
// DONE: can't mmap web link, but can load zip off server with timings
52+
53+
// TODO: run cba on files, mmap and decompress each can use incremental mode?
54+
// TODO: save/load the duration and modstamps for File at quit, and any other metadata (totals per section)
55+
// TODO: add jump to source/header, but path would need to be correct (sandbox block?)
56+
57+
// Build traces
58+
// TODO: OptFunction needs demangled. All backend strings are still mangled.
59+
// Don’t need the library CBA uses just use api::__cxa_demangle() on macOS.
60+
// https://github.com/llvm/llvm-project/issues/459
4661

4762
// TODO: across all files, many of the strings are the same. Could replace all strings
4863
// with an index, compress, and zip archive with the index table. buid, perf, mem strings
@@ -78,14 +93,14 @@ import UniformTypeIdentifiers
7893

7994
// 4-bit, 12-bit, 16-bit, variable, pad to 4B
8095

81-
// TODO: recent documents list doesn't survive relaunch, but only when app is rebuilt
96+
// DONE: recent documents list doesn't survive relaunch, but only when app is rebuilt
8297
// but still kind of annoying for development
8398

8499
// DONE: have a way to reload dropped folder
85100
// DONE: track parent archives, folder, and loose drop files
86101
// and when reload is hit, then reload all of that rebuild the list
87102
// and then reload the selected file
88-
// TODO: zipHelper to deal with archives, can use Swift Data to mmap content if needed
103+
// DONE: zipHelper to deal with archives, can use Swift Data to mmap content if needed
89104
// mmap the zip, list out the files and locations, and then defalte the content somewhere
90105
// only then can data be handed off toe Pefertto or CBA. And CBA needs all files.
91106
// Maybe extend CBA to read a zip file. Can just use ZipHelper.
@@ -706,6 +721,9 @@ func updateFileBuildTimings(_ catapultProfile: CatapultProfile) -> [String:Build
706721
// and then subtracting the immediate children.
707722
// See what CBA and Perfetto do to establish this.
708723

724+
// Would be good to establish this nesting once and store the level
725+
// with each event.d
726+
709727
// run through each file, and build a local map of name to size count
710728
for i in 0..<catapultProfile.traceEvents!.count {
711729
let event = catapultProfile.traceEvents![i]
@@ -759,7 +777,7 @@ func mergeFileBuildTimings(files: [File]) -> [String:BuildTiming] {
759777

760778
func buildPerfettoJsonFromBuildTimings(buildTimings: [String:BuildTiming]) -> String {
761779
// now convert those timings back into a perfetto displayable report
762-
// So just need to buid up the json above into events on tracks
780+
// So just need to build up the json above into events on tracks
763781
var events: [CatapultEvent] = []
764782

765783
// Also sort or assign a sort_index to the tracks. Sort biggest to smallest.
@@ -808,23 +826,27 @@ func buildPerfettoJsonFromBuildTimings(buildTimings: [String:BuildTiming]) -> St
808826
}
809827
}
810828

811-
// TODO: sort this by the duration
812829
events.sort {
830+
// want threadnames first, could just prepend these to array?
831+
if $0.ph! != $1.ph! {
832+
return $0.ph! < $1.ph!
833+
}
834+
835+
// then thread id
813836
if $0.tid! != $1.tid! {
814837
return $0.tid! < $1.tid!
815838
}
816839

840+
// then duration
817841
// has to be > to work as a single tid
818842
if $0.dur != $1.dur! {
819843
return $0.dur! > $1.dur!
820844
}
821845

846+
// then name
822847
return $0.name! < $1.name!
823848
}
824849

825-
// assign thread id, may not need names or tid
826-
// since Perfetto will just treat the events as subevents
827-
828850
let catapultProfile = CatapultProfile(traceEvents: events)
829851

830852
do {
@@ -945,7 +967,6 @@ func updateThreadInfo(_ catapultProfile: CatapultProfile, _ file: inout File) {
945967
}
946968

947969
file.threadInfo = text
948-
updateFileCache(file: file)
949970
}
950971

951972
func updateDuration(_ catapultProfile: CatapultProfile, _ file: inout File) {
@@ -967,8 +988,6 @@ func updateDuration(_ catapultProfile: CatapultProfile, _ file: inout File) {
967988
if startTime <= endTime {
968989
// for now assume micros
969990
file.duration = Double(endTime - startTime) * 1e-6
970-
971-
updateFileCache(file: file)
972991
}
973992
}
974993

@@ -1076,6 +1095,56 @@ func loadFileJS(_ path: String) -> String? {
10761095
file.buildTimings = updateFileBuildTimings(catapultProfile)
10771096
}
10781097

1098+
/* These are types CBA is looking at. It's not looking at any totals
1099+
DebugType isn't in this.
1100+
1101+
if (StrEqual(name, "ExecuteCompiler"))
1102+
event.type = BuildEventType::kCompiler;
1103+
else if (StrEqual(name, "Frontend"))
1104+
event.type = BuildEventType::kFrontend;
1105+
else if (StrEqual(name, "Backend"))
1106+
event.type = BuildEventType::kBackend;
1107+
else if (StrEqual(name, "Source"))
1108+
event.type = BuildEventType::kParseFile;
1109+
else if (StrEqual(name, "ParseTemplate"))
1110+
event.type = BuildEventType::kParseTemplate;
1111+
else if (StrEqual(name, "ParseClass"))
1112+
event.type = BuildEventType::kParseClass;
1113+
else if (StrEqual(name, "InstantiateClass"))
1114+
event.type = BuildEventType::kInstantiateClass;
1115+
else if (StrEqual(name, "InstantiateFunction"))
1116+
event.type = BuildEventType::kInstantiateFunction;
1117+
else if (StrEqual(name, "OptModule"))
1118+
event.type = BuildEventType::kOptModule;
1119+
else if (StrEqual(name, "OptFunction"))
1120+
event.type = BuildEventType::kOptFunction;
1121+
1122+
// here are totals that are in the file
1123+
// Total ExecuteCompiler = Total Frontend + Total Backend
1124+
// 2 frontend blocks though,
1125+
// 1. Source, InstantiateFunction, CodeGenFunction, ...
1126+
// 2. CodeGenFunction, DebugType, and big gaps
1127+
//
1128+
// 1 backend block
1129+
// OptModule
1130+
1131+
"Total ExecuteCompiler" <- important
1132+
"Total Frontend" <- important <- important
1133+
"Total InstantiateFunction"
1134+
"Total CodeGen Function"
1135+
"Total Backend"
1136+
"Total CodeGenPasses"
1137+
"Total OptModule" <- important
1138+
"Total OptFunction"
1139+
"Total RunPass"
1140+
"Total InstantiatePass"
1141+
"Total Source"
1142+
"Total ParseClass"
1143+
"Total DebugType"
1144+
"Total PerformPendingInstantiations"
1145+
"Total Optimizer"
1146+
*/
1147+
10791148
for i in 0..<catapultProfile.traceEvents!.count {
10801149
let event = catapultProfile.traceEvents![i]
10811150
if event.name == "Source" ||
@@ -1097,16 +1166,34 @@ func loadFileJS(_ path: String) -> String? {
10971166
event.name == "CodeGen Function" ||
10981167
event.name == "RunPass"
10991168
{
1100-
// This is a name
1101-
let detail = event.args!["detail"]!.value as! String
1102-
catapultProfile.traceEvents![i].name = detail
1169+
// backend symbols need demangle
1170+
let isDemangleNeeded = event.name == "OptFunction"
1171+
1172+
if isDemangleNeeded {
1173+
let detail = event.args!["detail"]!.value as! String
1174+
let symbolName = String(cString: demangleSymbolName(detail))
1175+
1176+
catapultProfile.traceEvents![i].name = symbolName
1177+
}
1178+
else {
1179+
// This is a name
1180+
let detail = event.args!["detail"]!.value as! String
1181+
catapultProfile.traceEvents![i].name = detail
1182+
}
1183+
}
1184+
1185+
// These aren't renamed but are useful data for report
1186+
// and are already calculated.
1187+
else if event.name == "Total Backend" {
1188+
file.totalBackend = event.dur!
1189+
}
1190+
else if event.name == "Total Ffrontend" {
1191+
file.totalFrontend = event.dur!
11031192
}
11041193
}
11051194

1106-
// walk the file and compute the duration if we don't already have ti
1195+
// walk the file and compute the duration if we don't already have it
11071196
if file.duration == 0.0 {
1108-
1109-
11101197
updateDuration(catapultProfile, &file)
11111198

11121199
// For now, just log the per-thread info
@@ -1341,7 +1428,7 @@ struct kram_profileApp: App {
13411428
}
13421429

13431430
// This isn't so valuable to open a file, but opening a referenced header from build
1344-
// would be.
1431+
// would be. But would to respond to/retrieve selection in JS side.
13451432
func openContainingFolder(_ str: String) {
13461433
let url = URL(string: str)!
13471434
NSWorkspace.shared.activateFileViewerSelecting([url]);
@@ -1382,7 +1469,6 @@ struct kram_profileApp: App {
13821469

13831470
let file = lookupFile(selection: sel)
13841471
file.setLoadStamp()
1385-
updateFileCache(file: file)
13861472
}
13871473

13881474
// Want to be able to lock the scale of the

0 commit comments

Comments
 (0)