mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-20 17:11:45 +00:00
nova: support EC time in trace subject info
The vanilla NOVA kernel solely supports tracking and exporting of execution times per SC kernel object, but not per thread (EC object). The commit extends to track execution times per EC in the NOVA kernel, exporting it to Genode's 'core' roottask and populating Genode's Trace::Subject_info structure. Fixes #4481
This commit is contained in:
parent
f6fedd5348
commit
858505918a
@ -242,6 +242,14 @@ namespace Nova {
|
||||
EC_DONATE_SC = 2U,
|
||||
EC_RESCHEDULE = 3U,
|
||||
EC_MIGRATE = 4U,
|
||||
EC_TIME = 5U,
|
||||
};
|
||||
|
||||
enum Sc_op {
|
||||
SC_TIME_IDLE = 0,
|
||||
SC_TIME_CROSS = 1,
|
||||
SC_TIME_KILLED = 2,
|
||||
SC_EC_TIME = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -182,6 +182,40 @@ namespace Nova {
|
||||
return (uint8_t)status;
|
||||
}
|
||||
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t syscall_6(Syscall s, uint8_t flags, unsigned sel,
|
||||
mword_t &p1, mword_t &p2, mword_t &p3,
|
||||
mword_t &p4)
|
||||
{
|
||||
mword_t status = eax(s, flags, sel);
|
||||
|
||||
asm volatile (" push %%ebp;"
|
||||
" push %%ebx;"
|
||||
|
||||
" mov %%ecx, %%ebx;"
|
||||
" mov %%esp, %%ecx;"
|
||||
" mov %%edx, %%ebp;"
|
||||
|
||||
" call 0f;"
|
||||
"0:"
|
||||
" addl $(1f-0b), (%%esp);"
|
||||
" mov (%%esp), %%edx;"
|
||||
"sysenter;"
|
||||
"1:"
|
||||
|
||||
" mov %%ebp, %%edx;"
|
||||
" mov %%ebx, %%ecx;"
|
||||
" pop %%ebx;"
|
||||
" pop %%ebp;"
|
||||
: "+a" (status), "+D" (p1), "+S" (p2), "+c" (p3),
|
||||
"+d" (p4)
|
||||
:
|
||||
: "memory");
|
||||
return (uint8_t)status;
|
||||
}
|
||||
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t call(unsigned pt)
|
||||
{
|
||||
@ -239,14 +273,51 @@ namespace Nova {
|
||||
}
|
||||
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t util_time(Syscall const syscall, mword_t const cap,
|
||||
uint8_t const op, unsigned long long &time)
|
||||
{
|
||||
mword_t time_h = 0, time_l = 0;
|
||||
uint8_t res = syscall_5(syscall, op, cap, time_h, time_l);
|
||||
time = (uint64_t(time_h) << 32ULL) | uint64_t(time_l);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t sc_ec_time(mword_t const cap_sc, mword_t const cap_ec,
|
||||
unsigned long long &time_sc,
|
||||
unsigned long long &time_ec)
|
||||
{
|
||||
mword_t time_h_sc = cap_ec, time_l_sc = 0;
|
||||
mword_t time_h_ec = 0, time_l_ec = 0;
|
||||
uint8_t res = syscall_6(NOVA_SC_CTRL, Sc_op::SC_EC_TIME, cap_sc,
|
||||
time_h_sc, time_l_sc, time_h_ec,
|
||||
time_l_ec);
|
||||
time_sc = (uint64_t(time_h_sc) << 32ULL) | uint64_t(time_l_sc);
|
||||
time_ec = (uint64_t(time_h_ec) << 32ULL) | uint64_t(time_l_ec);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t ec_ctrl(Ec_op op, mword_t ec = ~0UL, mword_t para = ~0UL,
|
||||
Crd crd = 0)
|
||||
{
|
||||
if (op == EC_TIME)
|
||||
return NOVA_INV_HYPERCALL;
|
||||
|
||||
return syscall_2(NOVA_EC_CTRL, op, ec, para, crd.value());
|
||||
}
|
||||
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t ec_time(mword_t const ec, unsigned long long &time)
|
||||
{
|
||||
return util_time(NOVA_EC_CTRL, ec, Ec_op::EC_TIME, time);
|
||||
}
|
||||
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t create_sc(unsigned sc, unsigned pd, unsigned ec, Qpd qpd)
|
||||
{
|
||||
@ -396,13 +467,9 @@ namespace Nova {
|
||||
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t sc_ctrl(unsigned sc, unsigned long long &time, uint8_t op = 0)
|
||||
inline uint8_t sc_ctrl(unsigned const sc, unsigned long long &time, uint8_t op = 0)
|
||||
{
|
||||
mword_t time_h = 0, time_l = 0;
|
||||
uint8_t res = syscall_5(NOVA_SC_CTRL, op, sc, time_h, time_l);
|
||||
time = time_h;
|
||||
time = (time << 32ULL) | time_l;
|
||||
return res;
|
||||
return util_time(NOVA_SC_CTRL, sc, op, time);
|
||||
}
|
||||
}
|
||||
#endif /* _INCLUDE__SPEC__32BIT__NOVA__SYSCALLS_H_ */
|
||||
|
@ -132,6 +132,24 @@ namespace Nova {
|
||||
return (uint8_t)status;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t syscall_6(Syscall s, uint8_t flags, mword_t sel,
|
||||
mword_t &p1, mword_t &p2, mword_t &p3,
|
||||
mword_t &p4)
|
||||
{
|
||||
mword_t status = rdi(s, flags, sel);
|
||||
|
||||
register mword_t r8 asm ("r8") = p4;
|
||||
|
||||
asm volatile ("syscall"
|
||||
: "+D" (status), "+S"(p1), "+d"(p2), "+a"(p3), "+r"(r8)
|
||||
:
|
||||
: "rcx", "r11", "memory");
|
||||
|
||||
p4 = r8;
|
||||
|
||||
return (uint8_t)status;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t call(mword_t pt)
|
||||
@ -191,14 +209,51 @@ namespace Nova {
|
||||
}
|
||||
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t util_time(Syscall const syscall, mword_t const cap,
|
||||
uint8_t const op, unsigned long long &time)
|
||||
{
|
||||
mword_t time_h = 0, time_l = 0;
|
||||
uint8_t res = syscall_5(syscall, op, cap, time_h, time_l);
|
||||
time = (time_h << 32ULL) | (time_l & 0xFFFFFFFFULL);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t sc_ec_time(mword_t const cap_sc, mword_t const cap_ec,
|
||||
unsigned long long &time_sc,
|
||||
unsigned long long &time_ec)
|
||||
{
|
||||
mword_t time_h_sc = cap_ec, time_l_sc = 0;
|
||||
mword_t time_h_ec = 0, time_l_ec = 0;
|
||||
uint8_t res = syscall_6(NOVA_SC_CTRL, Sc_op::SC_EC_TIME, cap_sc,
|
||||
time_h_sc, time_l_sc, time_h_ec,
|
||||
time_l_ec);
|
||||
time_sc = (time_h_sc << 32ULL) | (time_l_sc & 0xFFFFFFFFULL);
|
||||
time_ec = (time_h_ec << 32ULL) | (time_l_ec & 0xFFFFFFFFULL);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t ec_ctrl(Ec_op op, mword_t ec = ~0UL, mword_t para = ~0UL,
|
||||
Crd crd = 0)
|
||||
{
|
||||
if (op == EC_TIME)
|
||||
return NOVA_INV_HYPERCALL;
|
||||
|
||||
return syscall_2(NOVA_EC_CTRL, op, ec, para, crd.value());
|
||||
}
|
||||
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t ec_time(mword_t const ec, unsigned long long &time)
|
||||
{
|
||||
return util_time(NOVA_EC_CTRL, ec, Ec_op::EC_TIME, time);
|
||||
}
|
||||
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t create_sc(mword_t sc, mword_t pd, mword_t ec, Qpd qpd)
|
||||
{
|
||||
@ -316,13 +371,10 @@ namespace Nova {
|
||||
|
||||
|
||||
ALWAYS_INLINE
|
||||
inline uint8_t sc_ctrl(mword_t sm, unsigned long long &time, uint8_t op = 0)
|
||||
inline uint8_t sc_ctrl(mword_t const sc, unsigned long long &time,
|
||||
Sc_op const op)
|
||||
{
|
||||
mword_t time_h = 0, time_l = 0;
|
||||
uint8_t res = syscall_5(NOVA_SC_CTRL, op, sm, time_h, time_l);
|
||||
time = time_h;
|
||||
time = (time << 32ULL) | (time_l & 0xFFFFFFFFULL);
|
||||
return res;
|
||||
return util_time(NOVA_SC_CTRL, sc, op, time);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1 +1 @@
|
||||
6a1f0e6e6386e60748607c3c460c51a36a162307
|
||||
33a2fa953ec52b0f63b921f4d33d68891c0aada0
|
||||
|
@ -4,7 +4,7 @@ DOWNLOADS := nova.git
|
||||
|
||||
# r10 branch
|
||||
URL(nova) := https://github.com/alex-ab/NOVA.git
|
||||
REV(nova) := 7e3b5d3916825fb32e011cff4ee9b09ecdcb8d05
|
||||
REV(nova) := 00dc49bc18e7f72a9c85487e8f94fd859511d89d
|
||||
DIR(nova) := src/kernel/nova
|
||||
|
||||
PATCHES := $(sort $(wildcard $(REP_DIR)/patches/*.patch))
|
||||
|
@ -391,23 +391,6 @@ Platform::Platform()
|
||||
Obj_crd(sc_idle_base, log2cpu), true))
|
||||
nova_die();
|
||||
|
||||
/* test reading out idle SCs */
|
||||
bool sc_init = true;
|
||||
for (unsigned i = 0; i < hip.cpu_max(); i++) {
|
||||
|
||||
if (!hip.is_cpu_enabled(i))
|
||||
continue;
|
||||
|
||||
uint64_t n_time;
|
||||
uint8_t res = Nova::sc_ctrl(sc_idle_base + i, n_time);
|
||||
if (res != Nova::NOVA_OK) {
|
||||
sc_init = false;
|
||||
error(i, " ", res, " ", n_time, " - failed");
|
||||
}
|
||||
}
|
||||
if (!sc_init)
|
||||
nova_die();
|
||||
|
||||
/* configure virtual address spaces */
|
||||
#ifdef __x86_64__
|
||||
_vm_size = 0x7fffc0000000UL - _vm_base;
|
||||
@ -865,19 +848,30 @@ Platform::Platform()
|
||||
Info trace_source_info() const override
|
||||
{
|
||||
uint64_t sc_time = 0;
|
||||
uint64_t ec_time = 0;
|
||||
uint8_t res = 0;
|
||||
|
||||
enum SYSCALL_OP { IDLE_SC = 0, CROSS_SC = 1,
|
||||
KILLED_SC = 2 };
|
||||
uint8_t syscall_op = (name == "cross") ? CROSS_SC :
|
||||
((name == "killed") ? KILLED_SC : IDLE_SC);
|
||||
if (name == "killed") {
|
||||
res = Nova::sc_ec_time(sc_sel, sc_sel,
|
||||
sc_time, ec_time);
|
||||
} else {
|
||||
auto syscall_op = (name == "cross")
|
||||
? Sc_op::SC_TIME_CROSS
|
||||
: Sc_op::SC_TIME_IDLE;
|
||||
|
||||
res = Nova::sc_ctrl(sc_sel, sc_time,
|
||||
syscall_op);
|
||||
|
||||
if (syscall_op == Sc_op::SC_TIME_IDLE)
|
||||
ec_time = sc_time;
|
||||
}
|
||||
|
||||
uint8_t res = Nova::sc_ctrl(sc_sel, sc_time, syscall_op);
|
||||
if (res != Nova::NOVA_OK)
|
||||
warning("sc_ctrl on idle SC cap, op=", syscall_op,
|
||||
warning("sc_ctrl on ", name, " failed"
|
||||
", res=", res);
|
||||
|
||||
return { Session_label("kernel"), Trace::Thread_name(name),
|
||||
Trace::Execution_time(sc_time, sc_time), affinity };
|
||||
Trace::Execution_time(ec_time, sc_time), affinity };
|
||||
}
|
||||
|
||||
Trace_source(Trace::Source_registry ®istry,
|
||||
@ -920,16 +914,26 @@ Platform::Platform()
|
||||
*/
|
||||
Info trace_source_info() const override
|
||||
{
|
||||
uint64_t ec_time = 0;
|
||||
uint64_t sc_time = 0;
|
||||
|
||||
if (name == "root") {
|
||||
uint8_t res = Nova::sc_ctrl(ec_sc_sel + 1, sc_time);
|
||||
uint8_t res = Nova::sc_ec_time(ec_sc_sel + 1,
|
||||
ec_sc_sel,
|
||||
sc_time,
|
||||
ec_time);
|
||||
if (res != Nova::NOVA_OK)
|
||||
warning("sc_ctrl for ", name, " thread failed res=", res);
|
||||
warning("sc_ec_time for root failed "
|
||||
"res=", res);
|
||||
} else {
|
||||
uint8_t res = Nova::ec_time(ec_sc_sel, ec_time);
|
||||
if (res != Nova::NOVA_OK)
|
||||
warning("ec_time for", name, " thread "
|
||||
"failed res=", res);
|
||||
}
|
||||
|
||||
return { Session_label("core"), name,
|
||||
Trace::Execution_time(sc_time, sc_time), location };
|
||||
Trace::Execution_time(ec_time, sc_time), location };
|
||||
}
|
||||
|
||||
Core_trace_source(Trace::Source_registry ®istry,
|
||||
|
@ -314,17 +314,22 @@ const char * Platform_thread::pd_name() const {
|
||||
|
||||
Trace::Execution_time Platform_thread::execution_time() const
|
||||
{
|
||||
unsigned long long time = 0;
|
||||
uint64_t sc_time = 0;
|
||||
uint64_t ec_time = 0;
|
||||
|
||||
/* for ECs without a SC we simply return 0 */
|
||||
if (!sc_created())
|
||||
return { time, time, Nova::Qpd::DEFAULT_QUANTUM, _priority };
|
||||
if (!sc_created()) {
|
||||
/* time executed by EC (on whatever SC) */
|
||||
uint8_t res = Nova::ec_time(_sel_ec(), ec_time);
|
||||
if (res != Nova::NOVA_OK)
|
||||
warning("ec_time failed res=", res);
|
||||
return { ec_time, sc_time, Nova::Qpd::DEFAULT_QUANTUM, _priority };
|
||||
}
|
||||
|
||||
uint8_t res = Nova::sc_ctrl(_sel_sc(), time);
|
||||
uint8_t res = Nova::sc_ec_time(_sel_sc(), _sel_ec(), sc_time, ec_time);
|
||||
if (res != Nova::NOVA_OK)
|
||||
warning("sc_ctrl failed res=", res);
|
||||
|
||||
return { time, time, Nova::Qpd::DEFAULT_QUANTUM, _priority };
|
||||
return { ec_time, sc_time, Nova::Qpd::DEFAULT_QUANTUM, _priority };
|
||||
}
|
||||
|
||||
|
||||
|
@ -127,10 +127,14 @@ void Thread::start()
|
||||
*/
|
||||
Info trace_source_info() const override
|
||||
{
|
||||
uint64_t sc_time = 0;
|
||||
uint64_t ec_time = 0;
|
||||
|
||||
uint8_t res = Nova::ec_time(thread.native_thread().ec_sel, ec_time);
|
||||
if (res != Nova::NOVA_OK)
|
||||
warning("ec_time for core thread failed res=", res);
|
||||
|
||||
return { Session_label("core"), thread.name(),
|
||||
Trace::Execution_time(sc_time, sc_time), thread._affinity };
|
||||
Trace::Execution_time(ec_time, 0), thread._affinity };
|
||||
}
|
||||
|
||||
Core_trace_source(Trace::Source_registry ®istry, Thread &t)
|
||||
|
@ -85,14 +85,15 @@ static uint8_t _with_kernel_quota_upgrade(addr_t const pd_target,
|
||||
|
||||
Trace::Source::Info Vm_session_component::Vcpu::trace_source_info() const
|
||||
{
|
||||
uint64_t ec_time = 0;
|
||||
uint64_t sc_time = 0;
|
||||
|
||||
uint8_t res = Nova::sc_ctrl(sc_sel(), sc_time);
|
||||
uint8_t res = Nova::sc_ec_time(sc_sel(), ec_sel(), sc_time, ec_time);
|
||||
if (res != Nova::NOVA_OK)
|
||||
warning("sc_ctrl failed res=", res);
|
||||
warning("vCPU sc_ec_time failed res=", res);
|
||||
|
||||
return { _label, String<5>("vCPU"),
|
||||
Trace::Execution_time(sc_time, sc_time,
|
||||
Trace::Execution_time(ec_time, sc_time,
|
||||
Nova::Qpd::DEFAULT_QUANTUM, _priority),
|
||||
_location };
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user