summaryrefslogtreecommitdiff
path: root/DevTools
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-02-02 20:29:55 +0100
committerAndreas Kling <kling@serenityos.org>2020-02-02 20:29:55 +0100
commit266d7ca268b492570ad5e72a29496edbfd05a62d (patch)
treee1c900d737e21e361985508e3acdf76f5ed33dbe /DevTools
parentfa97ff1c83cc80c2f857bdc70a58ff6a588c5d3d (diff)
downloadserenity-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.cpp66
-rw-r--r--DevTools/ProfileViewer/Profile.h1
-rw-r--r--DevTools/ProfileViewer/main.cpp8
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;