diff options
author | Andreas Kling <kling@serenityos.org> | 2020-02-02 20:29:55 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-02-02 20:29:55 +0100 |
commit | 266d7ca268b492570ad5e72a29496edbfd05a62d (patch) | |
tree | e1c900d737e21e361985508e3acdf76f5ed33dbe /DevTools | |
parent | fa97ff1c83cc80c2f857bdc70a58ff6a588c5d3d (diff) | |
download | serenity-266d7ca268b492570ad5e72a29496edbfd05a62d.zip |
ProfileViewer: Add basic support for loading "perfcore" files
"perfcore" is the file that the kernel generates after a process that
was recording performance events has exited.
This patch teaches ProfileViewer how to load (and symbolicate!) those
files so that we can look at them. This will need a bunch more work
to make it truly useful.
Diffstat (limited to 'DevTools')
-rw-r--r-- | DevTools/ProfileViewer/Profile.cpp | 66 | ||||
-rw-r--r-- | DevTools/ProfileViewer/Profile.h | 1 | ||||
-rw-r--r-- | DevTools/ProfileViewer/main.cpp | 8 |
3 files changed, 74 insertions, 1 deletions
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 <AK/MappedFile.h> #include <AK/QuickSort.h> #include <LibCore/CFile.h> +#include <LibELF/ELFLoader.h> #include <stdio.h> static void sort_profile_nodes(Vector<NonnullRefPtr<ProfileNode>>& 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> 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<ELFLoader>(static_cast<const u8*>(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>(); + 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<Profile>(NonnullOwnPtr<Profile>::Adopt, *new Profile(move(profile_events))); +} + OwnPtr<Profile> 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<Profile> load_from_file(const StringView& path); + static OwnPtr<Profile> 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> 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; |