/** * various_monitor cli 命令行工具 */ #include "ucli.h" #include #include #include #include // for ioctl #include // #include // #include // // #include // #include // #include // ioctl // !todo move to a header file #define IOCTL_MAGIC_NUMBER 'k' #define IOCTL_PID _IOWR(IOCTL_MAGIC_NUMBER, 2, int) #define IOCTL_TGID _IOWR(IOCTL_MAGIC_NUMBER, 3, int) // int switch_namespace(pid_t pid, const char *ns) { // char ns_path[256]; // snprintf(ns_path, sizeof(ns_path), "/proc/%d/ns/%s", pid, ns); // int fd = open(ns_path, O_RDONLY); // if (fd == -1) { // perror("open"); // return -1; // } // if (setns(fd, 0) == -1) { // perror("setns"); // close(fd); // return -1; // } // close(fd); // return 0; // } // int switch_to_pid_namespace(pid_t pid) { // return switch_namespace(pid, "pid"); // } // void test(variable_monitor_task *tsk_info) { // // host // if (tsk_info->task.pid == tsk_info->task.container_pid){ // printf("host\n"); // diag_printf_raw_stack(tsk_info->task.tgid, tsk_info->task.container_tgid, // tsk_info->task.comm, &tsk_info->raw_stack); // } // printf("container\n"); // // Save the current namespace. // int fd = open("/proc/self/ns/pid", O_RDONLY); // if (fd == -1) { // perror("open"); // return; // } // // Switch to the namespace of the target process. // if (switch_to_pid_namespace(tsk_info->task.pid) != 0) { // close(fd); // return; // } // // Do something with tgid... // diag_printf_raw_stack(tsk_info->task.container_tgid, // tsk_info->task.container_tgid, tsk_info->task.comm, // &tsk_info->raw_stack); // // Switch back to the original namespace. // if (!run_in_host && setns(fd, 0) == -1) { // perror("setns"); // } // close(fd); // } static int task_info_extract(void *buf, unsigned int len, void *) { int *et_type; variable_monitor_record *vm_record; variable_monitor_task *tsk_info; struct load_monitor_cpu_run *cpu_run; static int seq = 0; if (len == 0) return 0; et_type = (int *)buf; switch (*et_type) { case VARIABLE_MONITOR_RECORD_TYPE: if (len < sizeof(variable_monitor_record)) break; vm_record = (variable_monitor_record *)buf; printf("threshold exceeded, Timestamp %d :\n", vm_record->tv); for (int i = 0; i < vm_record->threshold_num; i++) { printf("\t: pid: %d, name: %s, ptr: %p, threshold:%d\n", vm_record->threshold_record[i].task_id, vm_record->threshold_record[i] .name, // Assuming name is a null-terminated string vm_record->threshold_record[i].ptr, vm_record->threshold_record[i].threshold // vm_record->threshold_record[i].true_value ); } break; case VARIABLE_MONITOR_TASK_TYPE: if (len < sizeof(variable_monitor_task)) break; tsk_info = (variable_monitor_task *)buf; seq++; printf("##CGROUP:[%s] %d [%03d] 采样命中[%s]\n", tsk_info->task.cgroup_buf, tsk_info->task.pid, seq, tsk_info->task.state == 0 ? "R" : "D"); printk_task_brief(&tsk_info->task); // diag_printf_raw_stack(tsk_info->task.tgid, tsk_info->task.container_tgid, // tsk_info->task.comm, &tsk_info->raw_stack); // printf("run_in_host: %d\n", run_in_host); diag_printf_raw_stack(run_in_host ? tsk_info->task.tgid : tsk_info->task.container_tgid, tsk_info->task.container_tgid, tsk_info->task.comm, &tsk_info->raw_stack); // test(tsk_info); diag_printf_kern_stack(&tsk_info->kern_stack); printf("#* 0xffffffffffffff %s (UNKNOWN)\n", tsk_info->task.comm); diag_printf_proc_chains(&tsk_info->proc_chains); printf("##\n"); break; default: break; } return 0; } static void do_extract(char *buf, int len) { extract_variant_buffer(buf, len, task_info_extract, NULL); } static void do_dump(const char *arg) { //! todo static char variant_buf[256 * 1024 * 1024]; int len; int ret = 0; // 参数解析, 未实现/ 源码在 SOURCE/diagnose-tools/params_parse.h | // params_parse.cc // struct params_parser parse(arg); struct diag_ioctl_dump_param dump_param = { .user_ptr_len = &len, .user_buf_len = 256 * 1024 * 1024, .user_buf = variant_buf, }; ret = diag_call_ioctl(IOCTL_DUMP_LOG, (long)&dump_param); // !todo arg -> #define if (ret == 0) { do_extract(variant_buf, len); } } static void do_pid(char *arg) { int pid = 0; int ret; sscanf(optarg, "%d", &pid); if (pid <= 0) { printf("参数错误\n"); return; } printf("获取线程信息: %d\n", pid); ret = diag_call_ioctl(IOCTL_PID, (long)&pid); if (ret) { printf("获取线程信息错误: %d\n", ret); } sleep(3); do_dump(""); } static void do_tgid(char *arg) { int pid = 0; int ret; sscanf(optarg, "%d", &pid); if (pid <= 0) { printf("参数错误\n"); return; } printf("获取 tgid 信息: %d\n", pid); ret = diag_call_ioctl(IOCTL_TGID, (long)&pid); if (ret) { printf("获取线程信息错误: %d\n", ret); } sleep(3); do_dump(""); } int main(int argc, char *argv[]) { run_in_host = check_in_host(); printf("run_in_host: %d\n", run_in_host); for (int i = 0; i < argc; i++){ printf("argv[%d]: %s\n", i, argv[i]); } static const struct option long_options[] = { {"help", no_argument, 0, 0}, {"report", no_argument, 0, 0}, {"pid", required_argument, 0, 0}, {"tgid", required_argument, 0, 0}, {0, 0, 0, 0}}; int c; if (argc <= 1) { // do something default do_dump(optarg ? optarg : ""); return 0; } while (1) { int option_index = -1; c = getopt_long_only(argc, argv, "", long_options, &option_index); if (c == -1) { break; } // option_index = 2; switch (option_index) { case 0: // help // usage_pupil(); break; case 1: // report do_dump(optarg ? optarg : ""); break; case 2: // pid do_pid(optarg); break; case 3: // tgid do_tgid(optarg); break; default: // usage_pupil(); break; } } return 0; }