diff --git a/DevTools/ProfileViewer/Profile.cpp b/DevTools/ProfileViewer/Profile.cpp index d610a77ccc..716dc2f528 100644 --- a/DevTools/ProfileViewer/Profile.cpp +++ b/DevTools/ProfileViewer/Profile.cpp @@ -26,8 +26,10 @@ #include "Profile.h" #include "ProfileModel.h" +#include #include #include +#include #include static void sort_profile_nodes(Vector>& nodes) @@ -50,6 +52,7 @@ Profile::Profile(const JsonArray& json) m_samples.ensure_capacity(m_json.size()); for (auto& sample_value : m_json.values()) { + auto& sample_object = sample_value.as_object(); Sample sample; @@ -155,6 +158,69 @@ void Profile::rebuild_tree() m_model->update(); } +OwnPtr Profile::load_from_perfcore_file(const StringView& path) +{ + auto file = Core::File::construct(path); + if (!file->open(Core::IODevice::ReadOnly)) { + fprintf(stderr, "Unable to open %s, error: %s\n", String(path).characters(), file->error_string()); + return nullptr; + } + + auto json = JsonValue::from_string(file->read_all()); + if (!json.is_object()) { + fprintf(stderr, "Invalid perfcore format (not a JSON object)\n"); + return nullptr; + } + + auto& object = json.as_object(); + auto executable_path = object.get("executable").to_string(); + + MappedFile elf_file(executable_path); + if (!elf_file.is_valid()) { + fprintf(stderr, "Unable to open executable '%s' for symbolication.\n", executable_path.characters()); + return nullptr; + } + + auto elf_loader = make(static_cast(elf_file.data()), elf_file.size()); + + auto events_value = object.get("events"); + if (!events_value.is_array()) + return nullptr; + + auto& perf_events = events_value.as_array(); + if (perf_events.is_empty()) + return nullptr; + + JsonArray profile_events; + + for (auto& perf_event_value : perf_events.values()) { + auto& perf_event = perf_event_value.as_object(); + + JsonObject object; + object.set("timestamp", perf_event.get("timestamp")); + + JsonArray frames_array; + auto stack_array = perf_event.get("stack").as_array(); + + for (auto& frame : stack_array.values()) { + auto ptr = frame.to_number(); + u32 offset = 0; + auto symbol = elf_loader->symbolicate(ptr, &offset); + + JsonObject frame_object; + frame_object.set("address", ptr); + frame_object.set("symbol", symbol); + frame_object.set("offset", offset); + frames_array.append(move(frame_object)); + } + + object.set("frames", move(frames_array)); + profile_events.append(move(object)); + } + + return NonnullOwnPtr(NonnullOwnPtr::Adopt, *new Profile(move(profile_events))); +} + OwnPtr Profile::load_from_file(const StringView& path) { auto file = Core::File::construct(path); diff --git a/DevTools/ProfileViewer/Profile.h b/DevTools/ProfileViewer/Profile.h index bbefa20430..4ccde6f94a 100644 --- a/DevTools/ProfileViewer/Profile.h +++ b/DevTools/ProfileViewer/Profile.h @@ -105,6 +105,7 @@ private: class Profile { public: static OwnPtr load_from_file(const StringView& path); + static OwnPtr load_from_perfcore_file(const StringView& path); ~Profile(); GUI::Model& model(); diff --git a/DevTools/ProfileViewer/main.cpp b/DevTools/ProfileViewer/main.cpp index 86d0b83d6e..c58c91b09c 100644 --- a/DevTools/ProfileViewer/main.cpp +++ b/DevTools/ProfileViewer/main.cpp @@ -43,8 +43,14 @@ int main(int argc, char** argv) } const char* path = argv[1]; + OwnPtr profile; + + if (!strcmp(path, "perfcore")) { + profile = Profile::load_from_perfcore_file(path); + } else { + profile = Profile::load_from_file(path); + } - auto profile = Profile::load_from_file(path); if (!profile) { fprintf(stderr, "Unable to load profile '%s'\n", path); return 1;