summaryrefslogtreecommitdiff
path: root/Applications/SystemMonitor
diff options
context:
space:
mode:
authorTom <tomut@yahoo.com>2020-06-27 22:52:13 -0600
committerAndreas Kling <kling@serenityos.org>2020-07-01 12:07:01 +0200
commitcdc78515b6e12f6bf8b62cf311d8dde12e191cbd (patch)
tree08a6b589c65fbc4d93ed4d396ce97bd2174580af /Applications/SystemMonitor
parentd99901660db6ffaf600f3bca055fc43e611457a1 (diff)
downloadserenity-cdc78515b6e12f6bf8b62cf311d8dde12e191cbd.zip
SystemMonitor: Add a utilization graph for each processor
Diffstat (limited to 'Applications/SystemMonitor')
-rw-r--r--Applications/SystemMonitor/ProcessModel.cpp57
-rw-r--r--Applications/SystemMonitor/ProcessModel.h20
-rw-r--r--Applications/SystemMonitor/main.cpp26
3 files changed, 87 insertions, 16 deletions
diff --git a/Applications/SystemMonitor/ProcessModel.cpp b/Applications/SystemMonitor/ProcessModel.cpp
index 9af7d1f5fc..47a0418216 100644
--- a/Applications/SystemMonitor/ProcessModel.cpp
+++ b/Applications/SystemMonitor/ProcessModel.cpp
@@ -30,6 +30,7 @@
#include <AK/JsonObject.h>
#include <AK/JsonValue.h>
#include <AK/SharedBuffer.h>
+#include <LibCore/File.h>
#include <LibCore/ProcessStatisticsReader.h>
#include <fcntl.h>
#include <stdio.h>
@@ -50,6 +51,45 @@ ProcessModel::ProcessModel()
m_high_priority_icon = Gfx::Bitmap::load_from_file("/res/icons/highpriority16.png");
m_low_priority_icon = Gfx::Bitmap::load_from_file("/res/icons/lowpriority16.png");
m_normal_priority_icon = Gfx::Bitmap::load_from_file("/res/icons/normalpriority16.png");
+
+ auto file = Core::File::construct("/proc/cpuinfo");
+ if (file->open(Core::IODevice::ReadOnly)) {
+ OwnPtr<CpuInfo> cpu;
+ u32 cpu_id = 0;
+ while (file->can_read_line()) {
+ auto line = file->read_line(1024);
+ if (line.is_null())
+ continue;
+
+ auto str = String::copy(line, Chomp);
+ if (str.is_empty() && cpu)
+ m_cpus.append(cpu.release_nonnull());
+
+ size_t i;
+ bool have_val = false;
+ for (i = 0; i < str.length(); i++) {
+ if (str[i] == ':') {
+ have_val = true;
+ break;
+ }
+ }
+ if (!have_val)
+ continue;
+ auto key = str.substring(0, i);
+ auto val = str.substring(i + 1, str.length() - i - 1).trim_whitespace();
+
+ if (!cpu)
+ cpu = make<CpuInfo>(cpu_id++);
+
+ cpu->values.set(key, val);
+ }
+
+ if (cpu)
+ m_cpus.append(cpu.release_nonnull());
+ }
+
+ if (m_cpus.is_empty())
+ m_cpus.append(make<CpuInfo>(0));
}
ProcessModel::~ProcessModel()
@@ -97,6 +137,8 @@ String ProcessModel::column_name(int column) const
return "Purg:N";
case Column::CPU:
return "CPU";
+ case Column::Processor:
+ return "Processor";
case Column::Name:
return "Name";
case Column::Syscalls:
@@ -157,6 +199,7 @@ GUI::Variant ProcessModel::data(const GUI::ModelIndex& index, Role role) const
case Column::PurgeableVolatile:
case Column::PurgeableNonvolatile:
case Column::CPU:
+ case Column::Processor:
case Column::Syscalls:
case Column::InodeFaults:
case Column::ZeroFaults:
@@ -206,6 +249,8 @@ GUI::Variant ProcessModel::data(const GUI::ModelIndex& index, Role role) const
return (int)thread.current_state.amount_purgeable_nonvolatile;
case Column::CPU:
return thread.current_state.cpu_percent;
+ case Column::Processor:
+ return thread.current_state.cpu;
case Column::Name:
return thread.current_state.name;
case Column::Syscalls:
@@ -275,6 +320,8 @@ GUI::Variant ProcessModel::data(const GUI::ModelIndex& index, Role role) const
return pretty_byte_size(thread.current_state.amount_purgeable_nonvolatile);
case Column::CPU:
return thread.current_state.cpu_percent;
+ case Column::Processor:
+ return thread.current_state.cpu;
case Column::Name:
return thread.current_state.name;
case Column::Syscalls:
@@ -346,6 +393,7 @@ void ProcessModel::update()
state.tid = thread.tid;
state.times_scheduled = thread.times_scheduled;
+ state.cpu = thread.cpu;
state.priority = thread.priority;
state.effective_priority = thread.effective_priority;
state.state = thread.state;
@@ -365,7 +413,8 @@ void ProcessModel::update()
}
m_pids.clear();
- float total_cpu_percent = 0;
+ for (auto& c : m_cpus)
+ c.total_cpu_percent = 0.0;
Vector<PidAndTid, 16> pids_to_remove;
for (auto& it : m_threads) {
if (!live_pids.contains(it.key)) {
@@ -376,15 +425,15 @@ void ProcessModel::update()
u32 times_scheduled_diff = process.current_state.times_scheduled - process.previous_state.times_scheduled;
process.current_state.cpu_percent = ((float)times_scheduled_diff * 100) / (float)(sum_times_scheduled - last_sum_times_scheduled);
if (it.key.pid != 0) {
- total_cpu_percent += process.current_state.cpu_percent;
+ m_cpus[process.current_state.cpu].total_cpu_percent += process.current_state.cpu_percent;
m_pids.append(it.key);
}
}
for (auto pid : pids_to_remove)
m_threads.remove(pid);
- if (on_new_cpu_data_point)
- on_new_cpu_data_point(total_cpu_percent);
+ if (on_cpu_info_change)
+ on_cpu_info_change(m_cpus);
did_update(GUI::Model::UpdateFlag::DontInvalidateIndexes);
}
diff --git a/Applications/SystemMonitor/ProcessModel.h b/Applications/SystemMonitor/ProcessModel.h
index 61d1f4056a..a30ab4ff29 100644
--- a/Applications/SystemMonitor/ProcessModel.h
+++ b/Applications/SystemMonitor/ProcessModel.h
@@ -27,6 +27,7 @@
#pragma once
#include <AK/HashMap.h>
+#include <AK/NonnullOwnPtrVector.h>
#include <AK/String.h>
#include <AK/Vector.h>
#include <LibGUI/Model.h>
@@ -49,6 +50,7 @@ public:
Icon = 0,
Name,
CPU,
+ Processor,
State,
Priority,
EffectivePriority,
@@ -87,7 +89,21 @@ public:
virtual GUI::Variant data(const GUI::ModelIndex&, Role = Role::Display) const override;
virtual void update() override;
- Function<void(float)> on_new_cpu_data_point;
+ struct CpuInfo
+ {
+ u32 id;
+ float total_cpu_percent{0.0};
+ HashMap<String, String> values;
+
+ CpuInfo(u32 id):
+ id(id)
+ {
+ }
+ };
+
+ Function<void(const NonnullOwnPtrVector<CpuInfo>&)> on_cpu_info_change;
+
+ const NonnullOwnPtrVector<CpuInfo>& cpus() const { return m_cpus; }
private:
ProcessModel();
@@ -101,6 +117,7 @@ private:
String user;
String pledge;
String veil;
+ u32 cpu;
u32 priority;
u32 effective_priority;
size_t amount_virtual;
@@ -130,6 +147,7 @@ private:
HashMap<uid_t, String> m_usernames;
HashMap<PidAndTid, NonnullOwnPtr<Thread>> m_threads;
+ NonnullOwnPtrVector<CpuInfo> m_cpus;
Vector<PidAndTid> m_pids;
RefPtr<Gfx::Bitmap> m_generic_process_icon;
RefPtr<Gfx::Bitmap> m_high_priority_icon;
diff --git a/Applications/SystemMonitor/main.cpp b/Applications/SystemMonitor/main.cpp
index 5fc07ab380..d6f688a672 100644
--- a/Applications/SystemMonitor/main.cpp
+++ b/Applications/SystemMonitor/main.cpp
@@ -480,20 +480,24 @@ NonnullRefPtr<GUI::Widget> build_graphs_tab()
self.layout()->set_margins({ 4, 4, 4, 4 });
auto& cpu_graph_group_box = self.add<GUI::GroupBox>("CPU usage");
- cpu_graph_group_box.set_layout<GUI::VerticalBoxLayout>();
+ cpu_graph_group_box.set_layout<GUI::HorizontalBoxLayout>();
cpu_graph_group_box.layout()->set_margins({ 6, 16, 6, 6 });
cpu_graph_group_box.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
cpu_graph_group_box.set_preferred_size(0, 120);
- auto& cpu_graph = cpu_graph_group_box.add<GraphWidget>();
- cpu_graph.set_max(100);
- cpu_graph.set_text_color(Color::Green);
- cpu_graph.set_graph_color(Color::from_rgb(0x00bb00));
- cpu_graph.text_formatter = [](int value, int) {
- return String::format("%d%%", value);
- };
-
- ProcessModel::the().on_new_cpu_data_point = [graph = &cpu_graph](float cpu_percent) {
- graph->add_value(cpu_percent);
+ Vector<GraphWidget*> cpu_graphs;
+ for (size_t i = 0; i < ProcessModel::the().cpus().size(); i++) {
+ auto& cpu_graph = cpu_graph_group_box.add<GraphWidget>();
+ cpu_graph.set_max(100);
+ cpu_graph.set_text_color(Color::Green);
+ cpu_graph.set_graph_color(Color::from_rgb(0x00bb00));
+ cpu_graph.text_formatter = [](int value, int) {
+ return String::format("%d%%", value);
+ };
+ cpu_graphs.append(&cpu_graph);
+ }
+ ProcessModel::the().on_cpu_info_change = [cpu_graphs](const NonnullOwnPtrVector<ProcessModel::CpuInfo>& cpus) {
+ for (size_t i = 0; i < cpus.size(); i++)
+ cpu_graphs[i]->add_value(cpus[i].total_cpu_percent);
};
auto& memory_graph_group_box = self.add<GUI::GroupBox>("Memory usage");