From 858505918a2c109484fb37924c0cb0b7d949b85a Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Sat, 23 Apr 2022 22:15:35 +0200 Subject: [PATCH] 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 --- .../base-nova/include/nova/syscall-generic.h | 8 ++ .../include/spec/32bit/nova/syscalls.h | 79 +++++++++++++++++-- .../include/spec/64bit/nova/syscalls.h | 64 +++++++++++++-- repos/base-nova/ports/nova.hash | 2 +- repos/base-nova/ports/nova.port | 2 +- repos/base-nova/src/core/platform.cc | 58 +++++++------- repos/base-nova/src/core/platform_thread.cc | 17 ++-- repos/base-nova/src/core/thread_start.cc | 8 +- .../src/core/vm_session_component.cc | 7 +- 9 files changed, 193 insertions(+), 52 deletions(-) diff --git a/repos/base-nova/include/nova/syscall-generic.h b/repos/base-nova/include/nova/syscall-generic.h index 9218d99393..1692e5aa84 100644 --- a/repos/base-nova/include/nova/syscall-generic.h +++ b/repos/base-nova/include/nova/syscall-generic.h @@ -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, }; /** diff --git a/repos/base-nova/include/spec/32bit/nova/syscalls.h b/repos/base-nova/include/spec/32bit/nova/syscalls.h index 919214fc70..e52c61d334 100644 --- a/repos/base-nova/include/spec/32bit/nova/syscalls.h +++ b/repos/base-nova/include/spec/32bit/nova/syscalls.h @@ -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_ */ diff --git a/repos/base-nova/include/spec/64bit/nova/syscalls.h b/repos/base-nova/include/spec/64bit/nova/syscalls.h index 5576fb8d4a..3ab7e887ed 100644 --- a/repos/base-nova/include/spec/64bit/nova/syscalls.h +++ b/repos/base-nova/include/spec/64bit/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); } diff --git a/repos/base-nova/ports/nova.hash b/repos/base-nova/ports/nova.hash index edf4c29f5a..bf8d5f7d78 100644 --- a/repos/base-nova/ports/nova.hash +++ b/repos/base-nova/ports/nova.hash @@ -1 +1 @@ -6a1f0e6e6386e60748607c3c460c51a36a162307 +33a2fa953ec52b0f63b921f4d33d68891c0aada0 diff --git a/repos/base-nova/ports/nova.port b/repos/base-nova/ports/nova.port index 804413f12b..90f33a67b9 100644 --- a/repos/base-nova/ports/nova.port +++ b/repos/base-nova/ports/nova.port @@ -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)) diff --git a/repos/base-nova/src/core/platform.cc b/repos/base-nova/src/core/platform.cc index 6b8354e2fd..bb887537f9 100644 --- a/repos/base-nova/src/core/platform.cc +++ b/repos/base-nova/src/core/platform.cc @@ -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, diff --git a/repos/base-nova/src/core/platform_thread.cc b/repos/base-nova/src/core/platform_thread.cc index 10b89ab62f..dede726d2e 100644 --- a/repos/base-nova/src/core/platform_thread.cc +++ b/repos/base-nova/src/core/platform_thread.cc @@ -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 }; } diff --git a/repos/base-nova/src/core/thread_start.cc b/repos/base-nova/src/core/thread_start.cc index 7dc4024bbf..e600464c91 100644 --- a/repos/base-nova/src/core/thread_start.cc +++ b/repos/base-nova/src/core/thread_start.cc @@ -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) diff --git a/repos/base-nova/src/core/vm_session_component.cc b/repos/base-nova/src/core/vm_session_component.cc index 32195e4fc3..7d3d72c3e1 100644 --- a/repos/base-nova/src/core/vm_session_component.cc +++ b/repos/base-nova/src/core/vm_session_component.cc @@ -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 }; }