diff options
author | Tom <tomut@yahoo.com> | 2020-06-27 22:52:13 -0600 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-07-01 12:07:01 +0200 |
commit | cdc78515b6e12f6bf8b62cf311d8dde12e191cbd (patch) | |
tree | 08a6b589c65fbc4d93ed4d396ce97bd2174580af /Applications/SystemMonitor | |
parent | d99901660db6ffaf600f3bca055fc43e611457a1 (diff) | |
download | serenity-cdc78515b6e12f6bf8b62cf311d8dde12e191cbd.zip |
SystemMonitor: Add a utilization graph for each processor
Diffstat (limited to 'Applications/SystemMonitor')
-rw-r--r-- | Applications/SystemMonitor/ProcessModel.cpp | 57 | ||||
-rw-r--r-- | Applications/SystemMonitor/ProcessModel.h | 20 | ||||
-rw-r--r-- | Applications/SystemMonitor/main.cpp | 26 |
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"); |