X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Flttngtop.c;h=957d03aaea902abb507a50323e02e72572e406d2;hb=bca0e79c3ab65b13f2e3d3711ddb17661052f24a;hp=b024c9a5ed70c33d08dcf34393157b60a2596554;hpb=7c15d14a187496b734e553138a7b0ca0fda7ec66;p=lttngtop.git diff --git a/src/lttngtop.c b/src/lttngtop.c index b024c9a..957d03a 100644 --- a/src/lttngtop.c +++ b/src/lttngtop.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #ifdef LTTNGTOP_MMAP_LIVE #include @@ -72,6 +73,7 @@ pthread_t timer_thread; unsigned long refresh_display = 1 * NSEC_PER_SEC; unsigned long last_display_update = 0; unsigned long last_event_ts = 0; +struct syscall *last_syscall; /* list of FDs available for being read with snapshots */ struct bt_mmap_stream_list mmap_list; @@ -83,7 +85,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, @@ -211,14 +213,17 @@ void print_fields(struct bt_ctf_event *event) * hook on each event to check the timestamp and refresh the display if * necessary */ -enum bt_cb_ret print_timestamp(struct bt_ctf_event *call_data, void *private_data) +enum bt_cb_ret textdump(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; + int pid, cpu_id, tid, ret, lookup, current_syscall = 0; const struct bt_definition *scope; const char *hostname, *procname; + struct cputime *cpu; + char *from_syscall = NULL; timestamp = bt_ctf_get_timestamp(call_data); @@ -235,10 +240,16 @@ 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)) { + 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; @@ -260,22 +271,84 @@ enum bt_cb_ret print_timestamp(struct bt_ctf_event *call_data, void *private_dat } } + if (last_syscall && (strncmp(bt_ctf_event_name(call_data), + "exit_syscall", 12)) != 0) { + last_syscall = NULL; + printf(" ...interrupted...\n"); + } + cpu_id = get_cpu_id(call_data); procname = get_context_comm(call_data); + 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; + cpu->current_syscall->cpu_id = cpu_id; + last_syscall = cpu->current_syscall; + current_syscall = 1; + } else if ((strncmp(bt_ctf_event_name(call_data), "exit_syscall", 12)) == 0) { + struct tm start_ts; + + /* Return code of a syscall if it was the last displayed event. */ + if (last_syscall && last_syscall->ts_start == prev_ts) { + if (last_syscall->cpu_id == cpu_id) { + int64_t syscall_ret; + + delta = timestamp - last_syscall->ts_start; + 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")); - 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)); + printf(" = %" PRId64 " (+%" PRIu64 ".%09" PRIu64 ")\n", + syscall_ret, delta / NSEC_PER_SEC, + delta % NSEC_PER_SEC); + last_syscall = NULL; + goto end; + } else { + last_syscall = NULL; + printf(" ...interrupted...\n"); + } + } + + 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]", + 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; + last_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(")\n"); + printf(")%s%c", (from_syscall) ? from_syscall : "", + (current_syscall) ? '\0' : '\n'); + + free(from_syscall); end: return BT_CB_OK; @@ -522,6 +595,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); @@ -644,6 +719,7 @@ static int parse_options(int argc, char **argv) int opt, ret = 0; char *tmp_str; int *tid; + int i; remote_live = 0; @@ -664,8 +740,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)); @@ -714,7 +788,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) { @@ -743,9 +828,13 @@ 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, + textdump, NULL, NULL, NULL); } else { /* at each event check if we need to refresh */ @@ -756,10 +845,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( @@ -802,6 +887,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; @@ -1030,11 +1133,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) { @@ -1045,7 +1156,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) { @@ -1070,18 +1186,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);