From 081b0d391a5b9c9b65fa8e1872db6557efe0afe2 Mon Sep 17 00:00:00 2001 From: Leonmmcoset Date: Fri, 17 Apr 2026 21:14:40 +0800 Subject: [PATCH] procstat&sysstat --- CMakeLists.txt | 1 + cleonos/c/apps/help_main.c | 3 +- cleonos/c/apps/procstat_main.c | 244 ++++++++++++++++++++++ cleonos/c/apps/shell/shell_cmd.c | 3 +- cleonos/c/apps/sysstat_main.c | 311 ++++++++++++++++++++++++++++ cleonos/c/include/cleonos_syscall.h | 8 + cleonos/c/src/syscall.c | 16 ++ clks/include/clks/syscall.h | 4 + clks/kernel/syscall.c | 87 ++++++++ docs/syscall.md | 53 ++++- 10 files changed, 726 insertions(+), 4 deletions(-) create mode 100644 cleonos/c/apps/procstat_main.c create mode 100644 cleonos/c/apps/sysstat_main.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a57445b..c071ab3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -385,6 +385,7 @@ set(RAMDISK_ROOT_APPS) set(USER_SHELL_COMMAND_APPS help args ls cat grep head tail wc cut uniq sort pwd cd exec pid spawn wait sleep yield bg fg jobs kill ps top + procstat sysstat shutdown restart exit clear ansi ansitest wavplay fastfetch memstat fsstat taskstat userstat shstat stats tty dmesg kbdstat mkdir touch write append cp mv rm kdbg ) diff --git a/cleonos/c/apps/help_main.c b/cleonos/c/apps/help_main.c index 59c47ea..bfa9b68 100644 --- a/cleonos/c/apps/help_main.c +++ b/cleonos/c/apps/help_main.c @@ -30,7 +30,8 @@ static int ush_cmd_help(void) { ush_writeln(" spawn [args...] / bg [args...]"); ush_writeln(" wait / fg [pid]"); ush_writeln(" kill [signal]"); - ush_writeln(" jobs [-a] / ps [-a] [-u] / top [--once] [-n loops] [-d ticks]"); + ush_writeln(" jobs [-a] / ps [-a] [-u] / procstat [pid|self] [-a]"); + ush_writeln(" top [--once] [-n loops] [-d ticks] / sysstat [-a] [-n N]"); ush_writeln(" kdbg sym / kdbg bt / kdbg regs"); ush_writeln(" sleep "); ush_writeln(" spin (busy loop test for Alt+Ctrl+C)"); diff --git a/cleonos/c/apps/procstat_main.c b/cleonos/c/apps/procstat_main.c new file mode 100644 index 0000000..5e7d93d --- /dev/null +++ b/cleonos/c/apps/procstat_main.c @@ -0,0 +1,244 @@ +#include "cmd_runtime.h" + +static const char *ush_procstat_state_name(u64 state) { + if (state == CLEONOS_PROC_STATE_PENDING) { + return "PEND"; + } + if (state == CLEONOS_PROC_STATE_RUNNING) { + return "RUN "; + } + if (state == CLEONOS_PROC_STATE_STOPPED) { + return "STOP"; + } + if (state == CLEONOS_PROC_STATE_EXITED) { + return "EXIT"; + } + return "UNKN"; +} + +static int ush_procstat_next_token(const char **io_cursor, char *out, u64 out_size) { + const char *p; + u64 n = 0ULL; + + if (io_cursor == (const char **)0 || out == (char *)0 || out_size == 0ULL) { + return 0; + } + + out[0] = '\0'; + p = *io_cursor; + + if (p == (const char *)0) { + return 0; + } + + while (*p != '\0' && ush_is_space(*p) != 0) { + p++; + } + + if (*p == '\0') { + *io_cursor = p; + return 0; + } + + while (*p != '\0' && ush_is_space(*p) == 0) { + if (n + 1ULL < out_size) { + out[n++] = *p; + } + p++; + } + + out[n] = '\0'; + *io_cursor = p; + return 1; +} + +static void ush_procstat_print_line(const cleonos_proc_snapshot *snap) { + if (snap == (const cleonos_proc_snapshot *)0) { + return; + } + + ush_write("PID="); + ush_write_hex_u64(snap->pid); + ush_write(" ST="); + ush_write(ush_procstat_state_name(snap->state)); + ush_write(" TTY="); + ush_write_hex_u64(snap->tty_index); + ush_write(" RT="); + ush_write_hex_u64(snap->runtime_ticks); + ush_write(" MEM="); + ush_write_hex_u64(snap->mem_bytes); + ush_write(" SIG="); + ush_write_hex_u64(snap->last_signal); + ush_write(" PATH="); + ush_writeln(snap->path); +} + +static void ush_procstat_print_detail(const cleonos_proc_snapshot *snap) { + if (snap == (const cleonos_proc_snapshot *)0) { + return; + } + + ush_writeln("procstat:"); + ush_print_kv_hex(" PID", snap->pid); + ush_print_kv_hex(" PPID", snap->ppid); + ush_write(" STATE: "); + ush_write(ush_procstat_state_name(snap->state)); + ush_write_char('\n'); + ush_print_kv_hex(" STATE_ID", snap->state); + ush_print_kv_hex(" TTY", snap->tty_index); + ush_print_kv_hex(" STARTED_TICK", snap->started_tick); + ush_print_kv_hex(" EXITED_TICK", snap->exited_tick); + ush_print_kv_hex(" RUNTIME_TICKS", snap->runtime_ticks); + ush_print_kv_hex(" MEM_BYTES", snap->mem_bytes); + ush_print_kv_hex(" EXIT_STATUS", snap->exit_status); + ush_print_kv_hex(" LAST_SIGNAL", snap->last_signal); + ush_print_kv_hex(" LAST_FAULT_VECTOR", snap->last_fault_vector); + ush_print_kv_hex(" LAST_FAULT_ERROR", snap->last_fault_error); + ush_print_kv_hex(" LAST_FAULT_RIP", snap->last_fault_rip); + ush_write(" PATH: "); + ush_writeln(snap->path); +} + +static int ush_procstat_parse_args(const char *arg, u64 *out_pid, int *out_has_pid, int *out_include_exited) { + const char *cursor = arg; + char token[USH_PATH_MAX]; + u64 parsed_pid = 0ULL; + int has_pid = 0; + int include_exited = 0; + + if (out_pid == (u64 *)0 || out_has_pid == (int *)0 || out_include_exited == (int *)0) { + return 0; + } + + while (ush_procstat_next_token(&cursor, token, (u64)sizeof(token)) != 0) { + if (ush_streq(token, "-a") != 0 || ush_streq(token, "--all") != 0) { + include_exited = 1; + continue; + } + + if (ush_streq(token, "self") != 0) { + if (has_pid != 0) { + return 0; + } + parsed_pid = cleonos_sys_getpid(); + has_pid = 1; + continue; + } + + if (ush_parse_u64_dec(token, &parsed_pid) != 0 && parsed_pid != 0ULL) { + if (has_pid != 0) { + return 0; + } + has_pid = 1; + continue; + } + + return 0; + } + + *out_pid = parsed_pid; + *out_has_pid = has_pid; + *out_include_exited = include_exited; + return 1; +} + +static int ush_cmd_procstat(const char *arg) { + u64 target_pid = 0ULL; + int has_pid = 0; + int include_exited = 0; + + if (ush_procstat_parse_args(arg, &target_pid, &has_pid, &include_exited) == 0) { + ush_writeln("procstat: usage procstat [pid|self] [-a|--all]"); + return 0; + } + + if (has_pid != 0) { + cleonos_proc_snapshot snap; + + if (cleonos_sys_proc_snapshot(target_pid, &snap, (u64)sizeof(snap)) == 0ULL) { + ush_writeln("procstat: pid not found"); + return 0; + } + + ush_procstat_print_detail(&snap); + return 1; + } + + { + u64 proc_count = cleonos_sys_proc_count(); + u64 i; + u64 shown = 0ULL; + + ush_writeln("procstat:"); + + for (i = 0ULL; i < proc_count; i++) { + u64 pid = 0ULL; + cleonos_proc_snapshot snap; + + if (cleonos_sys_proc_pid_at(i, &pid) == 0ULL || pid == 0ULL) { + continue; + } + + if (cleonos_sys_proc_snapshot(pid, &snap, (u64)sizeof(snap)) == 0ULL) { + continue; + } + + if (include_exited == 0 && snap.state == CLEONOS_PROC_STATE_EXITED) { + continue; + } + + ush_procstat_print_line(&snap); + shown++; + } + + if (shown == 0ULL) { + ush_writeln("(no process)"); + } + } + + return 1; +} + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "procstat") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_procstat(arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; +} diff --git a/cleonos/c/apps/shell/shell_cmd.c b/cleonos/c/apps/shell/shell_cmd.c index 718a0cd..a80517b 100644 --- a/cleonos/c/apps/shell/shell_cmd.c +++ b/cleonos/c/apps/shell/shell_cmd.c @@ -155,7 +155,8 @@ static int ush_cmd_help(void) { ush_writeln(" spawn [args...] / bg [args...]"); ush_writeln(" wait / fg [pid]"); ush_writeln(" kill [signal]"); - ush_writeln(" jobs [-a] / ps [-a] [-u] / top [--once] [-n loops] [-d ticks]"); + ush_writeln(" jobs [-a] / ps [-a] [-u] / procstat [pid|self] [-a]"); + ush_writeln(" top [--once] [-n loops] [-d ticks] / sysstat [-a] [-n N]"); ush_writeln(" kdbg sym / kdbg bt / kdbg regs"); ush_writeln(" sleep "); ush_writeln(" yield"); diff --git a/cleonos/c/apps/sysstat_main.c b/cleonos/c/apps/sysstat_main.c new file mode 100644 index 0000000..6704623 --- /dev/null +++ b/cleonos/c/apps/sysstat_main.c @@ -0,0 +1,311 @@ +#include "cmd_runtime.h" + +#define USH_SYSSTAT_MAX_IDS (CLEONOS_SYSCALL_STATS_RECENT_ID + 1ULL) +#define USH_SYSSTAT_DEFAULT_TOP 12ULL + +typedef struct ush_sysstat_entry { + u64 id; + u64 recent; + u64 total; + const char *name; +} ush_sysstat_entry; + +static const char *ush_sysstat_name_for_id(u64 id) { + switch (id) { + case CLEONOS_SYSCALL_LOG_WRITE: return "LOG_WRITE"; + case CLEONOS_SYSCALL_TIMER_TICKS: return "TIMER_TICKS"; + case CLEONOS_SYSCALL_TASK_COUNT: return "TASK_COUNT"; + case CLEONOS_SYSCALL_CUR_TASK: return "CUR_TASK"; + case CLEONOS_SYSCALL_SERVICE_COUNT: return "SERVICE_COUNT"; + case CLEONOS_SYSCALL_SERVICE_READY_COUNT: return "SERVICE_READY"; + case CLEONOS_SYSCALL_CONTEXT_SWITCHES: return "CONTEXT_SWITCH"; + case CLEONOS_SYSCALL_KELF_COUNT: return "KELF_COUNT"; + case CLEONOS_SYSCALL_KELF_RUNS: return "KELF_RUNS"; + case CLEONOS_SYSCALL_FS_NODE_COUNT: return "FS_NODE_COUNT"; + case CLEONOS_SYSCALL_FS_CHILD_COUNT: return "FS_CHILD_COUNT"; + case CLEONOS_SYSCALL_FS_GET_CHILD_NAME: return "FS_CHILD_NAME"; + case CLEONOS_SYSCALL_FS_READ: return "FS_READ"; + case CLEONOS_SYSCALL_EXEC_PATH: return "EXEC_PATH"; + case CLEONOS_SYSCALL_EXEC_REQUESTS: return "EXEC_REQUESTS"; + case CLEONOS_SYSCALL_EXEC_SUCCESS: return "EXEC_SUCCESS"; + case CLEONOS_SYSCALL_USER_SHELL_READY: return "USER_SHELL_READY"; + case CLEONOS_SYSCALL_USER_EXEC_REQUESTED: return "USER_EXEC_REQ"; + case CLEONOS_SYSCALL_USER_LAUNCH_TRIES: return "USER_LAUNCH_TRY"; + case CLEONOS_SYSCALL_USER_LAUNCH_OK: return "USER_LAUNCH_OK"; + case CLEONOS_SYSCALL_USER_LAUNCH_FAIL: return "USER_LAUNCH_FAIL"; + case CLEONOS_SYSCALL_TTY_COUNT: return "TTY_COUNT"; + case CLEONOS_SYSCALL_TTY_ACTIVE: return "TTY_ACTIVE"; + case CLEONOS_SYSCALL_TTY_SWITCH: return "TTY_SWITCH"; + case CLEONOS_SYSCALL_TTY_WRITE: return "TTY_WRITE"; + case CLEONOS_SYSCALL_TTY_WRITE_CHAR: return "TTY_WRITE_CHAR"; + case CLEONOS_SYSCALL_KBD_GET_CHAR: return "KBD_GET_CHAR"; + case CLEONOS_SYSCALL_FS_STAT_TYPE: return "FS_STAT_TYPE"; + case CLEONOS_SYSCALL_FS_STAT_SIZE: return "FS_STAT_SIZE"; + case CLEONOS_SYSCALL_FS_MKDIR: return "FS_MKDIR"; + case CLEONOS_SYSCALL_FS_WRITE: return "FS_WRITE"; + case CLEONOS_SYSCALL_FS_APPEND: return "FS_APPEND"; + case CLEONOS_SYSCALL_FS_REMOVE: return "FS_REMOVE"; + case CLEONOS_SYSCALL_LOG_JOURNAL_COUNT: return "LOG_JCOUNT"; + case CLEONOS_SYSCALL_LOG_JOURNAL_READ: return "LOG_JREAD"; + case CLEONOS_SYSCALL_KBD_BUFFERED: return "KBD_BUFFERED"; + case CLEONOS_SYSCALL_KBD_PUSHED: return "KBD_PUSHED"; + case CLEONOS_SYSCALL_KBD_POPPED: return "KBD_POPPED"; + case CLEONOS_SYSCALL_KBD_DROPPED: return "KBD_DROPPED"; + case CLEONOS_SYSCALL_KBD_HOTKEY_SWITCHES: return "KBD_HOTKEYS"; + case CLEONOS_SYSCALL_GETPID: return "GETPID"; + case CLEONOS_SYSCALL_SPAWN_PATH: return "SPAWN_PATH"; + case CLEONOS_SYSCALL_WAITPID: return "WAITPID"; + case CLEONOS_SYSCALL_EXIT: return "EXIT"; + case CLEONOS_SYSCALL_SLEEP_TICKS: return "SLEEP_TICKS"; + case CLEONOS_SYSCALL_YIELD: return "YIELD"; + case CLEONOS_SYSCALL_SHUTDOWN: return "SHUTDOWN"; + case CLEONOS_SYSCALL_RESTART: return "RESTART"; + case CLEONOS_SYSCALL_AUDIO_AVAILABLE: return "AUDIO_AVAIL"; + case CLEONOS_SYSCALL_AUDIO_PLAY_TONE: return "AUDIO_TONE"; + case CLEONOS_SYSCALL_AUDIO_STOP: return "AUDIO_STOP"; + case CLEONOS_SYSCALL_EXEC_PATHV: return "EXEC_PATHV"; + case CLEONOS_SYSCALL_SPAWN_PATHV: return "SPAWN_PATHV"; + case CLEONOS_SYSCALL_PROC_ARGC: return "PROC_ARGC"; + case CLEONOS_SYSCALL_PROC_ARGV: return "PROC_ARGV"; + case CLEONOS_SYSCALL_PROC_ENVC: return "PROC_ENVC"; + case CLEONOS_SYSCALL_PROC_ENV: return "PROC_ENV"; + case CLEONOS_SYSCALL_PROC_LAST_SIGNAL: return "PROC_LAST_SIG"; + case CLEONOS_SYSCALL_PROC_FAULT_VECTOR: return "PROC_FAULT_VEC"; + case CLEONOS_SYSCALL_PROC_FAULT_ERROR: return "PROC_FAULT_ERR"; + case CLEONOS_SYSCALL_PROC_FAULT_RIP: return "PROC_FAULT_RIP"; + case CLEONOS_SYSCALL_PROC_COUNT: return "PROC_COUNT"; + case CLEONOS_SYSCALL_PROC_PID_AT: return "PROC_PID_AT"; + case CLEONOS_SYSCALL_PROC_SNAPSHOT: return "PROC_SNAPSHOT"; + case CLEONOS_SYSCALL_PROC_KILL: return "PROC_KILL"; + case CLEONOS_SYSCALL_KDBG_SYM: return "KDBG_SYM"; + case CLEONOS_SYSCALL_KDBG_BT: return "KDBG_BT"; + case CLEONOS_SYSCALL_KDBG_REGS: return "KDBG_REGS"; + case CLEONOS_SYSCALL_STATS_TOTAL: return "STATS_TOTAL"; + case CLEONOS_SYSCALL_STATS_ID_COUNT: return "STATS_ID_COUNT"; + case CLEONOS_SYSCALL_STATS_RECENT_WINDOW: return "STATS_RECENT_WIN"; + case CLEONOS_SYSCALL_STATS_RECENT_ID: return "STATS_RECENT_ID"; + default: return "UNKNOWN"; + } +} + +static int ush_sysstat_next_token(const char **io_cursor, char *out, u64 out_size) { + const char *p; + u64 n = 0ULL; + + if (io_cursor == (const char **)0 || out == (char *)0 || out_size == 0ULL) { + return 0; + } + + out[0] = '\0'; + p = *io_cursor; + + if (p == (const char *)0) { + return 0; + } + + while (*p != '\0' && ush_is_space(*p) != 0) { + p++; + } + + if (*p == '\0') { + *io_cursor = p; + return 0; + } + + while (*p != '\0' && ush_is_space(*p) == 0) { + if (n + 1ULL < out_size) { + out[n++] = *p; + } + p++; + } + + out[n] = '\0'; + *io_cursor = p; + return 1; +} + +static int ush_sysstat_parse_args(const char *arg, int *out_show_all, u64 *out_limit) { + const char *cursor = arg; + char token[USH_PATH_MAX]; + int show_all = 0; + u64 limit = USH_SYSSTAT_DEFAULT_TOP; + + if (out_show_all == (int *)0 || out_limit == (u64 *)0) { + return 0; + } + + while (ush_sysstat_next_token(&cursor, token, (u64)sizeof(token)) != 0) { + if (ush_streq(token, "-a") != 0 || ush_streq(token, "--all") != 0) { + show_all = 1; + continue; + } + + if (ush_streq(token, "-n") != 0 || ush_streq(token, "--top") != 0) { + if (ush_sysstat_next_token(&cursor, token, (u64)sizeof(token)) == 0 || ush_parse_u64_dec(token, &limit) == 0) { + return 0; + } + continue; + } + + return 0; + } + + if (limit == 0ULL) { + limit = 1ULL; + } + + *out_show_all = show_all; + *out_limit = limit; + return 1; +} + +static void ush_sysstat_sort_recent(ush_sysstat_entry *entries, u64 count) { + u64 i; + + if (entries == (ush_sysstat_entry *)0) { + return; + } + + for (i = 0ULL; i + 1ULL < count; i++) { + u64 j; + + for (j = i + 1ULL; j < count; j++) { + int swap = 0; + + if (entries[j].recent > entries[i].recent) { + swap = 1; + } else if (entries[j].recent == entries[i].recent && entries[j].total > entries[i].total) { + swap = 1; + } else if (entries[j].recent == entries[i].recent && entries[j].total == entries[i].total && + entries[j].id < entries[i].id) { + swap = 1; + } + + if (swap != 0) { + ush_sysstat_entry tmp = entries[i]; + entries[i] = entries[j]; + entries[j] = tmp; + } + } + } +} + +static int ush_cmd_sysstat(const char *arg) { + int show_all = 0; + u64 limit = USH_SYSSTAT_DEFAULT_TOP; + ush_sysstat_entry entries[USH_SYSSTAT_MAX_IDS]; + u64 entry_count = 0ULL; + u64 id; + u64 total = cleonos_sys_stats_total(); + u64 recent_window = cleonos_sys_stats_recent_window(); + u64 to_show; + + if (ush_sysstat_parse_args(arg, &show_all, &limit) == 0) { + ush_writeln("sysstat: usage sysstat [-a|--all] [-n N]"); + return 0; + } + + ush_writeln("sysstat:"); + ush_print_kv_hex(" TIMER_TICKS", cleonos_sys_timer_ticks()); + ush_print_kv_hex(" TASK_COUNT", cleonos_sys_task_count()); + ush_print_kv_hex(" CURRENT_TASK", cleonos_syscall(CLEONOS_SYSCALL_CUR_TASK, 0ULL, 0ULL, 0ULL)); + ush_print_kv_hex(" CONTEXT_SWITCHES", cleonos_sys_context_switches()); + ush_print_kv_hex(" PROC_COUNT", cleonos_sys_proc_count()); + ush_print_kv_hex(" EXEC_REQUESTS", cleonos_sys_exec_request_count()); + ush_print_kv_hex(" EXEC_SUCCESS", cleonos_sys_exec_success_count()); + ush_print_kv_hex(" SYSCALL_TOTAL", total); + ush_print_kv_hex(" SYSCALL_RECENT_WINDOW", recent_window); + ush_writeln(""); + + for (id = 0ULL; id < USH_SYSSTAT_MAX_IDS; id++) { + u64 id_total = cleonos_sys_stats_id_count(id); + u64 id_recent = cleonos_sys_stats_recent_id(id); + + if (show_all == 0 && id_total == 0ULL && id_recent == 0ULL) { + continue; + } + + entries[entry_count].id = id; + entries[entry_count].recent = id_recent; + entries[entry_count].total = id_total; + entries[entry_count].name = ush_sysstat_name_for_id(id); + entry_count++; + } + + if (entry_count == 0ULL) { + ush_writeln("(no syscall activity yet)"); + return 1; + } + + if (show_all == 0) { + ush_sysstat_sort_recent(entries, entry_count); + } + + to_show = entry_count; + if (show_all == 0 && to_show > limit) { + to_show = limit; + } + + for (id = 0ULL; id < to_show; id++) { + ush_write("ID="); + ush_write_hex_u64(entries[id].id); + ush_write(" RECENT="); + ush_write_hex_u64(entries[id].recent); + ush_write(" TOTAL="); + ush_write_hex_u64(entries[id].total); + ush_write(" NAME="); + ush_writeln(entries[id].name); + } + + if (show_all == 0 && entry_count > to_show) { + ush_write("... truncated, use "); + ush_write("sysstat -a"); + ush_writeln(" to show all syscall IDs"); + } + + return 1; +} + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "sysstat") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_sysstat(arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; +} diff --git a/cleonos/c/include/cleonos_syscall.h b/cleonos/c/include/cleonos_syscall.h index 5e3b3b0..fceaf9f 100644 --- a/cleonos/c/include/cleonos_syscall.h +++ b/cleonos/c/include/cleonos_syscall.h @@ -103,6 +103,10 @@ typedef struct cleonos_proc_snapshot { #define CLEONOS_SYSCALL_KDBG_SYM 65ULL #define CLEONOS_SYSCALL_KDBG_BT 66ULL #define CLEONOS_SYSCALL_KDBG_REGS 67ULL +#define CLEONOS_SYSCALL_STATS_TOTAL 68ULL +#define CLEONOS_SYSCALL_STATS_ID_COUNT 69ULL +#define CLEONOS_SYSCALL_STATS_RECENT_WINDOW 70ULL +#define CLEONOS_SYSCALL_STATS_RECENT_ID 71ULL u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); u64 cleonos_sys_log_write(const char *message, u64 length); @@ -172,5 +176,9 @@ u64 cleonos_sys_proc_kill(u64 pid, u64 signal); u64 cleonos_sys_kdbg_sym(u64 addr, char *out_line, u64 out_size); u64 cleonos_sys_kdbg_bt(u64 rbp, u64 rip, char *out_text, u64 out_size); u64 cleonos_sys_kdbg_regs(char *out_text, u64 out_size); +u64 cleonos_sys_stats_total(void); +u64 cleonos_sys_stats_id_count(u64 id); +u64 cleonos_sys_stats_recent_window(void); +u64 cleonos_sys_stats_recent_id(u64 id); #endif diff --git a/cleonos/c/src/syscall.c b/cleonos/c/src/syscall.c index e932948..f4bd7a1 100644 --- a/cleonos/c/src/syscall.c +++ b/cleonos/c/src/syscall.c @@ -294,3 +294,19 @@ u64 cleonos_sys_kdbg_bt(u64 rbp, u64 rip, char *out_text, u64 out_size) { u64 cleonos_sys_kdbg_regs(char *out_text, u64 out_size) { return cleonos_syscall(CLEONOS_SYSCALL_KDBG_REGS, (u64)out_text, out_size, 0ULL); } + +u64 cleonos_sys_stats_total(void) { + return cleonos_syscall(CLEONOS_SYSCALL_STATS_TOTAL, 0ULL, 0ULL, 0ULL); +} + +u64 cleonos_sys_stats_id_count(u64 id) { + return cleonos_syscall(CLEONOS_SYSCALL_STATS_ID_COUNT, id, 0ULL, 0ULL); +} + +u64 cleonos_sys_stats_recent_window(void) { + return cleonos_syscall(CLEONOS_SYSCALL_STATS_RECENT_WINDOW, 0ULL, 0ULL, 0ULL); +} + +u64 cleonos_sys_stats_recent_id(u64 id) { + return cleonos_syscall(CLEONOS_SYSCALL_STATS_RECENT_ID, id, 0ULL, 0ULL); +} diff --git a/clks/include/clks/syscall.h b/clks/include/clks/syscall.h index 87003cd..1808165 100644 --- a/clks/include/clks/syscall.h +++ b/clks/include/clks/syscall.h @@ -71,6 +71,10 @@ #define CLKS_SYSCALL_KDBG_SYM 65ULL #define CLKS_SYSCALL_KDBG_BT 66ULL #define CLKS_SYSCALL_KDBG_REGS 67ULL +#define CLKS_SYSCALL_STATS_TOTAL 68ULL +#define CLKS_SYSCALL_STATS_ID_COUNT 69ULL +#define CLKS_SYSCALL_STATS_RECENT_WINDOW 70ULL +#define CLKS_SYSCALL_STATS_RECENT_ID 71ULL void clks_syscall_init(void); u64 clks_syscall_dispatch(void *frame_ptr); diff --git a/clks/kernel/syscall.c b/clks/kernel/syscall.c index de5237c..2a26006 100644 --- a/clks/kernel/syscall.c +++ b/clks/kernel/syscall.c @@ -32,6 +32,8 @@ #define CLKS_SYSCALL_KDBG_STACK_WINDOW_BYTES (128ULL * 1024ULL) #define CLKS_SYSCALL_KERNEL_SYMBOL_FILE "/system/kernel.sym" #define CLKS_SYSCALL_KERNEL_ADDR_BASE 0xFFFF800000000000ULL +#define CLKS_SYSCALL_STATS_MAX_ID CLKS_SYSCALL_STATS_RECENT_ID +#define CLKS_SYSCALL_STATS_RING_SIZE 256U struct clks_syscall_frame { u64 rax; @@ -73,6 +75,12 @@ static clks_bool clks_syscall_last_frame_valid = CLKS_FALSE; static clks_bool clks_syscall_symbols_checked = CLKS_FALSE; static const char *clks_syscall_symbols_data = CLKS_NULL; static u64 clks_syscall_symbols_size = 0ULL; +static u64 clks_syscall_stats_total = 0ULL; +static u64 clks_syscall_stats_id_count[CLKS_SYSCALL_STATS_MAX_ID + 1ULL]; +static u64 clks_syscall_stats_recent_id_count[CLKS_SYSCALL_STATS_MAX_ID + 1ULL]; +static u16 clks_syscall_stats_recent_ring[CLKS_SYSCALL_STATS_RING_SIZE]; +static u32 clks_syscall_stats_recent_head = 0U; +static u32 clks_syscall_stats_recent_size = 0U; #if defined(CLKS_ARCH_X86_64) static inline void clks_syscall_outb(u16 port, u8 value) { @@ -1492,6 +1500,75 @@ static void clks_syscall_serial_write_hex64(u64 value) { } } +static void clks_syscall_stats_reset(void) { + clks_syscall_stats_total = 0ULL; + clks_memset(clks_syscall_stats_id_count, 0, sizeof(clks_syscall_stats_id_count)); + clks_memset(clks_syscall_stats_recent_id_count, 0, sizeof(clks_syscall_stats_recent_id_count)); + clks_memset(clks_syscall_stats_recent_ring, 0, sizeof(clks_syscall_stats_recent_ring)); + clks_syscall_stats_recent_head = 0U; + clks_syscall_stats_recent_size = 0U; +} + +static void clks_syscall_stats_record(u64 id) { + u16 ring_id = 0xFFFFU; + + clks_syscall_stats_total++; + + if (id <= CLKS_SYSCALL_STATS_MAX_ID) { + clks_syscall_stats_id_count[id]++; + } + + if (id <= 0xFFFFULL) { + ring_id = (u16)id; + } + + if (clks_syscall_stats_recent_size >= CLKS_SYSCALL_STATS_RING_SIZE) { + u64 old_id = (u64)clks_syscall_stats_recent_ring[clks_syscall_stats_recent_head]; + + if (old_id <= CLKS_SYSCALL_STATS_MAX_ID && clks_syscall_stats_recent_id_count[old_id] > 0ULL) { + clks_syscall_stats_recent_id_count[old_id]--; + } + } else { + clks_syscall_stats_recent_size++; + } + + clks_syscall_stats_recent_ring[clks_syscall_stats_recent_head] = ring_id; + + if (id <= CLKS_SYSCALL_STATS_MAX_ID) { + clks_syscall_stats_recent_id_count[id]++; + } + + clks_syscall_stats_recent_head++; + + if (clks_syscall_stats_recent_head >= CLKS_SYSCALL_STATS_RING_SIZE) { + clks_syscall_stats_recent_head = 0U; + } +} + +static u64 clks_syscall_stats_total_count(void) { + return clks_syscall_stats_total; +} + +static u64 clks_syscall_stats_id(u64 id) { + if (id > CLKS_SYSCALL_STATS_MAX_ID) { + return 0ULL; + } + + return clks_syscall_stats_id_count[id]; +} + +static u64 clks_syscall_stats_recent_window(void) { + return (u64)clks_syscall_stats_recent_size; +} + +static u64 clks_syscall_stats_recent_id(u64 id) { + if (id > CLKS_SYSCALL_STATS_MAX_ID) { + return 0ULL; + } + + return clks_syscall_stats_recent_id_count[id]; +} + static void clks_syscall_trace_user_program(u64 id) { clks_bool user_program_running = (clks_exec_is_running() == CLKS_TRUE && clks_exec_current_path_is_user() == CLKS_TRUE) @@ -1538,6 +1615,7 @@ void clks_syscall_init(void) { clks_syscall_symbols_checked = CLKS_FALSE; clks_syscall_symbols_data = CLKS_NULL; clks_syscall_symbols_size = 0ULL; + clks_syscall_stats_reset(); clks_log(CLKS_LOG_INFO, "SYSCALL", "INT80 FRAMEWORK ONLINE"); } @@ -1553,6 +1631,7 @@ u64 clks_syscall_dispatch(void *frame_ptr) { clks_syscall_last_frame_valid = CLKS_TRUE; id = frame->rax; + clks_syscall_stats_record(id); clks_syscall_trace_user_program(id); switch (id) { @@ -1699,6 +1778,14 @@ u64 clks_syscall_dispatch(void *frame_ptr) { return clks_syscall_kdbg_bt(frame->rbx); case CLKS_SYSCALL_KDBG_REGS: return clks_syscall_kdbg_regs(frame->rbx, frame->rcx); + case CLKS_SYSCALL_STATS_TOTAL: + return clks_syscall_stats_total_count(); + case CLKS_SYSCALL_STATS_ID_COUNT: + return clks_syscall_stats_id(frame->rbx); + case CLKS_SYSCALL_STATS_RECENT_WINDOW: + return clks_syscall_stats_recent_window(); + case CLKS_SYSCALL_STATS_RECENT_ID: + return clks_syscall_stats_recent_id(frame->rbx); default: return (u64)-1; } diff --git a/docs/syscall.md b/docs/syscall.md index b3edaba..7251117 100644 --- a/docs/syscall.md +++ b/docs/syscall.md @@ -83,7 +83,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); - `/proc/`:指定 PID 快照文本 - `/proc` 为只读;写入类 syscall 不支持。 -## 4. Syscall 列表(0~64) +## 4. Syscall 列表(0~71) ### 0 `CLEONOS_SYSCALL_LOG_WRITE` @@ -510,6 +510,53 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); - `SIGSTOP`:将 `PENDING` 进程置为 `STOPPED`;对已 `STOPPED` 目标返回成功。 - `SIGCONT`:将 `STOPPED` 进程恢复为 `PENDING`。 +### 65 `CLEONOS_SYSCALL_KDBG_SYM` + +- 参数: +- `arg0`: `u64 addr` +- `arg1`: `char *out_line` +- `arg2`: `u64 out_size` +- 返回:写入字节数(含截断) +- 说明:将地址符号化为文本(含偏移与可选源码位置)。 + +### 66 `CLEONOS_SYSCALL_KDBG_BT` + +- 参数: +- `arg0`: `struct { u64 rbp; u64 rip; u64 out_ptr; u64 out_size; } *req` +- 返回:写入字节数 +- 说明:输出回溯文本;x86_64 下会尝试沿帧指针遍历。 + +### 67 `CLEONOS_SYSCALL_KDBG_REGS` + +- 参数: +- `arg0`: `char *out_text` +- `arg1`: `u64 out_size` +- 返回:写入字节数 +- 说明:输出最近一次 syscall 进入内核时的寄存器快照。 + +### 68 `CLEONOS_SYSCALL_STATS_TOTAL` + +- 参数:无 +- 返回:自启动以来的 syscall 总调用次数 + +### 69 `CLEONOS_SYSCALL_STATS_ID_COUNT` + +- 参数: +- `arg0`: `u64 id` +- 返回:指定 syscall ID 的累计调用次数(ID 越界返回 `0`) + +### 70 `CLEONOS_SYSCALL_STATS_RECENT_WINDOW` + +- 参数:无 +- 返回:最近窗口内样本数量 +- 说明:当前内核实现窗口大小为 `256` 次 syscall。 + +### 71 `CLEONOS_SYSCALL_STATS_RECENT_ID` + +- 参数: +- `arg0`: `u64 id` +- 返回:指定 syscall ID 在“最近窗口”中的出现次数(ID 越界返回 `0`) + ## 5. 用户态封装函数 用户态封装位于: @@ -532,6 +579,8 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); - `cleonos_sys_proc_argc()` / `cleonos_sys_proc_argv()` / `cleonos_sys_proc_envc()` / `cleonos_sys_proc_env()` - `cleonos_sys_proc_last_signal()` / `cleonos_sys_proc_fault_vector()` / `cleonos_sys_proc_fault_error()` / `cleonos_sys_proc_fault_rip()` - `cleonos_sys_proc_count()` / `cleonos_sys_proc_pid_at()` / `cleonos_sys_proc_snapshot()` / `cleonos_sys_proc_kill()` +- `cleonos_sys_kdbg_sym()` / `cleonos_sys_kdbg_bt()` / `cleonos_sys_kdbg_regs()` +- `cleonos_sys_stats_total()` / `cleonos_sys_stats_id_count()` / `cleonos_sys_stats_recent_window()` / `cleonos_sys_stats_recent_id()` ## 6. 开发注意事项 @@ -542,6 +591,6 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); ## 7. Wine 兼容说明 -- `wine/cleonos_wine_lib/runner.py` 已适配 syscall `0..60`,包含 `EXEC_PATHV` / `SPAWN_PATHV` 与 `PROC_*` 系列。 +- `wine/cleonos_wine_lib/runner.py` 目前以 syscall `0..67` 为主,新增 ID 需同步适配后才能完整观测统计类接口。 - Wine 在运行时崩溃场景下会生成与内核一致格式的“信号编码退出状态”,可通过 `WAITPID` 读取。 - Wine 当前音频 syscall 为占位实现:`AUDIO_AVAILABLE=0`,`AUDIO_PLAY_TONE=0`,`AUDIO_STOP=1`。