diff options
author | Tom <tomut@yahoo.com> | 2020-09-18 20:05:56 -0600 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-01-03 22:12:19 +0100 |
commit | 754bf22da72bfdf160549713655acde26bee580c (patch) | |
tree | c468799b2685af4b74813bd0a0370d1ac0a2fe62 /MenuApplets | |
parent | f98ca35b83d521377d4bce5927fdcb4a764ac02e (diff) | |
download | serenity-754bf22da72bfdf160549713655acde26bee580c.zip |
ResourceGraph: Handle low memory situations bit better
Rather than crashing with an ASSERT, when we can't read from /proc
we draw the graph with red instead. This also alerts the user that
memory is very low.
Diffstat (limited to 'MenuApplets')
-rw-r--r-- | MenuApplets/ResourceGraph/main.cpp | 71 |
1 files changed, 48 insertions, 23 deletions
diff --git a/MenuApplets/ResourceGraph/main.cpp b/MenuApplets/ResourceGraph/main.cpp index 38d47a3bb1..f829dedeb6 100644 --- a/MenuApplets/ResourceGraph/main.cpp +++ b/MenuApplets/ResourceGraph/main.cpp @@ -51,11 +51,12 @@ class GraphWidget final : public GUI::Frame { public: static constexpr size_t history_size = 30; - GraphWidget(GraphType graph_type, Optional<Gfx::Color> graph_color) + GraphWidget(GraphType graph_type, Optional<Gfx::Color> graph_color, Optional<Gfx::Color> graph_error_color) : m_graph_type(graph_type) { set_frame_thickness(1); m_graph_color = graph_color.value_or(palette().menu_selection()); + m_graph_error_color = graph_error_color.value_or(Color::Red); start_timer(1000); } @@ -66,24 +67,32 @@ private: case GraphType::CPU: { unsigned busy; unsigned idle; - get_cpu_usage(busy, idle); - unsigned busy_diff = busy - m_last_cpu_busy; - unsigned idle_diff = idle - m_last_cpu_idle; - m_last_cpu_busy = busy; - m_last_cpu_idle = idle; - float cpu = (float)busy_diff / (float)(busy_diff + idle_diff); - m_history.enqueue(cpu); - m_tooltip = String::format("CPU usage: %.1f%%", 100 * cpu); + if (get_cpu_usage(busy, idle)) { + unsigned busy_diff = busy - m_last_cpu_busy; + unsigned idle_diff = idle - m_last_cpu_idle; + m_last_cpu_busy = busy; + m_last_cpu_idle = idle; + float cpu = (float)busy_diff / (float)(busy_diff + idle_diff); + m_history.enqueue(cpu); + m_tooltip = String::format("CPU usage: %.1f%%", 100 * cpu); + } else { + m_history.enqueue(-1); + m_tooltip = StringView("Unable to determine CPU usage"); + } break; } case GraphType::Memory: { unsigned allocated; unsigned available; - get_memory_usage(allocated, available); - float total_memory = allocated + available; - float memory = (float)allocated / total_memory; - m_history.enqueue(memory); - m_tooltip = String::format("Memory: %.1f MiB of %.1f MiB in use", (float)allocated / MiB, total_memory / MiB); + if (get_memory_usage(allocated, available)) { + float total_memory = allocated + available; + float memory = (float)allocated / total_memory; + m_history.enqueue(memory); + m_tooltip = String::format("Memory: %.1f MiB of %.1f MiB in use", (float)allocated / MiB, total_memory / MiB); + } else { + m_history.enqueue(-1); + m_tooltip = StringView("Unable to determine memory usage"); + } break; } default: @@ -103,10 +112,17 @@ private: int i = m_history.capacity() - m_history.size(); auto rect = frame_inner_rect(); for (auto value : m_history) { - painter.draw_line( - { rect.x() + i, rect.bottom() }, - { rect.x() + i, rect.top() + (int)(round(rect.height() - (value * rect.height()))) }, - m_graph_color); + if (value >= 0) { + painter.draw_line( + { rect.x() + i, rect.bottom() }, + { rect.x() + i, rect.top() + (int)(round(rect.height() - (value * rect.height()))) }, + m_graph_color); + } else { + painter.draw_line( + { rect.x() + i, rect.top() }, + { rect.x() + i, rect.bottom() }, + m_graph_error_color); + } ++i; } } @@ -125,12 +141,14 @@ private: } } - static void get_cpu_usage(unsigned& busy, unsigned& idle) + static bool get_cpu_usage(unsigned& busy, unsigned& idle) { busy = 0; idle = 0; auto all_processes = Core::ProcessStatisticsReader::get_all(); + if (all_processes.is_empty()) + return false; for (auto& it : all_processes) { for (auto& jt : it.value.threads) { @@ -140,13 +158,14 @@ private: busy += jt.ticks_user + jt.ticks_kernel; } } + return true; } - static void get_memory_usage(unsigned& allocated, unsigned& available) + static bool get_memory_usage(unsigned& allocated, unsigned& available) { auto proc_memstat = Core::File::construct("/proc/memstat"); if (!proc_memstat->open(Core::IODevice::OpenMode::ReadOnly)) - ASSERT_NOT_REACHED(); + return false; auto file_contents = proc_memstat->read_all(); auto json = JsonValue::from_string(file_contents); @@ -155,10 +174,12 @@ private: unsigned user_physical_available = json.value().as_object().get("user_physical_available").to_u32(); allocated = (user_physical_allocated * PAGE_SIZE); available = (user_physical_available * PAGE_SIZE); + return true; } GraphType m_graph_type; Gfx::Color m_graph_color; + Gfx::Color m_graph_error_color; CircularQueue<float, history_size> m_history; unsigned m_last_cpu_busy { 0 }; unsigned m_last_cpu_idle { 0 }; @@ -183,11 +204,13 @@ int main(int argc, char** argv) bool memory = false; const char* name = nullptr; const char* color = nullptr; + const char* error_color = nullptr; Core::ArgsParser args_parser; args_parser.add_option(cpu, "Show CPU usage", "cpu", 'C'); args_parser.add_option(memory, "Show memory usage", "memory", 'M'); args_parser.add_option(name, "Applet name used by WindowServer.ini to set the applet order", "name", 'n', "name"); args_parser.add_option(color, "Graph color", "color", 'c', "color"); + args_parser.add_option(error_color, "Graph color (error)", "error-color", 'e', "error-color"); args_parser.parse(argc, argv); if (!cpu && !memory) { @@ -207,16 +230,18 @@ int main(int argc, char** argv) if (name == nullptr) name = "ResourceGraph"; - Optional<Gfx::Color> graph_color; + Optional<Gfx::Color> graph_color, graph_error_color; if (color != nullptr) graph_color = Gfx::Color::from_string(color); + if (error_color != nullptr) + graph_error_color = Gfx::Color::from_string(error_color); auto window = GUI::Window::construct(); window->set_title(name); window->set_window_type(GUI::WindowType::MenuApplet); window->resize(GraphWidget::history_size + 2, 16); - window->set_main_widget<GraphWidget>(graph_type, graph_color); + window->set_main_widget<GraphWidget>(graph_type, graph_color, graph_error_color); window->show(); if (unveil("/res", "r") < 0) { |