X-Git-Url: https://git.lttng.org/?p=lttngtop.git;a=blobdiff_plain;f=src%2Flttngtop.c;h=d7bf627a702376fb952b04f7c3e9f113730cf0fa;hp=e9beb0d0aab082dec131fec1422359d6495f769f;hb=a15e6a1039a885e137a08948593da8383777b6d5;hpb=6e11e0d0eebdfe842bc7153ad9e28947b3cb3365 diff --git a/src/lttngtop.c b/src/lttngtop.c index e9beb0d..d7bf627 100644 --- a/src/lttngtop.c +++ b/src/lttngtop.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #ifdef LTTNGTOP_MMAP_LIVE #include @@ -83,7 +84,7 @@ GPtrArray *available_snapshots; sem_t metadata_available; int reload_trace = 0; -int last_textdump_print_newline = 1; +uint64_t prev_ts = 0; enum { OPT_NONE = 0, @@ -214,12 +215,14 @@ void print_fields(struct bt_ctf_event *event) enum bt_cb_ret print_timestamp(struct bt_ctf_event *call_data, void *private_data) { unsigned long timestamp; + uint64_t delta; struct tm start; uint64_t ts_nsec_start; - int pid, cpu_id; - int64_t syscall_ret; + int pid, cpu_id, tid, ret, lookup; const struct bt_definition *scope; const char *hostname, *procname; + struct cputime *cpu; + char *from_syscall = NULL; timestamp = bt_ctf_get_timestamp(call_data); @@ -236,49 +239,83 @@ enum bt_cb_ret print_timestamp(struct bt_ctf_event *call_data, void *private_dat if (pid == -1ULL && opt_tid) { goto error; } + + tid = get_context_tid(call_data); hostname = get_context_hostname(call_data); - if (opt_tid || opt_hostname) - if (!lookup_filter_tid_list(pid)) - goto end; + if (opt_child) + lookup = pid; + else + lookup = tid; + if (opt_tid || opt_hostname || opt_exec_name) { + if (!lookup_filter_tid_list(lookup)) { + /* To display when a process of ours in getting scheduled in */ + if (strcmp(bt_ctf_event_name(call_data), "sched_switch") == 0) { + int next_tid; + + scope = bt_ctf_get_top_level_scope(call_data, + BT_EVENT_FIELDS); + next_tid = bt_ctf_get_int64(bt_ctf_get_field(call_data, + scope, "_next_tid")); + if (bt_ctf_field_get_error()) { + fprintf(stderr, "Missing next_tid field\n"); + goto error; + } + if (!lookup_filter_tid_list(next_tid)) { + goto end; + } + } else { + goto end; + } + } + } cpu_id = get_cpu_id(call_data); procname = get_context_comm(call_data); - - if ((strcmp(bt_ctf_event_name(call_data), "exit_syscall") == 0) && - !last_textdump_print_newline) { - scope = bt_ctf_get_top_level_scope(call_data, - BT_EVENT_FIELDS); - syscall_ret = bt_ctf_get_int64(bt_ctf_get_field(call_data, - scope, "_ret")); - printf("= %ld\n", syscall_ret); - last_textdump_print_newline = 1; - } else { - /* we might have lost the exit_syscall event, so need to - * print the newline in this case */ - if (last_textdump_print_newline == 0) - printf("\n"); - if (hostname) { - printf("%02d:%02d:%02d.%09" PRIu64 " (%s) (cpu %d) [%s (%d)] %s (", - start.tm_hour, start.tm_min, start.tm_sec, - ts_nsec_start, hostname, cpu_id, procname, pid, - bt_ctf_event_name(call_data)); - } else { - printf("%02d:%02d:%02d.%09" PRIu64 " (cpu %d) [%s (%d)] %s (", - start.tm_hour, start.tm_min, start.tm_sec, - ts_nsec_start, cpu_id, procname, pid, - bt_ctf_event_name(call_data)); - } - print_fields(call_data); - printf(") "); - if (strncmp(bt_ctf_event_name(call_data), "sys_", 4) != 0) { - printf("\n"); - last_textdump_print_newline = 1; - } else { - last_textdump_print_newline = 0; + if (strncmp(bt_ctf_event_name(call_data), "sys_", 4) == 0) { + cpu = get_cpu(cpu_id); + cpu->current_syscall = g_new0(struct syscall, 1); + cpu->current_syscall->name = strdup(bt_ctf_event_name(call_data)); + cpu->current_syscall->ts_start = timestamp; + } else if ((strncmp(bt_ctf_event_name(call_data), "exit_syscall", 12)) == 0) { + struct tm start_ts; + + cpu = get_cpu(cpu_id); + if (cpu->current_syscall) { + delta = timestamp - cpu->current_syscall->ts_start; + start_ts = format_timestamp(cpu->current_syscall->ts_start); + ret = asprintf(&from_syscall, " [from %02d:%02d:%02d.%09" PRIu64 + " (+%" PRIu64 ".%09" PRIu64 ") (cpu %d) %s]\n", + start_ts.tm_hour, start_ts.tm_min, start_ts.tm_sec, + cpu->current_syscall->ts_start % NSEC_PER_SEC, + delta / NSEC_PER_SEC, delta % NSEC_PER_SEC, + cpu_id, cpu->current_syscall->name); + if (ret < 0) { + goto error; + } + free(cpu->current_syscall->name); + g_free(cpu->current_syscall); + cpu->current_syscall = NULL; } } + if (prev_ts == 0) + prev_ts = timestamp; + delta = timestamp - prev_ts; + prev_ts = timestamp; + + printf("%02d:%02d:%02d.%09" PRIu64 " (+%" PRIu64 ".%09" PRIu64 ") %s%s" + "(cpu %d) [%s (%d/%d)] %s (", + start.tm_hour, start.tm_min, start.tm_sec, + ts_nsec_start, delta / NSEC_PER_SEC, + delta % NSEC_PER_SEC, (hostname) ? hostname : "", + (hostname) ? " ": "", cpu_id, procname, pid, tid, + bt_ctf_event_name(call_data)); + print_fields(call_data); + printf(")%s", (from_syscall) ? from_syscall : "\n"); + + free(from_syscall); + end: return BT_CB_OK; error: @@ -524,6 +561,8 @@ void init_lttngtop() global_perf_liszt = g_hash_table_new(g_str_hash, g_str_equal); global_filter_list = g_hash_table_new(g_str_hash, g_str_equal); global_host_list = g_hash_table_new(g_str_hash, g_str_equal); + tid_filter_list = g_hash_table_new(g_str_hash, + g_str_equal); sem_init(&goodtodisplay, 0, 0); sem_init(&goodtoupdate, 0, 1); @@ -646,6 +685,7 @@ static int parse_options(int argc, char **argv) int opt, ret = 0; char *tmp_str; int *tid; + int i; remote_live = 0; @@ -666,8 +706,6 @@ static int parse_options(int argc, char **argv) break; case OPT_PID: toggle_filter = 1; - tid_filter_list = g_hash_table_new(g_str_hash, - g_str_equal); tmp_str = strtok(opt_tid, ","); while (tmp_str) { tid = malloc(sizeof(int)); @@ -716,7 +754,18 @@ static int parse_options(int argc, char **argv) } } - opt_input_path = poptGetArg(pc); + opt_exec_name = NULL; + opt_exec_argv = NULL; + for (i = 0; i < argc; i++) { + if (argv[i][0] == '-' && argv[i][1] == '-') { + opt_exec_name = argv[i + 1]; + opt_exec_argv = &argv[i + 1]; + break; + } + } + if (!opt_exec_name) { + opt_input_path = poptGetArg(pc); + } end: if (pc) { @@ -745,6 +794,10 @@ void iter_trace(struct bt_context *bt_ctx) bt_ctf_iter_add_callback(iter, g_quark_from_static_string("sched_process_fork"), NULL, 0, handle_sched_process_fork, NULL, NULL, NULL); + /* to clean up the process table */ + bt_ctf_iter_add_callback(iter, + g_quark_from_static_string("sched_process_free"), + NULL, 0, handle_sched_process_free, NULL, NULL, NULL); if (opt_textdump) { bt_ctf_iter_add_callback(iter, 0, NULL, 0, print_timestamp, @@ -758,10 +811,6 @@ void iter_trace(struct bt_context *bt_ctx) bt_ctf_iter_add_callback(iter, g_quark_from_static_string("sched_switch"), NULL, 0, handle_sched_switch, NULL, NULL, NULL); - /* to clean up the process table */ - bt_ctf_iter_add_callback(iter, - g_quark_from_static_string("sched_process_free"), - NULL, 0, handle_sched_process_free, NULL, NULL, NULL); /* to get all the process from the statedumps */ bt_ctf_iter_add_callback(iter, g_quark_from_static_string( @@ -804,6 +853,24 @@ void iter_trace(struct bt_context *bt_ctx) } } + if (opt_exec_name) { + pid_t pid; + + pid = fork(); + if (pid == 0) { + execvpe(opt_exec_name, opt_exec_argv, opt_exec_env); + exit(EXIT_SUCCESS); + } else if (pid > 0) { + opt_exec_pid = pid; + g_hash_table_insert(tid_filter_list, + (gpointer) &pid, + &pid); + } else { + perror("fork"); + exit(EXIT_FAILURE); + } + } + while ((event = bt_ctf_iter_read_event(iter)) != NULL) { if (quit || reload_trace) goto end_iter; @@ -1032,11 +1099,19 @@ end: return ret; } -int main(int argc, char **argv) +static void handle_sigchild(int signal) +{ + int status; + + waitpid(opt_exec_pid, &status, 0); +} + +int main(int argc, char **argv, char **envp) { int ret; struct bt_context *bt_ctx = NULL; + //babeltrace_verbose = 1; init_lttngtop(); ret = parse_options(argc, argv); if (ret < 0) { @@ -1047,7 +1122,12 @@ int main(int argc, char **argv) exit(EXIT_SUCCESS); } - if (!opt_input_path && !remote_live) { + if (opt_exec_name) { + opt_exec_env = envp; + signal(SIGCHLD, handle_sigchild); + } + + if (!opt_input_path && !remote_live && !opt_exec_name) { /* mmap live */ #ifdef LTTNGTOP_MMAP_LIVE if (opt_textdump) { @@ -1072,18 +1152,6 @@ int main(int argc, char **argv) #endif /* LTTNGTOP_MMAP_LIVE */ } else if (!opt_input_path && remote_live) { /* network live */ -#if 0 - ret = setup_network_live(opt_relay_hostname, opt_begin); - if (ret < 0) { - goto end; - } - - ret = open_trace(&bt_ctx); - if (ret < 0) { - goto end; - } -#endif - bt_ctx = bt_context_create(); ret = bt_context_add_traces_recursive(bt_ctx, opt_relay_hostname, "lttng-live", NULL);