2015-07-01 11:20:23 +02:00
|
|
|
/*
|
|
|
|
* \brief CPU load display
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2015-06-30
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-02-20 13:23:52 +01:00
|
|
|
* Copyright (C) 2015-2017 Genode Labs GmbH
|
2015-07-01 11:20:23 +02:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 13:23:52 +01:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2015-07-01 11:20:23 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
2016-11-25 16:54:49 +01:00
|
|
|
#include <base/component.h>
|
2017-03-20 12:04:55 +01:00
|
|
|
#include <base/heap.h>
|
2017-01-30 11:35:12 +01:00
|
|
|
#include <base/attached_rom_dataspace.h>
|
2015-07-01 11:20:23 +02:00
|
|
|
#include <polygon_gfx/shaded_polygon_painter.h>
|
2020-06-16 15:46:59 +02:00
|
|
|
#include <os/pixel_rgb888.h>
|
2015-07-01 11:20:23 +02:00
|
|
|
#include <os/pixel_alpha8.h>
|
|
|
|
#include <nano3d/scene.h>
|
|
|
|
#include <nano3d/sincos_frac16.h>
|
|
|
|
#include <gems/color_hsv.h>
|
|
|
|
|
|
|
|
|
|
|
|
namespace Cpu_load_display {
|
|
|
|
|
|
|
|
class Timeline;
|
|
|
|
class Cpu;
|
|
|
|
class Cpu_registry;
|
|
|
|
template <typename> class Scene;
|
|
|
|
|
|
|
|
typedef Genode::Xml_node Xml_node;
|
|
|
|
typedef Genode::Color Color;
|
|
|
|
|
|
|
|
using Genode::max;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Cpu_load_display::Timeline : public Genode::List<Timeline>::Element
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
enum { HISTORY_LEN = 32 };
|
|
|
|
|
|
|
|
typedef Genode::String<160> Label;
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
unsigned const _subject_id = 0;
|
|
|
|
|
|
|
|
unsigned _activity[HISTORY_LEN];
|
|
|
|
|
|
|
|
unsigned _sum_activity = 0;
|
|
|
|
|
|
|
|
Label _label;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return hue value based on subject ID
|
|
|
|
*/
|
|
|
|
unsigned _hue() const
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* To get nicely varying hue values, we pass the subject ID
|
|
|
|
* to a hash function.
|
|
|
|
*/
|
|
|
|
unsigned int const a = 1588635695, q = 2, r = 1117695901;
|
|
|
|
return (a*(_subject_id % q) - r*(_subject_id / q)) & 255;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
Timeline(unsigned subject_id, Label const &label)
|
|
|
|
:
|
|
|
|
_subject_id(subject_id), _label(label)
|
|
|
|
{
|
|
|
|
Genode::memset(_activity, 0, sizeof(_activity));
|
|
|
|
}
|
|
|
|
|
|
|
|
void activity(unsigned long recent_activity, unsigned now)
|
|
|
|
{
|
|
|
|
unsigned const i = now % HISTORY_LEN;
|
|
|
|
|
|
|
|
_sum_activity -= _activity[i];
|
|
|
|
|
|
|
|
_activity[i] = recent_activity;
|
|
|
|
|
|
|
|
_sum_activity += recent_activity;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long activity(unsigned i) const
|
|
|
|
{
|
|
|
|
return _activity[i % HISTORY_LEN];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool has_subject_id(unsigned subject_id) const
|
|
|
|
{
|
|
|
|
return _subject_id == subject_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool idle() const { return _sum_activity == 0; }
|
|
|
|
|
2016-05-11 18:21:47 +02:00
|
|
|
bool kernel() const
|
2015-07-01 11:20:23 +02:00
|
|
|
{
|
|
|
|
return _label == Label("kernel");
|
|
|
|
}
|
|
|
|
|
|
|
|
enum Color_type { COLOR_TOP, COLOR_BOTTOM };
|
|
|
|
|
|
|
|
Color color(Color_type type) const
|
|
|
|
{
|
|
|
|
unsigned const brightness = 140;
|
|
|
|
unsigned const saturation = type == COLOR_TOP ? 70 : 140;
|
|
|
|
unsigned const alpha = 230;
|
|
|
|
|
|
|
|
Color const c = color_from_hsv(_hue(), saturation, brightness);
|
|
|
|
return Color(c.r, c.g, c.b, alpha);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Cpu_load_display::Cpu : public Genode::List<Cpu>::Element
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2017-03-20 12:04:55 +01:00
|
|
|
Genode::Allocator &_heap;
|
2015-07-01 11:20:23 +02:00
|
|
|
Genode::Point<> const _pos;
|
2019-01-14 20:04:40 +01:00
|
|
|
Genode::List<Timeline> _timelines { };
|
2015-07-01 11:20:23 +02:00
|
|
|
|
|
|
|
Timeline *_lookup_timeline(Xml_node subject)
|
|
|
|
{
|
|
|
|
unsigned long const subject_id = subject.attribute_value("id", 0UL);
|
|
|
|
|
2019-01-21 15:46:48 +01:00
|
|
|
Timeline::Label const label =
|
|
|
|
subject.attribute_value("label", Timeline::Label());
|
2015-07-01 11:20:23 +02:00
|
|
|
|
|
|
|
for (Timeline *t = _timelines.first(); t; t = t->next()) {
|
|
|
|
if (t->has_subject_id(subject_id))
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add new timeline */
|
2019-01-21 15:46:48 +01:00
|
|
|
Timeline *t = new (_heap) Timeline(subject_id, label);
|
2015-07-01 11:20:23 +02:00
|
|
|
_timelines.insert(t);
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long _activity(Xml_node subject)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
Xml_node activity = subject.sub_node("activity");
|
|
|
|
return activity.attribute_value("recent", 0UL);
|
|
|
|
} catch (Xml_node::Nonexistent_sub_node) { }
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2017-03-20 12:04:55 +01:00
|
|
|
Cpu(Genode::Allocator &heap, Genode::Point<> pos)
|
|
|
|
: _heap(heap), _pos(pos) { }
|
2015-07-01 11:20:23 +02:00
|
|
|
|
|
|
|
bool has_pos(Genode::Point<> pos) const
|
|
|
|
{
|
|
|
|
return pos == _pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
void import_trace_subject(Xml_node subject, unsigned now)
|
|
|
|
{
|
|
|
|
unsigned long const activity = _activity(subject);
|
|
|
|
|
|
|
|
if (activity)
|
|
|
|
_lookup_timeline(subject)->activity(activity, now);
|
|
|
|
}
|
|
|
|
|
|
|
|
void advance(unsigned now)
|
|
|
|
{
|
|
|
|
Timeline *next = nullptr;
|
|
|
|
for (Timeline *t = _timelines.first(); t; t = next) {
|
|
|
|
|
|
|
|
next = t->next();
|
|
|
|
|
|
|
|
t->activity(0, now);
|
|
|
|
|
|
|
|
if (t->idle()) {
|
|
|
|
|
|
|
|
_timelines.remove(t);
|
2017-03-20 12:04:55 +01:00
|
|
|
Genode::destroy(_heap, t);
|
2015-07-01 11:20:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long activity_sum(unsigned i) const
|
|
|
|
{
|
|
|
|
unsigned long sum = 0;
|
|
|
|
|
|
|
|
for (Timeline const *t = _timelines.first(); t; t = t->next())
|
|
|
|
sum += t->activity(i);
|
|
|
|
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename FN>
|
|
|
|
void for_each_timeline(FN const &fn) const
|
|
|
|
{
|
|
|
|
for (Timeline const *t = _timelines.first(); t; t = t->next())
|
|
|
|
fn(*t);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Cpu_load_display::Cpu_registry
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2017-03-20 12:04:55 +01:00
|
|
|
Genode::Allocator &_heap;
|
|
|
|
|
2019-01-14 20:04:40 +01:00
|
|
|
Genode::List<Cpu> _cpus { };
|
2015-07-01 11:20:23 +02:00
|
|
|
|
|
|
|
static Genode::Point<> _cpu_pos(Xml_node subject)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
Xml_node affinity = subject.sub_node("affinity");
|
|
|
|
return Genode::Point<>(affinity.attribute_value("xpos", 0UL),
|
|
|
|
affinity.attribute_value("ypos", 0UL));
|
|
|
|
} catch (Xml_node::Nonexistent_sub_node) { }
|
|
|
|
|
|
|
|
return Genode::Point<>(0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Cpu *_lookup_cpu(Xml_node subject)
|
|
|
|
{
|
|
|
|
/* find CPU that matches the affinity of the subject */
|
|
|
|
Genode::Point<> cpu_pos = _cpu_pos(subject);
|
|
|
|
for (Cpu *cpu = _cpus.first(); cpu; cpu = cpu->next()) {
|
|
|
|
if (cpu->has_pos(cpu_pos))
|
|
|
|
return cpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add new CPU */
|
2017-03-20 12:04:55 +01:00
|
|
|
Cpu *cpu = new (_heap) Cpu(_heap, cpu_pos);
|
2015-07-01 11:20:23 +02:00
|
|
|
_cpus.insert(cpu);
|
|
|
|
return cpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
void _import_trace_subject(Xml_node subject, unsigned now)
|
|
|
|
{
|
|
|
|
Cpu *cpu = _lookup_cpu(subject);
|
|
|
|
|
|
|
|
cpu->import_trace_subject(subject, now);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2017-03-20 12:04:55 +01:00
|
|
|
Cpu_registry(Genode::Allocator &heap) : _heap(heap) { }
|
|
|
|
|
2015-07-01 11:20:23 +02:00
|
|
|
void import_trace_subjects(Xml_node node, unsigned now)
|
|
|
|
{
|
|
|
|
node.for_each_sub_node("subject", [&] (Xml_node subject) {
|
|
|
|
_import_trace_subject(subject, now); });
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename FN>
|
|
|
|
void for_each_cpu(FN const &fn) const
|
|
|
|
{
|
|
|
|
for (Cpu const *cpu = _cpus.first(); cpu; cpu = cpu->next())
|
|
|
|
fn(*cpu);
|
|
|
|
}
|
|
|
|
|
|
|
|
void advance(unsigned now)
|
|
|
|
{
|
|
|
|
for (Cpu *cpu = _cpus.first(); cpu; cpu = cpu->next())
|
|
|
|
cpu->advance(now);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <typename PT>
|
|
|
|
class Cpu_load_display::Scene : public Nano3d::Scene<PT>
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
Genode::Env &_env;
|
|
|
|
|
2020-06-12 11:23:57 +02:00
|
|
|
Gui::Area const _size;
|
2015-07-01 11:20:23 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
Genode::Attached_rom_dataspace _config { _env, "config" };
|
|
|
|
|
|
|
|
void _handle_config() { _config.update(); }
|
2015-07-01 11:20:23 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
Genode::Signal_handler<Scene> _config_handler;
|
2015-07-01 11:20:23 +02:00
|
|
|
|
2017-03-20 12:04:55 +01:00
|
|
|
Genode::Attached_rom_dataspace _trace_subjects { _env, "trace_subjects" };
|
2015-07-01 11:20:23 +02:00
|
|
|
|
|
|
|
unsigned _now = 0;
|
|
|
|
|
2017-03-20 12:04:55 +01:00
|
|
|
Genode::Heap _heap { _env.ram(), _env.rm() };
|
|
|
|
|
|
|
|
Cpu_registry _cpu_registry { _heap };
|
2015-07-01 11:20:23 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
void _handle_trace_subjects()
|
2015-07-01 11:20:23 +02:00
|
|
|
{
|
|
|
|
_trace_subjects.update();
|
|
|
|
|
2016-05-11 18:21:47 +02:00
|
|
|
if (!_trace_subjects.valid())
|
2015-07-01 11:20:23 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
_cpu_registry.advance(++_now);
|
|
|
|
|
|
|
|
try {
|
|
|
|
Xml_node subjects(_trace_subjects.local_addr<char>());
|
|
|
|
_cpu_registry.import_trace_subjects(subjects, _now);
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
} catch (...) { Genode::error("failed to import trace subjects"); }
|
2015-07-01 11:20:23 +02:00
|
|
|
}
|
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
Genode::Signal_handler<Scene> _trace_subjects_handler;
|
2015-07-01 11:20:23 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2019-04-09 15:46:36 +02:00
|
|
|
Scene(Genode::Env &env, Genode::uint64_t update_rate_ms,
|
2020-06-12 11:23:57 +02:00
|
|
|
Gui::Point pos, Gui::Area size)
|
2015-07-01 11:20:23 +02:00
|
|
|
:
|
2016-11-25 16:54:49 +01:00
|
|
|
Nano3d::Scene<PT>(env, update_rate_ms, pos, size),
|
|
|
|
_env(env), _size(size),
|
|
|
|
_config_handler(env.ep(), *this, &Scene::_handle_config),
|
|
|
|
_trace_subjects_handler(env.ep(), *this, &Scene::_handle_trace_subjects)
|
2015-07-01 11:20:23 +02:00
|
|
|
{
|
2016-11-25 16:54:49 +01:00
|
|
|
_config.sigh(_config_handler);
|
|
|
|
_handle_config();
|
2015-07-01 11:20:23 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
_trace_subjects.sigh(_trace_subjects_handler);
|
2015-07-01 11:20:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
2017-03-20 12:04:55 +01:00
|
|
|
Polygon::Shaded_painter _shaded_painter { _heap, _size.h() };
|
2015-07-01 11:20:23 +02:00
|
|
|
|
|
|
|
long _activity_sum[Timeline::HISTORY_LEN];
|
|
|
|
long _y_level[Timeline::HISTORY_LEN];
|
|
|
|
long _y_curr[Timeline::HISTORY_LEN];
|
|
|
|
|
|
|
|
void _plot_cpu(Genode::Surface<PT> &pixel,
|
|
|
|
Genode::Surface<Genode::Pixel_alpha8> &alpha,
|
2020-06-12 11:23:57 +02:00
|
|
|
Cpu const &cpu, Gui::Rect rect)
|
2015-07-01 11:20:23 +02:00
|
|
|
{
|
|
|
|
enum { HISTORY_LEN = Timeline::HISTORY_LEN };
|
|
|
|
|
|
|
|
/* calculate activity sum for each point in history */
|
|
|
|
for (unsigned i = 0; i < HISTORY_LEN; i++)
|
|
|
|
_activity_sum[i] = cpu.activity_sum(i);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < HISTORY_LEN; i++)
|
|
|
|
_y_level[i] = 0;
|
|
|
|
|
|
|
|
int const h = rect.h();
|
|
|
|
int const w = rect.w();
|
|
|
|
|
|
|
|
cpu.for_each_timeline([&] (Timeline const &timeline) {
|
|
|
|
|
2016-05-11 18:21:47 +02:00
|
|
|
if (timeline.kernel())
|
2015-07-01 11:20:23 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
bool first = true;
|
|
|
|
|
|
|
|
/* reset values of the current timeline */
|
|
|
|
for (unsigned i = 0; i < HISTORY_LEN; i++)
|
|
|
|
_y_curr[i] = 0;
|
|
|
|
|
|
|
|
Color const top_color = timeline.color(Timeline::COLOR_TOP);
|
|
|
|
Color const bottom_color = timeline.color(Timeline::COLOR_BOTTOM);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < HISTORY_LEN; i++) {
|
|
|
|
|
|
|
|
unsigned const t = (_now - i - 0) % HISTORY_LEN;
|
|
|
|
unsigned const prev_t = (_now - i + 1) % HISTORY_LEN;
|
|
|
|
|
|
|
|
unsigned long const activity = timeline.activity(t);
|
|
|
|
|
|
|
|
int const dy = _activity_sum[t] ? (activity*h) / _activity_sum[t] : 0;
|
|
|
|
|
|
|
|
_y_curr[t] = _y_level[t] + dy;
|
|
|
|
|
|
|
|
if (!first) {
|
|
|
|
|
|
|
|
/* draw polygon */
|
|
|
|
int const n = HISTORY_LEN - 1;
|
|
|
|
int const x0 = ((n - i + 0)*w)/n + rect.x1();
|
|
|
|
int const x1 = ((n - i + 1)*w)/n + rect.x1();
|
|
|
|
|
|
|
|
int const y0 = rect.y1() + h - _y_curr[t];
|
|
|
|
int const y1 = rect.y1() + h - _y_curr[prev_t];
|
|
|
|
int const y2 = rect.y1() + h - _y_level[prev_t];
|
|
|
|
int const y3 = rect.y1() + h - _y_level[t];
|
|
|
|
|
|
|
|
typedef Polygon::Shaded_painter::Point Point;
|
|
|
|
Point points[4];
|
|
|
|
points[0] = Point(x0, y0, top_color);
|
|
|
|
points[1] = Point(x1, y1, top_color);
|
|
|
|
points[2] = Point(x1, y2, y1 == y2 ? top_color : bottom_color);
|
|
|
|
points[3] = Point(x0, y3, y3 == y0 ? top_color : bottom_color);
|
|
|
|
_shaded_painter.paint(pixel, alpha, points, 4);
|
|
|
|
|
|
|
|
/* drop shadow */
|
|
|
|
Color const black (0, 0, 0, 100);
|
|
|
|
Color const translucent (0, 0, 0, 0);
|
|
|
|
|
|
|
|
points[0] = Point(x0, y3 - 5, translucent);
|
|
|
|
points[1] = Point(x1, y2 - 5, translucent);
|
|
|
|
points[2] = Point(x1, y2, black);
|
|
|
|
points[3] = Point(x0, y3, black);
|
|
|
|
|
|
|
|
_shaded_painter.paint(pixel, alpha, points, 4);
|
|
|
|
}
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* raise level by the values of the current timeline */
|
|
|
|
for (unsigned i = 0; i < HISTORY_LEN; i++)
|
|
|
|
_y_level[i] = _y_curr[i];
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Scene interface
|
|
|
|
*/
|
|
|
|
void render(Genode::Surface<PT> &pixel,
|
|
|
|
Genode::Surface<Genode::Pixel_alpha8> &alpha) override
|
|
|
|
{
|
|
|
|
/* background */
|
|
|
|
Color const top_color = Color(10, 10, 10, 20);
|
|
|
|
Color const bottom_color = Color(10, 10, 10, 100);
|
|
|
|
|
|
|
|
unsigned const w = pixel.size().w();
|
|
|
|
unsigned const h = pixel.size().h();
|
|
|
|
|
|
|
|
typedef Polygon::Shaded_painter::Point Point;
|
|
|
|
Point points[4];
|
|
|
|
points[0] = Point(0, 0, top_color);
|
|
|
|
points[1] = Point(w - 1, 0, top_color);
|
|
|
|
points[2] = Point(w - 1, h - 1, bottom_color);
|
|
|
|
points[3] = Point(0, h - 1, bottom_color);
|
|
|
|
_shaded_painter.paint(pixel, alpha, points, 4);
|
|
|
|
|
|
|
|
/* determine number of CPUs */
|
|
|
|
unsigned num_cpus = 0;
|
2019-01-14 20:04:40 +01:00
|
|
|
_cpu_registry.for_each_cpu([&] (Cpu const &) { num_cpus++; });
|
2015-07-01 11:20:23 +02:00
|
|
|
|
|
|
|
if (num_cpus == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* plot graphs for the CPUs below each other */
|
|
|
|
enum { GAP = 8 };
|
2020-06-12 11:23:57 +02:00
|
|
|
Gui::Point const step(0, _size.h()/num_cpus);
|
|
|
|
Gui::Area const size(_size.w(), step.y() - GAP);
|
|
|
|
Gui::Point point(0, GAP/2);
|
2015-07-01 11:20:23 +02:00
|
|
|
|
|
|
|
_cpu_registry.for_each_cpu([&] (Cpu const &cpu) {
|
2020-06-12 11:23:57 +02:00
|
|
|
_plot_cpu(pixel, alpha, cpu, Gui::Rect(point, size));
|
2015-07-01 11:20:23 +02:00
|
|
|
point = point + step;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
void Component::construct(Genode::Env &env)
|
2015-07-01 11:20:23 +02:00
|
|
|
{
|
|
|
|
enum { UPDATE_RATE_MS = 250 };
|
|
|
|
|
2020-06-16 15:46:59 +02:00
|
|
|
static Cpu_load_display::Scene<Genode::Pixel_rgb888>
|
2016-11-25 16:54:49 +01:00
|
|
|
scene(env, UPDATE_RATE_MS,
|
2020-06-12 11:23:57 +02:00
|
|
|
Gui::Point(0, 0), Gui::Area(400, 400));
|
2015-07-01 11:20:23 +02:00
|
|
|
}
|