#include <fts.h>
#include <assert.h>
#include <sys/mman.h>
+#include <sys/wait.h>
#include <lttng/lttng.h>
#ifdef LTTNGTOP_MMAP_LIVE
#include <lttng/lttngtop-helper.h>
uint64_t delta;
struct tm start;
uint64_t ts_nsec_start;
- int pid, cpu_id, tid;
+ 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);
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;
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;
+ } 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;
(hostname) ? " ": "", cpu_id, procname, pid, tid,
bt_ctf_event_name(call_data));
print_fields(call_data);
- printf(")\n");
+ printf(")%s", (from_syscall) ? from_syscall : "\n");
+
+ free(from_syscall);
end:
return BT_CB_OK;
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);
int opt, ret = 0;
char *tmp_str;
int *tid;
+ int i;
remote_live = 0;
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));
}
}
- 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) {
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,
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(
}
}
+ 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;
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) {
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) {
#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);