kernel: Let user_debugger take care of tracking syscall runtime.

If we just use the kernel entry time, then the pre-syscall tracing
routine (with a debugger message send) will be counted in the syscall's
runtime.

Makes the output of timing in strace and strace -c much more accurate,
however it won't include the "syscall overhead" (time spent in the
syscall entry routines, etc.) But we already can't account for time
spent in the userland-to-kernel transition, so that should probably
be measured some other way if knowing it is desired.

In fact, on architectures which used the generic syscall dispatcher
(e.g. RISC-V), this is the behavior that already existed. So this just
makes x86 consistent with them.

Change-Id: I8cef6111e478ab49b0584e15575172eea77a8760
Reviewed-on: https://review.haiku-os.org/c/haiku/+/8240
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Augustin Cavalier
2024-09-07 15:31:15 +00:00
committed by waddlesplash
parent 2358db9297
commit 788da26bbc
7 changed files with 44 additions and 56 deletions
+5 -4
View File
@@ -122,8 +122,10 @@ struct thread_debug_info {
// profiling related part; if samples != NULL, the thread is profiled
struct {
bigtime_t interval;
// sampling interval
union {
bigtime_t interval;
bigtime_t syscall_start_time;
};
area_id sample_area;
// cloned sample buffer area
addr_t* samples;
@@ -253,8 +255,7 @@ void init_user_debug();
// debug event callbacks
void user_debug_pre_syscall(uint32 syscall, void *args);
void user_debug_post_syscall(uint32 syscall, void *args, uint64 returnValue,
bigtime_t startTime);
void user_debug_post_syscall(uint32 syscall, void *args, uint64 returnValue);
bool user_debug_exception_occurred(debug_exception_type exception, int signal);
bool user_debug_handle_signal(int signal, struct sigaction *handler,
siginfo_t *info, bool deadly);
+8 -3
View File
@@ -300,6 +300,9 @@ record_syscall_stats(const Syscall& syscall, debug_post_syscall& message)
syscall_stats& stats = sSyscallStats[syscall.Name()];
stats.count++;
if (message.start_time == 0)
return;
bigtime_t time = message.end_time - message.start_time;
stats.time += time;
sSyscallTime += time;
@@ -457,12 +460,14 @@ print_syscall(FILE *outputFile, Syscall* syscall, debug_post_syscall &message,
print_to_string(&string, &length, ")");
}
bigtime_t duration = 0;
if (message.start_time != 0)
duration = message.end_time - message.start_time;
if (colorize) {
print_to_string(&string, &length, " %s(%lld us)%s\n", kTerminalTextMagenta,
message.end_time - message.start_time, kTerminalTextNormal);
duration, kTerminalTextNormal);
} else {
print_to_string(&string, &length, " (%lld us)\n",
message.end_time - message.start_time);
print_to_string(&string, &length, " (%lld us)\n", duration);
}
//for (int32 i = 0; i < 16; i++) {
+1 -20
View File
@@ -57,22 +57,6 @@
UPDATE_THREAD_USER_TIME_COMMON() \
UNLOCK_THREAD_TIME()
#define UPDATE_THREAD_USER_TIME_PUSH_TIME() \
call system_time; \
push %edx; \
push %eax; \
\
LOCK_THREAD_TIME() \
\
/* recover the system time, note that */ \
/* LOCK_THREAD_TIME() leaves an address on the stack */ \
movl 4(%esp), %eax; \
movl 8(%esp), %edx; \
\
UPDATE_THREAD_USER_TIME_COMMON() \
\
UNLOCK_THREAD_TIME()
#define UPDATE_THREAD_KERNEL_TIME() \
LOCK_THREAD_TIME() \
\
@@ -624,8 +608,7 @@ STATIC_FUNCTION(handle_syscall):
STOP_USER_DEBUGGING()
// update the thread's user time
UPDATE_THREAD_USER_TIME_PUSH_TIME()
// leave the time on the stack (needed for post syscall debugging)
UPDATE_THREAD_USER_TIME()
sti // enable interrupts
@@ -687,8 +670,6 @@ FUNCTION_END(handle_syscall)
// post syscall debugging
testl $THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi)
jz 2f
pushl -8(%ebp) // syscall start time
pushl -12(%ebp)
xor %edx, %edx
testl $THREAD_FLAGS_64_BIT_SYSCALL_RETURN, THREAD_flags(%edi)
jz 1f
@@ -81,8 +81,6 @@
LOCK_THREAD_TIME() \
\
call system_time; \
\
/* Preserve system_time for post syscall debug */ \
movq %rax, %r13; \
\
/* thread->user_time += now - thread->last_time; */ \
@@ -364,7 +362,6 @@ FUNCTION(x86_64_sysenter32_entry):
movq %r14, %rdi // syscall number
movq %rsp, %rsi
movq IFRAME_ax(%rbp), %rdx // return value
movq %r13, %rcx // start time, preserved earlier
call user_debug_post_syscall
addq $48, %rsp
1:
+1 -5
View File
@@ -64,8 +64,7 @@
// The macros below require R12 to contain the current thread pointer. R12 is
// callee-save so will be preserved through all function calls and only needs
// to be obtained once. R13 is used to store the system call start time, will
// also be preserved.
// to be obtained once.
#define LOCK_THREAD_TIME() \
leaq THREAD_time_lock(%r12), %rdi; \
@@ -79,8 +78,6 @@
LOCK_THREAD_TIME() \
\
call system_time; \
\
/* Preserve system_time for post syscall debug */ \
movq %rax, %r13; \
\
/* thread->user_time += now - thread->last_time; */ \
@@ -526,7 +523,6 @@ FUNCTION(x86_64_syscall_entry):
movq %r14, %rdi // syscall number
movq %rsp, %rsi
movq IFRAME_ax(%rbp), %rdx // return value
movq %r13, %rcx // start time, preserved earlier
call user_debug_post_syscall
addq $48, %rsp
1:
+28 -16
View File
@@ -309,6 +309,7 @@ init_thread_debug_info(struct thread_debug_info *info)
info->ignore_signals = 0;
info->ignore_signals_once = 0;
info->profile.sample_area = -1;
info->profile.interval = 0;
info->profile.samples = NULL;
info->profile.flush_needed = false;
info->profile.installed_timer = NULL;
@@ -337,6 +338,7 @@ clear_thread_debug_info(struct thread_debug_info *info, bool dying)
info->ignore_signals = 0;
info->ignore_signals_once = 0;
info->profile.sample_area = -1;
info->profile.interval = 0;
info->profile.samples = NULL;
info->profile.flush_needed = false;
}
@@ -841,29 +843,33 @@ user_debug_pre_syscall(uint32 syscall, void *args)
// check whether pre-syscall tracing is enabled for team or thread
int32 threadDebugFlags = atomic_get(&thread->debug_info.flags);
if (!(teamDebugFlags & B_TEAM_DEBUG_PRE_SYSCALL)
&& !(threadDebugFlags & B_THREAD_DEBUG_PRE_SYSCALL)) {
return;
if ((teamDebugFlags & B_TEAM_DEBUG_PRE_SYSCALL)
|| (threadDebugFlags & B_THREAD_DEBUG_PRE_SYSCALL)) {
// prepare the message
debug_pre_syscall message;
message.syscall = syscall;
// copy the syscall args
if (syscall < (uint32)kSyscallCount) {
if (kSyscallInfos[syscall].parameter_size > 0)
memcpy(message.args, args, kSyscallInfos[syscall].parameter_size);
}
thread_hit_debug_event(B_DEBUGGER_MESSAGE_PRE_SYSCALL, &message,
sizeof(message), true);
}
// prepare the message
debug_pre_syscall message;
message.syscall = syscall;
// copy the syscall args
if (syscall < (uint32)kSyscallCount) {
if (kSyscallInfos[syscall].parameter_size > 0)
memcpy(message.args, args, kSyscallInfos[syscall].parameter_size);
if ((teamDebugFlags & B_TEAM_DEBUG_POST_SYSCALL)
|| (threadDebugFlags & B_THREAD_DEBUG_POST_SYSCALL)) {
// The syscall_start_time storage is shared with the profiler's interval.
if (thread->debug_info.profile.samples == NULL)
thread->debug_info.profile.syscall_start_time = system_time();
}
thread_hit_debug_event(B_DEBUGGER_MESSAGE_PRE_SYSCALL, &message,
sizeof(message), true);
}
void
user_debug_post_syscall(uint32 syscall, void *args, uint64 returnValue,
bigtime_t startTime)
user_debug_post_syscall(uint32 syscall, void *args, uint64 returnValue)
{
// check whether a debugger is installed
Thread *thread = thread_get_current_thread();
@@ -882,6 +888,12 @@ user_debug_post_syscall(uint32 syscall, void *args, uint64 returnValue,
return;
}
bigtime_t startTime = 0;
if (thread->debug_info.profile.samples == NULL) {
startTime = thread->debug_info.profile.syscall_start_time;
thread->debug_info.profile.syscall_start_time = 0;
}
// prepare the message
debug_post_syscall message;
message.start_time = startTime;
+1 -5
View File
@@ -194,15 +194,11 @@ _user_is_computer_on(void)
int32
syscall_dispatcher(uint32 callIndex, void* args, uint64* _returnValue)
{
bigtime_t startTime;
// dprintf("syscall_dispatcher: thread 0x%x call 0x%x, arg0 0x%x, arg1 0x%x arg2 0x%x arg3 0x%x arg4 0x%x\n",
// thread_get_current_thread_id(), call_num, arg0, arg1, arg2, arg3, arg4);
user_debug_pre_syscall(callIndex, args);
startTime = system_time();
switch (callIndex) {
// the cases are auto-generated
#include "syscall_dispatcher.h"
@@ -211,7 +207,7 @@ syscall_dispatcher(uint32 callIndex, void* args, uint64* _returnValue)
*_returnValue = (uint64)B_BAD_VALUE;
}
user_debug_post_syscall(callIndex, args, *_returnValue, startTime);
user_debug_post_syscall(callIndex, args, *_returnValue);
// dprintf("syscall_dispatcher: done with syscall 0x%x\n", callIndex);