瀏覽代碼

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.
Tom 4 年之前
父節點
當前提交
754bf22da7
共有 1 個文件被更改,包括 48 次插入23 次删除
  1. 48 23
      MenuApplets/ResourceGraph/main.cpp

+ 48 - 23
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) {