mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 17:10:23 +00:00
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.
This commit is contained in:
parent
fa97ff1c83
commit
266d7ca268
Notes:
sideshowbarker
2024-07-19 09:41:17 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/266d7ca268b
3 changed files with 74 additions and 1 deletions
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue