parent
36fac8e22b
commit
93ba870b2d
|
@ -7,7 +7,10 @@ Configuration
|
||||||
|
|
||||||
The interval of output generation can be defined via the 'period_ms' attribute
|
The interval of output generation can be defined via the 'period_ms' attribute
|
||||||
of the '<config>' node. The value is specified in milliseconds.
|
of the '<config>' node. The value is specified in milliseconds.
|
||||||
|
The threads with the top most execution time are shown per CPU. The sorting
|
||||||
|
of the execution time can be shown per thread ('ec' - execution context) or,
|
||||||
|
if supported by the kernel, per scheduling context of a thread ('sc').
|
||||||
|
|
||||||
The following example shows the default values.
|
The following example shows the default values.
|
||||||
|
|
||||||
! <config period_ms="5000"/>
|
! <config period_ms="5000" sort_time="ec"/>
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <base/heap.h>
|
#include <base/heap.h>
|
||||||
#include <os/reporter.h>
|
#include <os/reporter.h>
|
||||||
|
|
||||||
|
enum SORT_TIME { EC_TIME = 0, SC_TIME = 1};
|
||||||
|
|
||||||
struct Trace_subject_registry
|
struct Trace_subject_registry
|
||||||
{
|
{
|
||||||
|
@ -34,17 +35,23 @@ struct Trace_subject_registry
|
||||||
/**
|
/**
|
||||||
* Execution time during the last period
|
* Execution time during the last period
|
||||||
*/
|
*/
|
||||||
unsigned long long recent_execution_time = 0;
|
Genode::uint64_t recent_time[2] = { 0, 0 };
|
||||||
|
|
||||||
Entry(Genode::Trace::Subject_id id) : id(id) { }
|
Entry(Genode::Trace::Subject_id id) : id(id) { }
|
||||||
|
|
||||||
void update(Genode::Trace::Subject_info const &new_info)
|
void update(Genode::Trace::Subject_info const &new_info)
|
||||||
{
|
{
|
||||||
if (new_info.execution_time().thread_context < info.execution_time().thread_context)
|
if (new_info.execution_time().thread_context < info.execution_time().thread_context)
|
||||||
recent_execution_time = 0;
|
recent_time[EC_TIME] = 0;
|
||||||
else
|
else
|
||||||
recent_execution_time = new_info.execution_time().thread_context -
|
recent_time[EC_TIME] = new_info.execution_time().thread_context -
|
||||||
info.execution_time().thread_context;
|
info.execution_time().thread_context;
|
||||||
|
|
||||||
|
if (new_info.execution_time().scheduling_context < info.execution_time().scheduling_context)
|
||||||
|
recent_time[SC_TIME] = 0;
|
||||||
|
else
|
||||||
|
recent_time[SC_TIME] = new_info.execution_time().scheduling_context -
|
||||||
|
info.execution_time().scheduling_context;
|
||||||
|
|
||||||
info = new_info;
|
info = new_info;
|
||||||
}
|
}
|
||||||
|
@ -67,7 +74,8 @@ struct Trace_subject_registry
|
||||||
enum { MAX_CPUS_X = 16, MAX_CPUS_Y = 1, MAX_ELEMENTS_PER_CPU = 6};
|
enum { MAX_CPUS_X = 16, MAX_CPUS_Y = 1, MAX_ELEMENTS_PER_CPU = 6};
|
||||||
|
|
||||||
/* accumulated execution time on all CPUs */
|
/* accumulated execution time on all CPUs */
|
||||||
unsigned long long total [MAX_CPUS_X][MAX_CPUS_Y];
|
unsigned long long total_first [MAX_CPUS_X][MAX_CPUS_Y];
|
||||||
|
unsigned long long total_second [MAX_CPUS_X][MAX_CPUS_Y];
|
||||||
|
|
||||||
/* most significant consumer per CPU */
|
/* most significant consumer per CPU */
|
||||||
Entry const * load[MAX_CPUS_X][MAX_CPUS_Y][MAX_ELEMENTS_PER_CPU];
|
Entry const * load[MAX_CPUS_X][MAX_CPUS_Y][MAX_ELEMENTS_PER_CPU];
|
||||||
|
@ -121,7 +129,7 @@ struct Trace_subject_registry
|
||||||
|
|
||||||
/* remove dead threads which did not run in the last period */
|
/* remove dead threads which did not run in the last period */
|
||||||
if (e->info.state() == Genode::Trace::Subject_info::DEAD &&
|
if (e->info.state() == Genode::Trace::Subject_info::DEAD &&
|
||||||
!e->recent_execution_time) {
|
!e->recent_time[EC_TIME] && !e->recent_time[SC_TIME]) {
|
||||||
|
|
||||||
trace.free(e->id);
|
trace.free(e->id);
|
||||||
_entries.remove(e);
|
_entries.remove(e);
|
||||||
|
@ -144,12 +152,16 @@ struct Trace_subject_registry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void top()
|
void top(enum SORT_TIME sorting)
|
||||||
{
|
{
|
||||||
/* clear old calculations */
|
/* clear old calculations */
|
||||||
Genode::memset(total, 0, sizeof(total));
|
Genode::memset(total_first, 0, sizeof(total_first));
|
||||||
|
Genode::memset(total_second, 0, sizeof(total_second));
|
||||||
Genode::memset(load, 0, sizeof(load));
|
Genode::memset(load, 0, sizeof(load));
|
||||||
|
|
||||||
|
unsigned const first = sorting == EC_TIME ? EC_TIME : SC_TIME;
|
||||||
|
unsigned const second = sorting == EC_TIME ? SC_TIME : EC_TIME;
|
||||||
|
|
||||||
for (Entry const *e = _entries.first(); e; e = e->next()) {
|
for (Entry const *e = _entries.first(); e; e = e->next()) {
|
||||||
|
|
||||||
/* collect highest execution time per CPU */
|
/* collect highest execution time per CPU */
|
||||||
|
@ -163,7 +175,8 @@ struct Trace_subject_registry
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
total[x][y] += e->recent_execution_time;
|
total_first[x][y] += e->recent_time[first];
|
||||||
|
total_second[x][y] += e->recent_time[second];
|
||||||
|
|
||||||
enum { NONE = ~0U };
|
enum { NONE = ~0U };
|
||||||
unsigned replace = NONE;
|
unsigned replace = NONE;
|
||||||
|
@ -182,16 +195,16 @@ struct Trace_subject_registry
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < MAX_ELEMENTS_PER_CPU; i++) {
|
for (unsigned i = 0; i < MAX_ELEMENTS_PER_CPU; i++) {
|
||||||
if (e->recent_execution_time
|
if (e->recent_time[first]
|
||||||
<= load[x][y][i]->recent_execution_time)
|
<= load[x][y][i]->recent_time[first])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (replace == NONE) {
|
if (replace == NONE) {
|
||||||
replace = i;
|
replace = i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (load[x][y][replace]->recent_execution_time
|
if (load[x][y][replace]->recent_time[first]
|
||||||
> load[x][y][i]->recent_execution_time)
|
> load[x][y][i]->recent_time[first])
|
||||||
replace = i;
|
replace = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,8 +224,8 @@ struct Trace_subject_registry
|
||||||
if (!load[x][y][j])
|
if (!load[x][y][j])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (load[x][y][i]->recent_execution_time
|
if (load[x][y][i]->recent_time[first]
|
||||||
< load[x][y][j]->recent_execution_time) {
|
< load[x][y][j]->recent_time[first]) {
|
||||||
|
|
||||||
Entry const * tmp = load[x][y][j];
|
Entry const * tmp = load[x][y][j];
|
||||||
load[x][y][j] = load[x][y][i];
|
load[x][y][j] = load[x][y][i];
|
||||||
|
@ -232,23 +245,47 @@ struct Trace_subject_registry
|
||||||
for (unsigned x = 0; x < MAX_CPUS_X; x++) {
|
for (unsigned x = 0; x < MAX_CPUS_X; x++) {
|
||||||
for (unsigned y = 0; y < MAX_CPUS_Y; y++) {
|
for (unsigned y = 0; y < MAX_CPUS_Y; y++) {
|
||||||
for (unsigned i = 0; i < MAX_ELEMENTS_PER_CPU; i++) {
|
for (unsigned i = 0; i < MAX_ELEMENTS_PER_CPU; i++) {
|
||||||
if (!load[x][y][i] || !total[x][y])
|
if (!load[x][y][i] || !total_first[x][y])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
unsigned percent = load[x][y][i]->recent_execution_time * 100 / total[x][y];
|
unsigned ec_percent = load[x][y][i]->recent_time[first] * 100 / total_first[x][y];
|
||||||
unsigned rest = load[x][y][i]->recent_execution_time * 10000 / total[x][y] - (percent * 100);
|
unsigned ec_rest = load[x][y][i]->recent_time[first] * 10000 / total_first[x][y] - (ec_percent * 100);
|
||||||
|
|
||||||
|
unsigned sc_percent = 0;
|
||||||
|
unsigned sc_rest = 0;
|
||||||
|
if (total_second[x][y]) {
|
||||||
|
sc_percent = load[x][y][i]->recent_time[second] * 100 / total_second[x][y];
|
||||||
|
sc_rest = load[x][y][i]->recent_time[second] * 10000 / total_second[x][y] - (sc_percent * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum { NAME_SPACE = 24 };
|
||||||
|
static char space[NAME_SPACE];
|
||||||
|
Genode::memset(space, ' ', NAME_SPACE - 1);
|
||||||
|
|
||||||
|
unsigned thread_name_len = load[x][y][i]->info.thread_name().length();
|
||||||
|
if (!thread_name_len)
|
||||||
|
space[NAME_SPACE - 1] = 0;
|
||||||
|
else
|
||||||
|
if (thread_name_len >= NAME_SPACE)
|
||||||
|
space[0] = 0;
|
||||||
|
else
|
||||||
|
space[NAME_SPACE - thread_name_len] = 0;
|
||||||
|
|
||||||
|
Genode::String<NAME_SPACE> space_string(space);
|
||||||
|
|
||||||
using Genode::log;
|
using Genode::log;
|
||||||
log("cpu=", load[x][y][i]->info.affinity().xpos(), ".",
|
log("cpu=", load[x][y][i]->info.affinity().xpos(), ".",
|
||||||
load[x][y][i]->info.affinity().ypos(), " ",
|
load[x][y][i]->info.affinity().ypos(), " ",
|
||||||
percent < 10 ? " " : (percent < 100 ? " " : ""),
|
ec_percent < 10 ? " " : (ec_percent < 100 ? " " : ""),
|
||||||
percent, ".", rest < 10 ? "0" : "", rest, "% "
|
ec_percent, ".", ec_rest < 10 ? "0" : "", ec_rest, "% ",
|
||||||
"thread='", load[x][y][i]->info.thread_name(), "' "
|
sc_percent < 10 ? " " : (sc_percent < 100 ? " " : ""),
|
||||||
|
sc_percent, ".", sc_rest < 10 ? "0" : "", sc_rest, "% "
|
||||||
|
"thread='", load[x][y][i]->info.thread_name(), "' ", space_string,
|
||||||
"label='", load[x][y][i]->info.session_label(), "'");
|
"label='", load[x][y][i]->info.session_label(), "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (load[0][0][0] && load[0][0][0]->recent_execution_time)
|
if (load[0][0][0] && load[0][0][0]->recent_time[first])
|
||||||
Genode::log("");
|
Genode::log("");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -278,6 +315,8 @@ struct App::Main
|
||||||
|
|
||||||
unsigned long _period_ms = _default_period_ms();
|
unsigned long _period_ms = _default_period_ms();
|
||||||
|
|
||||||
|
SORT_TIME _sort { EC_TIME };
|
||||||
|
|
||||||
Attached_rom_dataspace _config { _env, "config" };
|
Attached_rom_dataspace _config { _env, "config" };
|
||||||
|
|
||||||
Timer::Connection _timer { _env };
|
Timer::Connection _timer { _env };
|
||||||
|
@ -312,6 +351,16 @@ void App::Main::_handle_config()
|
||||||
|
|
||||||
_period_ms = _config.xml().attribute_value("period_ms", _default_period_ms());
|
_period_ms = _config.xml().attribute_value("period_ms", _default_period_ms());
|
||||||
|
|
||||||
|
String<8> ec_sc(_config.xml().attribute_value("sort_time", String<8>("ec")));
|
||||||
|
if (ec_sc == "ec")
|
||||||
|
_sort = EC_TIME;
|
||||||
|
else
|
||||||
|
_sort = SC_TIME;
|
||||||
|
|
||||||
|
log("sorting based on ",
|
||||||
|
_sort == EC_TIME ? "execution context (ec) [other option is scheduling context (sc)]"
|
||||||
|
: "scheduling context (sc) [other option is execution context (ec)]");
|
||||||
|
|
||||||
_timer.trigger_periodic(1000*_period_ms);
|
_timer.trigger_periodic(1000*_period_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +377,7 @@ void App::Main::_handle_period()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* show most significant consumers */
|
/* show most significant consumers */
|
||||||
_trace_subject_registry.top();
|
_trace_subject_registry.top(_sort);
|
||||||
|
|
||||||
/* by destructing the session we free up the allocated memory in core */
|
/* by destructing the session we free up the allocated memory in core */
|
||||||
if (reconstruct) {
|
if (reconstruct) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user