/*
- * Copyright (C) 2011 Julien Desfossez
+ * Copyright (C) 2011-2012 Julien Desfossez
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License Version 2 as
unsigned int current_display_index = 0;
sem_wait(&bootstrap);
+ /*
+ * Prevent the 1 second delay when we hit ESC
+ */
+ ESCDELAY = 0;
init_ncurses();
while (1) {
{
unsigned long timestamp;
- timestamp = bt_ctf_get_timestamp(call_data);
+ timestamp = bt_ctf_get_real_timestamp(call_data);
if (timestamp == -1ULL)
goto error;
struct perfcounter *get_perf_counter(const char *name, struct processtop *proc,
struct cputime *cpu)
{
- struct perfcounter *ret, *global;
+ struct perfcounter *ret;
GHashTable *table;
if (proc)
ret->visible = 1;
g_hash_table_insert(table, (gpointer) strdup(name), ret);
- global = g_hash_table_lookup(lttngtop.perf_list, (gpointer) name);
- if (!global) {
- global = g_new0(struct perfcounter, 1);
- memcpy(global, ret, sizeof(struct perfcounter));
- /* by default, sort on the first perf context */
- if (g_hash_table_size(lttngtop.perf_list) == 0)
- global->sort = 1;
- g_hash_table_insert(lttngtop.perf_list, (gpointer) strdup(name), global);
- }
-
end:
return ret;
struct cputime *cpu)
{
struct definition const * const *list = NULL;
+ const struct definition *field;
unsigned int count;
- int i, ret;
+ struct perfcounter *perfcounter;
+ GHashTableIter iter;
+ gpointer key;
+ int ret;
if (!scope)
goto end;
if (ret < 0)
goto end;
- for (i = 0; i < count; i++) {
- const char *name = bt_ctf_field_name(list[i]);
- if (strncmp(name, "perf_", 5) == 0) {
- int value = bt_ctf_get_uint64(list[i]);
+ if (count == 0)
+ goto end;
+
+ g_hash_table_iter_init(&iter, global_perf_liszt);
+ while (g_hash_table_iter_next (&iter, &key, (gpointer) &perfcounter)) {
+ field = bt_ctf_get_field(event, scope, (char *) key);
+ if (field) {
+ int value = bt_ctf_get_uint64(field);
if (bt_ctf_field_get_error())
continue;
- update_perf_value(proc, cpu, name, value);
+ update_perf_value(proc, cpu, (char *) key, value);
}
}
struct processtop *parent, *child;
unsigned long timestamp;
- /* FIXME : display nice error when missing context pid, tid, ppid and comm */
-
- timestamp = bt_ctf_get_timestamp(call_data);
+ timestamp = bt_ctf_get_real_timestamp(call_data);
if (timestamp == -1ULL)
goto error;
pid = get_context_pid(call_data);
if (pid == -1ULL) {
-// fprintf(stderr, "Missing pid context info\n");
goto error;
}
tid = get_context_tid(call_data);
if (tid == -1ULL) {
-// fprintf(stderr, "Missing tid context info\n");
goto error;
}
ppid = get_context_ppid(call_data);
if (ppid == -1ULL) {
-// fprintf(stderr, "Missing ppid context info\n");
goto error;
}
comm = get_context_comm(call_data);
if (!comm) {
-// fprintf(stderr, "Missing procname context info\n");
goto error;
}
void init_lttngtop()
{
copies = g_ptr_array_new();
- lttngtop.perf_list = g_hash_table_new(g_str_hash, g_str_equal);
+ global_perf_liszt = g_hash_table_new(g_str_hash, g_str_equal);
sem_init(&goodtodisplay, 0, 0);
sem_init(&goodtoupdate, 0, 1);
usage(stdout);
ret = 1; /* exit cleanly */
goto end;
- case OPT_LIST:
- // list_formats(stdout);
- ret = 1;
- goto end;
- case OPT_VERBOSE:
-// babeltrace_verbose = 1;
- break;
- case OPT_DEBUG:
-// babeltrace_debug = 1;
- break;
- case OPT_NAMES:
-// opt_field_names = 1;
- break;
default:
ret = -EINVAL;
goto end;
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(
+ "lttng_statedump_process_state"),
+ NULL, 0, handle_statedump_process_state,
+ NULL, NULL, NULL);
/* for IO top */
bt_ctf_iter_add_callback(iter,
GArray *trace_ids;
char lpath[PATH_MAX];
char * const paths[2] = { lpath, NULL };
- int ret;
+ int ret = -1;
/*
* Need to copy path, because fts_open can change it.
}
metafd = openat(dirfd, "metadata", O_RDONLY);
if (metafd < 0) {
- ret = close(dirfd);
- if (ret < 0) {
- perror("close");
- goto error;
- }
+ close(dirfd);
+ ret = -1;
+ continue;
} else {
int trace_id;
node->fts_accpath, format_str,
packet_seek, NULL, NULL);
if (trace_id < 0) {
- fprintf(stderr, "[error] [Context] opening trace \"%s\" from %s "
+ fprintf(stderr, "[warning] [Context] opening trace \"%s\" from %s "
"for reading.\n", node->fts_accpath, path);
- ret = trace_id;
- goto error;
+ /* Allow to skip erroneous traces. */
+ continue;
}
g_array_append_val(trace_ids, trace_id);
}
}
g_array_free(trace_ids, TRUE);
- return 0;
+ return ret;
error:
return ret;
}
+static int check_field_requirements(const struct bt_ctf_field_decl *const * field_list,
+ int field_cnt, int *tid_check, int *pid_check,
+ int *procname_check, int *ppid_check)
+{
+ int j;
+ struct perfcounter *global;
+ const char *name;
+
+ for (j = 0; j < field_cnt; j++) {
+ name = bt_ctf_get_decl_field_name(field_list[j]);
+ if (*tid_check == 0) {
+ if (strncmp(name, "tid", 3) == 0)
+ (*tid_check)++;
+ }
+ if (*pid_check == 0) {
+ if (strncmp(name, "tid", 3) == 0)
+ (*pid_check)++;
+ }
+ if (*ppid_check == 0) {
+ if (strncmp(name, "ppid", 4) == 0)
+ (*ppid_check)++;
+ }
+ if (*procname_check == 0) {
+ if (strncmp(name, "procname", 8) == 0)
+ (*procname_check)++;
+ }
+ if (strncmp(name, "perf_", 5) == 0) {
+ global = g_hash_table_lookup(global_perf_liszt, (gpointer) name);
+ if (!global) {
+ global = g_new0(struct perfcounter, 1);
+ /* by default, sort on the first perf context */
+ if (g_hash_table_size(global_perf_liszt) == 0)
+ global->sort = 1;
+ global->visible = 1;
+ g_hash_table_insert(global_perf_liszt, (gpointer) strdup(name), global);
+ }
+ }
+ }
+
+ if (*tid_check == 1 && *pid_check == 1 && *ppid_check == 1 &&
+ *procname_check == 1)
+ return 0;
+
+ return -1;
+}
+
+/*
+ * check_requirements: check if the required context informations are available
+ *
+ * If each mandatory context information is available for at least in one
+ * event, return 0 otherwise return -1.
+ */
+int check_requirements(struct bt_context *ctx)
+{
+ unsigned int i, evt_cnt, field_cnt;
+ struct bt_ctf_event_decl *const * evt_list;
+ const struct bt_ctf_field_decl *const * field_list;
+ int tid_check = 0;
+ int pid_check = 0;
+ int procname_check = 0;
+ int ppid_check = 0;
+ int ret = 0;
+
+ bt_ctf_get_event_decl_list(0, ctx, &evt_list, &evt_cnt);
+ for (i = 0; i < evt_cnt; i++) {
+ bt_ctf_get_decl_fields(evt_list[i], BT_STREAM_EVENT_CONTEXT,
+ &field_list, &field_cnt);
+ ret = check_field_requirements(field_list, field_cnt,
+ &tid_check, &pid_check, &procname_check,
+ &ppid_check);
+
+ bt_ctf_get_decl_fields(evt_list[i], BT_EVENT_CONTEXT,
+ &field_list, &field_cnt);
+ ret = check_field_requirements(field_list, field_cnt,
+ &tid_check, &pid_check, &procname_check,
+ &ppid_check);
+
+ bt_ctf_get_decl_fields(evt_list[i], BT_STREAM_PACKET_CONTEXT,
+ &field_list, &field_cnt);
+ ret = check_field_requirements(field_list, field_cnt,
+ &tid_check, &pid_check, &procname_check,
+ &ppid_check);
+ }
+
+ if (tid_check == 0) {
+ ret = -1;
+ fprintf(stderr, "[error] missing tid context information\n");
+ }
+ if (pid_check == 0) {
+ ret = -1;
+ fprintf(stderr, "[error] missing pid context information\n");
+ }
+ if (ppid_check == 0) {
+ ret = -1;
+ fprintf(stderr, "[error] missing ppid context information\n");
+ }
+ if (procname_check == 0) {
+ ret = -1;
+ fprintf(stderr, "[error] missing procname context information\n");
+ }
+
+ return ret;
+}
+
int main(int argc, char **argv)
{
int ret;
bt_ctx = bt_context_create();
ret = bt_context_add_traces_recursive(bt_ctx, opt_input_path, "ctf", NULL);
if (ret < 0) {
- printf("[error] Opening the trace\n");
+ 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;
}