X-Git-Url: https://git.lttng.org/?p=lttngtop.git;a=blobdiff_plain;f=src%2Flttngtop.c;h=d7bf627a702376fb952b04f7c3e9f113730cf0fa;hp=bfae663182c0cb89a9dd0d59da74a5627d66f09a;hb=a15e6a1039a885e137a08948593da8383777b6d5;hpb=bab469fc468832ae02c61e24bf3afaba24228c09 diff --git a/src/lttngtop.c b/src/lttngtop.c index bfae663..d7bf627 100644 --- a/src/lttngtop.c +++ b/src/lttngtop.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #ifdef LTTNGTOP_MMAP_LIVE #include @@ -52,14 +53,16 @@ #include "common.h" #include "network-live.h" -#include "lttng-index.h" +#define NET_URL_PREFIX "net://" +#define NET4_URL_PREFIX "net4://" +#define NET6_URL_PREFIX "net6://" #define DEFAULT_FILE_ARRAY_SIZE 1 const char *opt_input_path; -static int opt_textdump; -static int opt_child; -static int opt_begin; +int opt_textdump; +int opt_child; +int opt_begin; int quit = 0; @@ -81,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, @@ -212,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); @@ -234,42 +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"); - 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)); - 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: @@ -515,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); @@ -540,8 +588,8 @@ void init_lttngtop() void usage(FILE *fp) { fprintf(fp, "LTTngTop %s\n\n", VERSION); - fprintf(fp, "Usage : lttngtop [OPTIONS] [TRACE]\n"); - fprintf(fp, " TRACE Path to the trace to analyse (no trace path for live tracing)\n"); + fprintf(fp, "Usage : lttngtop [OPTIONS] TRACE\n"); + fprintf(fp, " TRACE Path to the trace to analyse (-r for network live tracing, nothing for mmap live streaming)\n"); fprintf(fp, " -h, --help This help message\n"); fprintf(fp, " -t, --textdump Display live events in text-only\n"); fprintf(fp, " -p, --pid Comma-separated list of PIDs to display\n"); @@ -637,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; @@ -653,13 +702,10 @@ static int parse_options(int argc, char **argv) opt_textdump = 1; break; case OPT_CHILD: - opt_textdump = 1; opt_child = 1; 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)); @@ -708,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) { @@ -733,6 +790,14 @@ void iter_trace(struct bt_context *bt_ctx) bt_ctf_iter_add_callback(iter, 0, NULL, 0, fix_process_table, NULL, NULL, NULL); + /* to handle the follow child option */ + 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, @@ -746,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( @@ -792,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; @@ -831,6 +910,19 @@ int bt_context_add_traces_recursive(struct bt_context *ctx, const char *path, char * const paths[2] = { lpath, NULL }; int ret = -1; + if ((strncmp(path, NET4_URL_PREFIX, sizeof(NET4_URL_PREFIX) - 1)) == 0 || + (strncmp(path, NET6_URL_PREFIX, sizeof(NET6_URL_PREFIX) - 1)) == 0 || + (strncmp(path, NET_URL_PREFIX, sizeof(NET_URL_PREFIX) - 1)) == 0) { + ret = bt_context_add_trace(ctx, + path, format_str, packet_seek, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "[warning] [Context] cannot open trace \"%s\" " + "for reading.\n", path); + /* Allow to skip erroneous traces. */ + ret = 1; /* partial error */ + } + return ret; + } /* * Need to copy path, because fts_open can change it. * It is the pointer array, not the strings, that are constant. @@ -1007,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) { @@ -1022,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) { @@ -1039,18 +1144,19 @@ int main(int argc, char **argv) goto end; #else - fprintf(stderr, "Mmap live support not compiled\n"); + fprintf(stderr, "[ERROR] Mmap live support not compiled, specify a " + "trace directory or -r \n"); + usage(stdout); + ret = -1; goto end; #endif /* LTTNGTOP_MMAP_LIVE */ } else if (!opt_input_path && remote_live) { /* network live */ - ret = setup_network_live(opt_relay_hostname, opt_begin); - if (ret < 0) { - goto end; - } - - ret = open_trace(&bt_ctx); + bt_ctx = bt_context_create(); + ret = bt_context_add_traces_recursive(bt_ctx, opt_relay_hostname, + "lttng-live", NULL); if (ret < 0) { + fprintf(stderr, "[error] Opening the trace\n"); goto end; } } else { @@ -1062,27 +1168,34 @@ int main(int argc, char **argv) fprintf(stderr, "[error] Opening the trace\n"); goto end; } - } - ret = check_requirements(bt_ctx); - if (ret < 0) { - fprintf(stderr, "[error] some mandatory contexts were missing, exiting.\n"); - goto end; - } - if (!opt_textdump) { - pthread_create(&display_thread, NULL, ncurses_display, (void *) NULL); - pthread_create(&timer_thread, NULL, refresh_thread, (void *) NULL); + ret = check_requirements(bt_ctx); + if (ret < 0) { + fprintf(stderr, "[error] some mandatory contexts " + "were missing, exiting.\n"); + goto end; + } + + if (!opt_textdump) { + pthread_create(&display_thread, NULL, ncurses_display, + (void *) NULL); + pthread_create(&timer_thread, NULL, refresh_thread, + (void *) NULL); + } + + iter_trace(bt_ctx); } - iter_trace(bt_ctx); pthread_join(display_thread, NULL); quit = 1; pthread_join(timer_thread, NULL); + ret = 0; + end: if (bt_ctx) bt_context_put(bt_ctx); - return 0; + return ret; }