mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-24 02:03:06 -05:00
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.
This commit is contained in:
parent
f98ca35b83
commit
754bf22da7
Notes:
sideshowbarker
2024-07-19 00:08:36 +09:00
Author: https://github.com/tomuta Commit: https://github.com/SerenityOS/serenity/commit/754bf22da72 Pull-request: https://github.com/SerenityOS/serenity/pull/4736
1 changed files with 48 additions and 23 deletions
|
@ -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) {
|
||||
|
|
Loading…
Add table
Reference in a new issue