mirror of
https://github.com/RGBCube/serenity
synced 2025-05-16 07:34:58 +00:00

Most of the models were just calling did_update anyway, which is pointless since it can be unified to the base Model class. Instead, code calling update() will now call invalidate(), which functions identically and is more obvious in what it does. Additionally, a default implementation is provided, which removes the need to add empty implementations of update() for each model subclass. Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
138 lines
4.5 KiB
C++
138 lines
4.5 KiB
C++
/*
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include "ProfileModel.h"
|
|
#include "Profile.h"
|
|
#include <LibGUI/FileIconProvider.h>
|
|
#include <LibSymbolication/Symbolication.h>
|
|
#include <stdio.h>
|
|
|
|
namespace Profiler {
|
|
|
|
ProfileModel::ProfileModel(Profile& profile)
|
|
: m_profile(profile)
|
|
{
|
|
m_user_frame_icon.set_bitmap_for_size(16, Gfx::Bitmap::try_load_from_file("/res/icons/16x16/inspector-object.png"));
|
|
m_kernel_frame_icon.set_bitmap_for_size(16, Gfx::Bitmap::try_load_from_file("/res/icons/16x16/inspector-object-red.png"));
|
|
}
|
|
|
|
ProfileModel::~ProfileModel()
|
|
{
|
|
}
|
|
|
|
GUI::ModelIndex ProfileModel::index(int row, int column, const GUI::ModelIndex& parent) const
|
|
{
|
|
if (!parent.is_valid()) {
|
|
if (m_profile.roots().is_empty())
|
|
return {};
|
|
return create_index(row, column, m_profile.roots().at(row).ptr());
|
|
}
|
|
auto& remote_parent = *static_cast<ProfileNode*>(parent.internal_data());
|
|
return create_index(row, column, remote_parent.children().at(row).ptr());
|
|
}
|
|
|
|
GUI::ModelIndex ProfileModel::parent_index(const GUI::ModelIndex& index) const
|
|
{
|
|
if (!index.is_valid())
|
|
return {};
|
|
auto& node = *static_cast<ProfileNode*>(index.internal_data());
|
|
if (!node.parent())
|
|
return {};
|
|
|
|
// NOTE: If the parent has no parent, it's a root, so we have to look among the roots.
|
|
if (!node.parent()->parent()) {
|
|
for (size_t row = 0; row < m_profile.roots().size(); ++row) {
|
|
if (m_profile.roots()[row].ptr() == node.parent()) {
|
|
return create_index(row, index.column(), node.parent());
|
|
}
|
|
}
|
|
VERIFY_NOT_REACHED();
|
|
return {};
|
|
}
|
|
|
|
for (size_t row = 0; row < node.parent()->parent()->children().size(); ++row) {
|
|
if (node.parent()->parent()->children()[row].ptr() == node.parent())
|
|
return create_index(row, index.column(), node.parent());
|
|
}
|
|
|
|
VERIFY_NOT_REACHED();
|
|
return {};
|
|
}
|
|
|
|
int ProfileModel::row_count(const GUI::ModelIndex& index) const
|
|
{
|
|
if (!index.is_valid())
|
|
return m_profile.roots().size();
|
|
auto& node = *static_cast<ProfileNode*>(index.internal_data());
|
|
return node.children().size();
|
|
}
|
|
|
|
int ProfileModel::column_count(const GUI::ModelIndex&) const
|
|
{
|
|
return Column::__Count;
|
|
}
|
|
|
|
String ProfileModel::column_name(int column) const
|
|
{
|
|
switch (column) {
|
|
case Column::SampleCount:
|
|
return m_profile.show_percentages() ? "% Samples" : "# Samples";
|
|
case Column::SelfCount:
|
|
return m_profile.show_percentages() ? "% Self" : "# Self";
|
|
case Column::ObjectName:
|
|
return "Object";
|
|
case Column::StackFrame:
|
|
return "Stack Frame";
|
|
default:
|
|
VERIFY_NOT_REACHED();
|
|
return {};
|
|
}
|
|
}
|
|
|
|
GUI::Variant ProfileModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
|
|
{
|
|
auto* node = static_cast<ProfileNode*>(index.internal_data());
|
|
if (role == GUI::ModelRole::TextAlignment) {
|
|
if (index.column() == Column::SampleCount || index.column() == Column::SelfCount)
|
|
return Gfx::TextAlignment::CenterRight;
|
|
}
|
|
if (role == GUI::ModelRole::Icon) {
|
|
if (index.column() == Column::StackFrame) {
|
|
if (node->is_root()) {
|
|
return GUI::FileIconProvider::icon_for_executable(node->process().executable);
|
|
}
|
|
auto maybe_kernel_base = Symbolication::kernel_base();
|
|
if (maybe_kernel_base.has_value() && node->address() >= maybe_kernel_base.value())
|
|
return m_kernel_frame_icon;
|
|
return m_user_frame_icon;
|
|
}
|
|
return {};
|
|
}
|
|
if (role == GUI::ModelRole::Display) {
|
|
if (index.column() == Column::SampleCount) {
|
|
if (m_profile.show_percentages())
|
|
return ((float)node->event_count() / (float)m_profile.filtered_event_indices().size()) * 100.0f;
|
|
return node->event_count();
|
|
}
|
|
if (index.column() == Column::SelfCount) {
|
|
if (m_profile.show_percentages())
|
|
return ((float)node->self_count() / (float)m_profile.filtered_event_indices().size()) * 100.0f;
|
|
return node->self_count();
|
|
}
|
|
if (index.column() == Column::ObjectName)
|
|
return node->object_name();
|
|
if (index.column() == Column::StackFrame) {
|
|
if (node->is_root()) {
|
|
return String::formatted("{} ({})", node->process().basename, node->process().pid);
|
|
}
|
|
return node->symbol();
|
|
}
|
|
return {};
|
|
}
|
|
return {};
|
|
}
|
|
|
|
}
|