rename lttngtop/ to src/
authorJulien Desfossez <julien.desfossez@efficios.com>
Tue, 21 Feb 2012 22:22:52 +0000 (17:22 -0500)
committerJulien Desfossez <julien.desfossez@efficios.com>
Tue, 21 Feb 2012 22:22:52 +0000 (17:22 -0500)
Signed-off-by: Julien Desfossez <julien.desfossez@efficios.com>
24 files changed:
Makefile.am
configure.ac
lttngtop/Makefile.am [deleted file]
lttngtop/common.c [deleted file]
lttngtop/common.h [deleted file]
lttngtop/cputop.c [deleted file]
lttngtop/cputop.h [deleted file]
lttngtop/cursesdisplay.c [deleted file]
lttngtop/cursesdisplay.h [deleted file]
lttngtop/iostreamtop.c [deleted file]
lttngtop/iostreamtop.h [deleted file]
lttngtop/lttngtop.c [deleted file]
lttngtop/lttngtoptypes.h [deleted file]
src/Makefile.am [new file with mode: 0644]
src/common.c [new file with mode: 0644]
src/common.h [new file with mode: 0644]
src/cputop.c [new file with mode: 0644]
src/cputop.h [new file with mode: 0644]
src/cursesdisplay.c [new file with mode: 0644]
src/cursesdisplay.h [new file with mode: 0644]
src/iostreamtop.c [new file with mode: 0644]
src/iostreamtop.h [new file with mode: 0644]
src/lttngtop.c [new file with mode: 0644]
src/lttngtoptypes.h [new file with mode: 0644]

index 009425c5cbd8a0cee01f2f7aed2ae2cedb43c770..733b0cdc983918a7d0c9421bb44003c016f0ca25 100644 (file)
@@ -2,4 +2,4 @@ AM_CFLAGS = $(PACKAGE_CFLAGS)
 
 ACLOCAL_AMFLAGS = -I m4
 
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = lttngtop
+SUBDIRS = src
index d38cefbeec235d04e5e54df219e56cb36b557ba0..495a5e07edefdd0dc98cd1f14607f549d7016c54 100644 (file)
@@ -66,6 +66,6 @@ AC_SUBST(PACKAGE_CFLAGS)
 
 AC_CONFIG_FILES([
        Makefile
 
 AC_CONFIG_FILES([
        Makefile
-       lttngtop/Makefile
+       src/Makefile
 ])
 AC_OUTPUT
 ])
 AC_OUTPUT
diff --git a/lttngtop/Makefile.am b/lttngtop/Makefile.am
deleted file mode 100644 (file)
index 5d6ca3e..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-AM_CFLAGS = $(PACKAGE_CFLAGS)
-
-bin_PROGRAMS = lttngtop
-
-lttngtop_SOURCES = \
-       lttngtop.c \
-       common.c \
-       cursesdisplay.c \
-       cputop.c \
-       iostreamtop.c
-
-lttngtop_LDADD = -lbabeltrace -lctf
diff --git a/lttngtop/common.c b/lttngtop/common.c
deleted file mode 100644 (file)
index 2a0f1f4..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright (C) 2011 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
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include "common.h"
-
-struct processtop *find_process_tid(struct lttngtop *ctx, int tid, char *comm)
-{
-       gint i;
-       struct processtop *tmp;
-
-       for (i = 0; i < ctx->process_table->len; i++) {
-               tmp = g_ptr_array_index(ctx->process_table, i);
-               if (tmp && tmp->tid == tid)
-                       return tmp;
-       }
-       return NULL;
-}
-
-struct processtop* add_proc(struct lttngtop *ctx, int tid, char *comm,
-               unsigned long timestamp)
-{
-       struct processtop *newproc;
-
-       /* if the PID already exists, we just rename the process */
-       /* FIXME : need to integrate with clone/fork/exit to be accurate */
-       newproc = find_process_tid(ctx, tid, comm);
-       if (!newproc) {
-               newproc = malloc(sizeof(struct processtop));
-               memset(newproc, 0, sizeof(struct processtop));
-               newproc->tid = tid;
-               newproc->birth = timestamp;
-               newproc->process_files_table = g_ptr_array_new();
-               newproc->threads = g_ptr_array_new();
-               newproc->perf = g_hash_table_new(g_direct_hash, g_direct_equal);
-               newproc->iostream = malloc(sizeof(struct iostream));
-               newproc->iostream->ret_read = 0;
-               newproc->iostream->ret_write = 0;
-               newproc->iostream->ret_total = 0;
-               newproc->iostream->syscall_info = NULL;
-               g_ptr_array_add(ctx->process_table, newproc);
-       }
-       newproc->comm = strdup(comm);
-
-       return newproc;
-}
-
-struct processtop* update_proc(struct processtop* proc, int pid, int tid,
-               int ppid, char *comm)
-{
-       if (proc) {
-               proc->pid = pid;
-               proc->tid = tid;
-               proc->ppid = ppid;
-               if (strcmp(proc->comm, comm) != 0) {
-                       free(proc->comm);
-                       proc->comm = strdup(comm);
-               }
-       }
-       return proc;
-}
-
-/*
- * This function just sets the time of death of a process.
- * When we rotate the cputime we remove it from the process list.
- */
-void death_proc(struct lttngtop *ctx, int tid, char *comm,
-               unsigned long timestamp)
-{
-       struct processtop *tmp;
-       tmp = find_process_tid(ctx, tid, comm);
-       if (tmp && strcmp(tmp->comm, comm) == 0)
-               tmp->death = timestamp;
-}
-
-struct processtop* get_proc(struct lttngtop *ctx, int tid, char *comm,
-               unsigned long timestamp)
-{
-       struct processtop *tmp;
-       tmp = find_process_tid(ctx, tid, comm);
-       if (tmp && strcmp(tmp->comm, comm) == 0)
-               return tmp;
-       return add_proc(ctx, tid, comm, timestamp);
-}
-
-void add_thread(struct processtop *parent, struct processtop *thread)
-{
-       gint i;
-       struct processtop *tmp;
-
-       for (i = 0; i < parent->threads->len; i++) {
-               tmp = g_ptr_array_index(parent->threads, i);
-               if (tmp == thread)
-                       return;
-       }
-       g_ptr_array_add(parent->threads, thread);
-}
-
-struct cputime* add_cpu(int cpu)
-{
-       struct cputime *newcpu;
-
-       newcpu = malloc(sizeof(struct cputime));
-       newcpu->id = cpu;
-       newcpu->current_task = NULL;
-       newcpu->perf = g_hash_table_new(g_direct_hash, g_direct_equal);
-
-       g_ptr_array_add(lttngtop.cpu_table, newcpu);
-
-       return newcpu;
-}
-struct cputime* get_cpu(int cpu)
-{
-       gint i;
-       struct cputime *tmp;
-
-       for (i = 0; i < lttngtop.cpu_table->len; i++) {
-               tmp = g_ptr_array_index(lttngtop.cpu_table, i);
-               if (tmp->id == cpu)
-                       return tmp;
-       }
-
-       return add_cpu(cpu);
-}
-
-/*
- * At the end of a sampling period, we need to display the cpu time for each
- * process and to reset it to zero for the next period
- */
-void rotate_cputime(unsigned long end)
-{
-       gint i;
-       struct cputime *tmp;
-       unsigned long elapsed;
-
-       for (i = 0; i < lttngtop.cpu_table->len; i++) {
-               tmp = g_ptr_array_index(lttngtop.cpu_table, i);
-               elapsed = end - tmp->task_start;
-               if (tmp->current_task) {
-                       tmp->current_task->totalcpunsec += elapsed;
-                       tmp->current_task->threadstotalcpunsec += elapsed;
-                       if (tmp->current_task->pid != tmp->current_task->tid &&
-                                       tmp->current_task->threadparent) {
-                               tmp->current_task->threadparent->threadstotalcpunsec += elapsed;
-                       }
-               }
-               tmp->task_start = end;
-       }
-}
-
-void reset_perf_counter(gpointer key, gpointer value, gpointer user_data)
-{
-       ((struct perfcounter*) value)->count = 0;
-}
-
-void copy_perf_counter(gpointer key, gpointer value, gpointer new_table)
-{
-       struct perfcounter *newperf;
-       
-       newperf = malloc(sizeof(struct perfcounter));
-       newperf->count = ((struct perfcounter *) value)->count;
-       newperf->visible = ((struct perfcounter *) value)->visible;
-       newperf->sort = ((struct perfcounter *) value)->sort;
-       g_hash_table_insert((GHashTable *) new_table, key, newperf);
-}
-
-void rotate_perfcounter() {
-       int i;
-       struct processtop *tmp;
-       for (i = 0; i < lttngtop.process_table->len; i++) {
-               tmp = g_ptr_array_index(lttngtop.process_table, i);
-               g_hash_table_foreach(tmp->perf, reset_perf_counter, NULL);
-       }
-}
-
-void cleanup_processtop()
-{
-       gint i;
-       struct processtop *tmp;
-
-       for (i = 0; i < lttngtop.process_table->len; i++) {
-               tmp = g_ptr_array_index(lttngtop.process_table, i);
-               tmp->totalcpunsec = 0;
-               tmp->threadstotalcpunsec = 0;
-               tmp->iostream->ret_read = 0;
-               tmp->iostream->ret_write = 0;
-       }
-}
-
-struct lttngtop* get_copy_lttngtop(unsigned long start, unsigned long end)
-{
-       gint i, j;
-       unsigned long time;
-       struct lttngtop *dst;
-       struct processtop *tmp, *tmp2, *new;
-       struct cputime *tmpcpu, *newcpu;
-       struct files *tmpfile, *newfile;
-
-       dst = malloc(sizeof(struct lttngtop));
-       dst = memset(dst, 0, sizeof(struct lttngtop));
-       dst->start = start;
-       dst->end = end;
-       dst->process_table = g_ptr_array_new();
-       dst->files_table = g_ptr_array_new();
-       dst->cpu_table = g_ptr_array_new();
-       dst->perf_list = g_hash_table_new(g_direct_hash, g_direct_equal);
-
-       rotate_cputime(end);
-
-       g_hash_table_foreach(lttngtop.perf_list, copy_perf_counter, dst->perf_list);
-       for (i = 0; i < lttngtop.process_table->len; i++) {
-               tmp = g_ptr_array_index(lttngtop.process_table, i);
-               new = malloc(sizeof(struct processtop));
-
-               memcpy(new, tmp, sizeof(struct processtop));
-               new->threads = g_ptr_array_new();
-               new->comm = strdup(tmp->comm);
-               new->process_files_table = g_ptr_array_new();
-               new->perf = g_hash_table_new(g_direct_hash, g_direct_equal);
-               g_hash_table_foreach(tmp->perf, copy_perf_counter, new->perf);
-
-               new->iostream = malloc(sizeof(struct iostream));
-               memcpy(new->iostream, tmp->iostream, sizeof(struct iostream));
-               /* compute the stream speed */
-               if (end - start != 0)
-               {
-                       time = (end - start)/NSEC_PER_SEC;
-                       new->iostream->ret_read = new->iostream->ret_read/(time);
-                       new->iostream->ret_write = new->iostream->ret_write/(time);
-               }
-
-               for (j = 0; j < tmp->process_files_table->len; j++) {
-                       tmpfile = g_ptr_array_index(tmp->process_files_table, j);
-                       newfile = malloc(sizeof(struct files));
-
-                       memcpy(newfile, tmpfile, sizeof(struct files));
-
-                       newfile->name = strdup(tmpfile->name);
-                       newfile->ref = new;
-
-                       g_ptr_array_add(new->process_files_table, newfile);
-                       g_ptr_array_add(dst->files_table, newfile);
-
-                       /*
-                        * if the process died during the last period, we remove all
-                        * files associated with if after the copy
-                        */
-                       if (tmp->death > 0 && tmp->death < end) {
-                               g_ptr_array_remove(tmp->process_files_table, tmpfile);
-                               free(tmpfile);
-                       }
-               }
-               g_ptr_array_add(dst->process_table, new);
-
-               /*
-                * if the process died during the last period, we remove it from
-                * the current process list after the copy
-                */
-               if (tmp->death > 0 && tmp->death < end) {
-                       g_ptr_array_remove(lttngtop.process_table, tmp);
-                       g_ptr_array_free(tmp->threads, TRUE);
-                       free(tmp->comm);
-                       g_ptr_array_free(tmp->process_files_table, TRUE);
-                       g_hash_table_destroy(tmp->perf);
-                       free(tmp);
-               }
-       }
-       rotate_perfcounter();
-
-       for (i = 0; i < lttngtop.cpu_table->len; i++) {
-               tmpcpu = g_ptr_array_index(lttngtop.cpu_table, i);
-               newcpu = malloc(sizeof(struct cputime));
-               memcpy(newcpu, tmpcpu, sizeof(struct cputime));
-               newcpu->perf = g_hash_table_new(g_direct_hash, g_direct_equal);
-               g_hash_table_foreach(tmpcpu->perf, copy_perf_counter, newcpu->perf);
-               /*
-                * note : we don't care about the current process pointer in the copy
-                * so the reference is invalid after the memcpy
-                */
-               g_ptr_array_add(dst->cpu_table, newcpu);
-       }
-       /* create the threads index if required */
-       for (i = 0; i < dst->process_table->len; i++) {
-               tmp = g_ptr_array_index(dst->process_table, i);
-               if (tmp->pid == tmp->tid) {
-                       for (j = 0; j < dst->process_table->len; j++) {
-                               tmp2 = g_ptr_array_index(dst->process_table, j);
-                               if (tmp2->pid == tmp->pid) {
-                                       tmp2->threadparent = tmp;
-                                       g_ptr_array_add(tmp->threads, tmp2);
-                               }
-                       }
-               }
-       }
-
-       //  update_global_stats(dst);
-       cleanup_processtop();
-
-       return dst;
-}
-
diff --git a/lttngtop/common.h b/lttngtop/common.h
deleted file mode 100644 (file)
index e81256c..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2011 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
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#ifndef _COMMON_H
-#define _COMMON_H
-
-#include <semaphore.h>
-#include <babeltrace/ctf/events.h>
-#include "lttngtoptypes.h"
-#include "cputop.h"
-
-#define NSEC_PER_USEC 1000
-#define NSEC_PER_SEC 1000000000L
-
-sem_t goodtodisplay, goodtoupdate, timer, pause_sem, end_trace_sem, bootstrap;
-
-GPtrArray *copies; /* struct lttngtop */
-pthread_mutex_t perf_list_mutex;
-
-struct lttngtop *data;
-
-struct processtop *find_process_tid(struct lttngtop *ctx, int pid, char *comm);
-struct processtop* add_proc(struct lttngtop *ctx, int pid, char *comm,
-               unsigned long timestamp);
-struct processtop* update_proc(struct processtop* proc, int pid, int tid,
-               int ppid, char *comm);
-void add_thread(struct processtop *parent, struct processtop *thread);
-struct processtop* get_proc(struct lttngtop *ctx, int tid, char *comm,
-               unsigned long timestamp);
-void death_proc(struct lttngtop *ctx, int tid, char *comm,
-               unsigned long timestamp);
-struct cputime* add_cpu(int cpu);
-struct cputime* get_cpu(int cpu);
-struct lttngtop* get_copy_lttngtop(unsigned long start, unsigned long end);
-struct perfcounter *add_perf_counter(GPtrArray *perf, GQuark quark,
-               unsigned long count);
-struct perfcounter *get_perf_counter(const char *name, struct processtop *proc,
-               struct cputime *cpu);
-
-#endif /* _COMMON_H */
diff --git a/lttngtop/cputop.c b/lttngtop/cputop.c
deleted file mode 100644 (file)
index 2ade0db..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2011 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
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#include <babeltrace/babeltrace.h>
-
-#include "lttngtoptypes.h"
-#include "common.h"
-#include "cputop.h"
-
-void update_cputop_data(unsigned long timestamp, int64_t cpu, int prev_pid,
-               int next_pid, char *prev_comm, char *next_comm)
-{
-       struct cputime *tmpcpu;
-       unsigned long elapsed;
-
-       tmpcpu = get_cpu(cpu);
-
-       if (tmpcpu->current_task && tmpcpu->current_task->pid == prev_pid) {
-               elapsed = timestamp - tmpcpu->task_start;
-               tmpcpu->current_task->totalcpunsec += elapsed;
-               tmpcpu->current_task->threadstotalcpunsec += elapsed;
-               if (tmpcpu->current_task->pid != tmpcpu->current_task->tid)
-                       tmpcpu->current_task->threadparent->threadstotalcpunsec += elapsed;
-       }
-
-       if (next_pid != 0)
-               tmpcpu->current_task = get_proc(&lttngtop, next_pid, next_comm, timestamp);
-       else
-               tmpcpu->current_task = NULL;
-
-       tmpcpu->task_start = timestamp;
-}
-
-enum bt_cb_ret handle_sched_switch(struct bt_ctf_event *call_data,
-               void *private_data)
-{
-       struct definition *scope;
-       unsigned long timestamp;
-       uint64_t cpu_id;
-       char *prev_comm, *next_comm;
-       int prev_tid, next_tid;
-
-       timestamp = bt_ctf_get_timestamp(call_data);
-       if (timestamp == -1ULL)
-               goto error;
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_EVENT_FIELDS);
-       prev_comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
-                               scope, "_prev_comm"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing prev_comm context info\n");
-               goto error;
-       }
-
-       next_comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
-                               scope, "_next_comm"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing next_comm context info\n");
-               goto error;
-       }
-
-       prev_tid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
-                               scope, "_prev_tid"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing prev_tid context info\n");
-               goto error;
-       }
-
-       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 context info\n");
-               goto error;
-       }
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_STREAM_PACKET_CONTEXT);
-       cpu_id = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
-                               scope, "cpu_id"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing cpu_id context info\n");
-               goto error;
-       }
-
-       update_cputop_data(timestamp, cpu_id, prev_tid, next_tid,
-                       prev_comm, next_comm);
-
-       return BT_CB_OK;
-
-error:
-       return BT_CB_ERROR_STOP;
-}
-
-enum bt_cb_ret handle_sched_process_free(struct bt_ctf_event *call_data,
-               void *private_data)
-{
-       struct definition *scope;
-       unsigned long timestamp;
-       char *comm;
-       int tid;
-
-       timestamp = bt_ctf_get_timestamp(call_data);
-       if (timestamp == -1ULL)
-               goto error;
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_EVENT_FIELDS);
-       comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
-                               scope, "_comm"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing procname context info\n");
-               goto error;
-       }
-
-       tid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
-                               scope, "_tid"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing tid context info\n");
-               goto error;
-       }
-
-       death_proc(&lttngtop, tid, comm, timestamp);
-
-       return BT_CB_OK;
-
-error:
-       return BT_CB_ERROR_STOP;
-
-}
-
diff --git a/lttngtop/cputop.h b/lttngtop/cputop.h
deleted file mode 100644 (file)
index 8b57823..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2011 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
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#ifndef _LTTNGTOP_H
-#define _LTTNGTOP_H
-
-#include <babeltrace/babeltrace.h>
-#include <babeltrace/ctf/callbacks.h>
-#include <inttypes.h>
-#include <glib.h>
-
-enum bt_cb_ret handle_sched_switch(struct bt_ctf_event *hook_data,
-               void *call_data);
-
-enum bt_cb_ret handle_sched_process_free(struct bt_ctf_event *call_data,
-               void *private_data);
-
-#endif /* _LTTNGTOP_H */
diff --git a/lttngtop/cursesdisplay.c b/lttngtop/cursesdisplay.c
deleted file mode 100644 (file)
index 0f79485..0000000
+++ /dev/null
@@ -1,1003 +0,0 @@
-/*
- * Copyright (C) 2011 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
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <ncurses.h>
-#include <panel.h>
-#include <pthread.h>
-#include <semaphore.h>
-
-#include "cursesdisplay.h"
-#include "lttngtoptypes.h"
-#include "common.h"
-
-#define DEFAULT_DELAY 15
-#define MAX_LINE_LENGTH 50
-#define MAX_LOG_LINES 4
-
-/* to prevent concurrent updates of the different windows */
-sem_t update_display_sem;
-
-char *termtype;
-WINDOW *footer, *header, *center, *status;
-WINDOW *perf_panel_window = NULL;
-PANEL *perf_panel, *main_panel;
-
-int perf_panel_visible = 0;
-int perf_line_selected = 0;
-
-int last_display_index, currently_displayed_index;
-
-struct processtop *selected_process = NULL;
-int selected_tid;
-char *selected_comm;
-int selected_ret;
-
-int selected_line = 0; /* select bar position */
-int selected_in_list = 0; /* selection relative to the whole list */
-int list_offset = 0; /* first index in the list to display (scroll) */
-int nb_log_lines = 0;
-char log_lines[MAX_LINE_LENGTH * MAX_LOG_LINES + MAX_LOG_LINES];
-
-int max_elements = 80;
-
-int toggle_threads = -1;
-int toggle_pause = -1;
-int toggle_tree = -1;
-
-int max_center_lines;
-
-pthread_t keyboard_thread;
-
-void reset_ncurses()
-{
-       curs_set(1);
-       endwin();
-       exit(0);
-}
-
-static void handle_sigterm(int signal)
-{
-       reset_ncurses();
-}
-
-void init_screen()
-{
-       initscr();
-       noecho();
-       halfdelay(DEFAULT_DELAY);
-       nonl();
-       intrflush(stdscr, false);
-       keypad(stdscr, true);
-       curs_set(0);
-
-       if (has_colors()) {
-               start_color();
-               init_pair(1, COLOR_RED, COLOR_BLACK); /* - */
-               init_pair(2, COLOR_GREEN, COLOR_BLACK); /* + */
-               init_pair(3, COLOR_BLACK, COLOR_WHITE); /* keys */
-               init_pair(4, COLOR_WHITE, COLOR_GREEN); /* keys activated */
-               init_pair(5, COLOR_WHITE, COLOR_BLUE); /* select line */
-       }
-       termtype = getenv("TERM");
-       if (!strcmp(termtype, "xterm") ||  !strcmp(termtype, "xterm-color") ||
-                       !strcmp(termtype, "vt220")) {
-               define_key("\033[H", KEY_HOME);
-               define_key("\033[F", KEY_END);
-               define_key("\033OP", KEY_F(1));
-               define_key("\033OQ", KEY_F(2));
-               define_key("\033OR", KEY_F(3));
-               define_key("\033OS", KEY_F(4));
-               define_key("\0330U", KEY_F(6));
-               define_key("\033[11~", KEY_F(1));
-               define_key("\033[12~", KEY_F(2));
-               define_key("\033[13~", KEY_F(3));
-               define_key("\033[14~", KEY_F(4));
-               define_key("\033[16~", KEY_F(6));
-               define_key("\033[17;2~", KEY_F(18));
-       }
-       signal(SIGTERM, handle_sigterm);
-       mousemask(BUTTON1_CLICKED, NULL);
-       refresh();
-}
-
-WINDOW *create_window(int height, int width, int startx, int starty)
-{
-       WINDOW *win;
-       win = newwin(height, width, startx, starty);
-       box(win, 0 , 0);
-       wrefresh(win);
-       return win;
-}
-
-WINDOW *create_window_no_border(int height, int width, int startx, int starty)
-{
-       WINDOW *win;
-       win = newwin(height, width, startx, starty);
-       wrefresh(win);
-       return win;
-}
-
-void print_digit(WINDOW *win, int digit)
-{
-       if (digit < 0) {
-               wattron(win, COLOR_PAIR(1));
-               wprintw(win, "%d", digit);
-               wattroff(win, COLOR_PAIR(1));
-       } else if (digit > 0) {
-               wattron(win, COLOR_PAIR(2));
-               wprintw(win, "+%d", digit);
-               wattroff(win, COLOR_PAIR(2));
-       } else {
-               wprintw(win, "0");
-       }
-}
-
-void print_digits(WINDOW *win, int first, int second)
-{
-       wprintw(win, "(");
-       print_digit(win, first);
-       wprintw(win, ", ");
-       print_digit(win, second);
-       wprintw(win, ")");
-}
-
-void print_headers(int line, char *desc, int value, int first, int second)
-{
-       wattron(header, A_BOLD);
-       mvwprintw(header, line, 4, "%s", desc);
-       wattroff(header, A_BOLD);
-       mvwprintw(header, line, 16, "N/A", value);
-       wmove(header, line, 24);
-       print_digits(header, first, second);
-       wmove(header, line, 40);
-}
-
-void set_window_title(WINDOW *win, char *title)
-{
-       wattron(win, A_BOLD);
-       mvwprintw(win, 0, 1, title);
-       wattroff(win, A_BOLD);
-}
-
-void print_log(char *str)
-{
-       int i;
-       int current_line = 1;
-       int current_char = 1;
-       char *tmp, *tmp2;
-       /* rotate the line buffer */
-       if (nb_log_lines >= MAX_LOG_LINES) {
-               tmp = strndup(log_lines, MAX_LINE_LENGTH * MAX_LOG_LINES + MAX_LOG_LINES);
-               tmp2 = strchr(tmp, '\n');
-               memset(log_lines, '\0', strlen(log_lines));
-               strncat(log_lines, tmp2 + 1, strlen(tmp2) - 1);
-               log_lines[strlen(log_lines)] = '\n';
-               log_lines[strlen(log_lines)] = '\0';
-               free(tmp);
-       }
-       nb_log_lines++;
-
-       strncat(log_lines, str, MAX_LINE_LENGTH - 1);
-
-       if (nb_log_lines < MAX_LOG_LINES)
-               log_lines[strlen(log_lines)] = '\n';
-       log_lines[strlen(log_lines)] = '\0';
-
-       werase(status);
-       box(status, 0 , 0);
-       set_window_title(status, "Status");
-       for (i = 0; i < strlen(log_lines); i++) {
-               if (log_lines[i] == '\n') {
-                       wmove(status, ++current_line, 1);
-                       current_char = 1;
-               } else {
-                       mvwprintw(status, current_line, current_char++, "%c", log_lines[i]);
-               }
-       }
-       wrefresh(status);
-}
-
-void print_key(WINDOW *win, char *key, char *desc, int toggle)
-{
-       int pair;
-       if (toggle > 0)
-               pair = 4;
-       else
-               pair = 3;
-       wattron(win, COLOR_PAIR(pair));
-       wprintw(footer, "%s", key);
-       wattroff(win, COLOR_PAIR(pair));
-       wprintw(footer, ":%s", desc);
-}
-
-void update_footer()
-{
-       sem_wait(&update_display_sem);
-       werase(footer);
-       wmove(footer, 1, 1);
-       print_key(footer, "F2", "CPUtop  ", current_view == cpu);
-       print_key(footer, "F3", "PerfTop  ", current_view == perf);
-       print_key(footer, "F6", "IOTop  ", current_view == iostream);
-       print_key(footer, "Enter", "Details  ", current_view == process_details);
-       print_key(footer, "q", "Quit | ", 0);
-       print_key(footer, "P", "Perf Pref  ", 0);
-       print_key(footer, "p", "Pause  ", toggle_pause);
-
-       wrefresh(footer);
-       sem_post(&update_display_sem);
-}
-
-void basic_header()
-{
-       werase(header);
-       box(header, 0 , 0);
-       set_window_title(header, "Statistics for interval [gathering data...[");
-       wattron(header, A_BOLD);
-       mvwprintw(header, 1, 4, "CPUs");
-       mvwprintw(header, 2, 4, "Processes");
-       mvwprintw(header, 3, 4, "Threads");
-       mvwprintw(header, 4, 4, "Files");
-       mvwprintw(header, 5, 4, "Network");
-       mvwprintw(header, 6, 4, "IO");
-       wattroff(header, A_BOLD);
-       wrefresh(header);
-}
-
-void update_header()
-{
-       werase(header);
-       box(header, 0 , 0);
-       set_window_title(header, "Statistics for interval ");
-       wattron(header, A_BOLD);
-       /*
-       wprintw(header, "[%lu.%lu, %lu.%lu[",
-                       data->start.tv_sec, data->start.tv_nsec,
-                       data->end.tv_sec, data->end.tv_nsec);
-                       */
-       wprintw(header, "[%lu, %lu[",
-            data->start,
-            data->end);
-       mvwprintw(header, 1, 4, "CPUs");
-       wattroff(header, A_BOLD);
-       wprintw(header, "\t%d\t(max/cpu : %0.2f%)", data->cpu_table->len,
-                       100.0/data->cpu_table->len);
-       print_headers(2, "Processes", data->nbproc, data->nbnewproc,
-                       -1*(data->nbdeadproc));
-       print_headers(3, "Threads", data->nbthreads, data->nbnewthreads,
-                       -1*(data->nbdeadthreads));
-       print_headers(4, "Files", data->nbfiles, data->nbnewfiles,
-                       -1*(data->nbclosedfiles));
-       mvwprintw(header, 4, 43, "N/A kbytes/sec");
-       print_headers(5, "Network", 114, 0, 0);
-       mvwprintw(header, 5, 43, "N/A Mbytes/sec");
-       wrefresh(header);
-}
-
-gint sort_by_cpu_desc(gconstpointer p1, gconstpointer p2)
-{
-       struct processtop *n1 = *(struct processtop **)p1;
-       struct processtop *n2 = *(struct processtop **)p2;
-       unsigned long totaln1 = n1->totalcpunsec;
-       unsigned long totaln2 = n2->totalcpunsec;
-
-       if (totaln1 < totaln2)
-               return 1;
-       if (totaln1 == totaln2)
-               return 0;
-       return -1;
-}
-
-gint sort_by_cpu_group_by_threads_desc(gconstpointer p1, gconstpointer p2)
-{
-       struct processtop *n1 = *(struct processtop **)p1;
-       struct processtop *n2 = *(struct processtop **)p2;
-       unsigned long totaln1 = n1->threadstotalcpunsec;
-       unsigned long totaln2 = n2->threadstotalcpunsec;
-
-       if (totaln1 < totaln2)
-               return 1;
-       if (totaln1 == totaln2)
-               return 0;
-       return -1;
-}
-
-void update_cputop_display()
-{
-       int i;
-       int header_offset = 2;
-       struct processtop *tmp;
-       unsigned long elapsed;
-       double maxcputime;
-       int nblinedisplayed = 0;
-       int current_line = 0;
-
-       elapsed = data->end - data->start;
-       maxcputime = elapsed * data->cpu_table->len / 100.0;
-
-       g_ptr_array_sort(data->process_table, sort_by_cpu_desc);
-
-       set_window_title(center, "CPU Top");
-       wattron(center, A_BOLD);
-       mvwprintw(center, 1, 1, "CPU(%)");
-       mvwprintw(center, 1, 12, "TGID");
-       mvwprintw(center, 1, 22, "PID");
-       mvwprintw(center, 1, 32, "NAME");
-       wattroff(center, A_BOLD);
-
-       max_center_lines = LINES - 7 - 7 - 1 - header_offset;
-
-       /* iterate the process (thread) list */
-       for (i = list_offset; i < data->process_table->len &&
-                       nblinedisplayed < max_center_lines; i++) {
-               tmp = g_ptr_array_index(data->process_table, i);
-
-               if (current_line == selected_line) {
-                       selected_process = tmp;
-                       selected_tid = tmp->tid;
-                       selected_comm = tmp->comm;
-                       wattron(center, COLOR_PAIR(5));
-                       mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
-               }
-               /* CPU(%) */
-               mvwprintw(center, current_line + header_offset, 1, "%1.2f",
-                               tmp->totalcpunsec / maxcputime);
-               /* TGID */
-               mvwprintw(center, current_line + header_offset, 12, "%d", tmp->pid);
-               /* PID */
-               mvwprintw(center, current_line + header_offset, 22, "%d", tmp->tid);
-               /* NAME */
-               mvwprintw(center, current_line + header_offset, 32, "%s", tmp->comm);
-               wattroff(center, COLOR_PAIR(5));
-               nblinedisplayed++;
-               current_line++;
-       }
-}
-
-gint sort_perf(gconstpointer p1, gconstpointer p2, gpointer key)
-{
-       struct processtop *n1 = *(struct processtop **) p1;
-       struct processtop *n2 = *(struct processtop **) p2;
-
-       struct perfcounter *tmp1, *tmp2;
-       unsigned long totaln2 = 0;
-       unsigned long totaln1 = 0;
-
-       if (!key)
-               return 0;
-
-       tmp1 = g_hash_table_lookup(n1->perf, key);
-       if (!tmp1)
-               totaln1 = 0;
-       else
-               totaln1 = tmp1->count;
-
-       tmp2 = g_hash_table_lookup(n2->perf, key);
-       if (!tmp2)
-               totaln2 = 0;
-       else
-               totaln2 = tmp2->count;
-
-       if (totaln1 < totaln2)
-               return 1;
-       if (totaln1 == totaln2) {
-               totaln1 = n1->tid;
-               totaln2 = n2->tid;
-               if (totaln1 < totaln2)
-                       return 1;
-               return -1;
-       }
-       return -1;
-}
-
-void print_key_title(char *key, int line)
-{
-       wattron(center, A_BOLD);
-       mvwprintw(center, line, 1, "%s\t", key);
-       wattroff(center, A_BOLD);
-}
-
-void update_process_details()
-{
-       unsigned long elapsed;
-       double maxcputime;
-       struct processtop *tmp = find_process_tid(data, selected_tid, selected_comm);
-
-       set_window_title(center, "Process details");
-
-
-       elapsed = data->end - data->start;
-       maxcputime = elapsed * data->cpu_table->len / 100.0;
-
-       print_key_title("Name", 1);
-       wprintw(center, "%s", selected_comm);
-       print_key_title("TID", 2);
-       wprintw(center, "%d", selected_tid);
-       if (!tmp) {
-               print_key_title("Does not exit at this time", 3);
-               return;
-       }
-
-       print_key_title("PID", 3);
-       wprintw(center, "%d", tmp->pid);
-       print_key_title("PPID", 4);
-       wprintw(center, "%d", tmp->ppid);
-       print_key_title("CPU", 5);
-       wprintw(center, "%1.2f %%", tmp->totalcpunsec/maxcputime);
-}
-
-void update_perf()
-{
-       int i, j;
-       int nblinedisplayed = 0;
-       int current_line = 0;
-       struct processtop *tmp;
-       int header_offset = 2;
-       int perf_row = 40;
-       struct perfcounter *perfn1, *perfn2;
-       GList *perflist;
-       char *perf_key = NULL;
-       int value;
-
-       set_window_title(center, "Perf Top");
-       wattron(center, A_BOLD);
-       mvwprintw(center, 1, 1, "PID");
-       mvwprintw(center, 1, 11, "TID");
-       mvwprintw(center, 1, 22, "NAME");
-
-       perf_row = 40;
-       perflist = g_list_first(g_hash_table_get_keys(data->perf_list));
-       while (perflist) {
-               perfn1 = g_hash_table_lookup(data->perf_list, perflist->data);
-               /* + 6 to strip the "_perf_" prefix */
-               if (perfn1->visible) {
-                       mvwprintw(center, 1, perf_row, "%s",
-                                       (char *) perflist->data + 6);
-                       perf_row += 20;
-               }
-               if (perfn1->sort) {
-                       perf_key = (char *) perflist->data;
-               }
-               perflist = g_list_next(perflist);
-       }
-       wattroff(center, A_BOLD);
-
-       g_ptr_array_sort_with_data(data->process_table, sort_perf, perf_key);
-       for (i = 0; i < data->process_table->len && 
-                       nblinedisplayed < max_center_lines; i++) {
-               GList *perf_keys;
-               tmp = g_ptr_array_index(data->process_table, i);
-
-               if (current_line == selected_line) {
-                       selected_process = tmp;
-                       wattron(center, COLOR_PAIR(5));
-                       mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
-               }
-
-               mvwprintw(center, current_line + header_offset, 1, "%d", tmp->pid);
-               mvwprintw(center, current_line + header_offset, 11, "%d", tmp->tid);
-               mvwprintw(center, current_line + header_offset, 22, "%s", tmp->comm);
-
-               /* FIXME : sometimes there is a segfault here, I have no idea why :-( */
-               perf_keys = g_hash_table_get_keys(data->perf_list);
-               if (perf_keys)
-                       perflist = g_list_first(perf_keys);
-               else
-                       perflist = NULL;
-
-               perf_row = 40;
-               j = 0;
-               while (perflist) {
-                       j++;
-                       perfn1 = g_hash_table_lookup(data->perf_list, perflist->data);
-                       if (!perfn1) {
-                               perflist = g_list_next(perflist);
-                               continue;
-                       }
-                       if (perfn1->visible) {
-                               perfn2 = g_hash_table_lookup(tmp->perf, perflist->data);
-                               if (perfn2)
-                                       value = perfn2->count;
-                               else
-                                       value = 0;
-                               mvwprintw(center, current_line + header_offset, perf_row, "%d", value);
-                               perf_row += 20;
-                       }
-                       perflist = g_list_next(perflist);
-               }
-
-               wattroff(center, COLOR_PAIR(5));
-               nblinedisplayed++;
-               current_line++;
-       }
-}
-
-void update_fileio()
-{
-       int i;
-       int offset;
-
-       set_window_title(center, "IO Top");
-       wattron(center, A_BOLD);
-       mvwprintw(center, 1, 10, "READ");
-       mvwprintw(center, 2, 1, "bytes");
-       mvwprintw(center, 2, 15, "bytes/sec");
-
-       mvwprintw(center, 1, 39, "WRITE");
-       mvwprintw(center, 2, 33, "bytes");
-       mvwprintw(center, 2, 45, "bytes/sec");
-
-       if (toggle_threads > 0) {
-               mvwprintw(center, 1, 60, "TGID");
-               mvwprintw(center, 1, 70, "PID");
-               offset = 8;
-       } else {
-               mvwprintw(center, 1, 60, "PID(TGID)");
-               offset = 0;
-       }
-       mvwprintw(center, 1, 72 + offset, "NAME");
-       wattroff(center, A_BOLD);
-
-       for (i = 3; i < LINES - 3 - 8 - 1; i++) {
-               mvwprintw(center, i, 1, "%d", i*1000);
-               mvwprintw(center, i, 15, "%dk", i);
-               mvwprintw(center, i, 28, "|    %d", i*2000);
-               mvwprintw(center, i, 45, "%dk", i*2);
-               if (toggle_threads > 0) {
-                       mvwprintw(center, i, 57, "|  %d", i);
-                       mvwprintw(center, i, 70, "%d", i);
-               } else {
-                       mvwprintw(center, i, 57, "|  %d", i);
-               }
-               mvwprintw(center, i, 72 + offset, "process_%d", i);
-       }
-}
-
-gint sort_by_ret_desc(gconstpointer p1, gconstpointer p2)
-{
-       struct processtop *n1 = *(struct processtop **)p1;
-       struct processtop *n2 = *(struct processtop **)p2;
-       unsigned long totaln1 = n1->iostream->ret_total;
-       unsigned long totaln2 = n2->iostream->ret_total;
-
-       if (totaln1 < totaln2)
-               return 1;
-       if (totaln1 == totaln2)
-               return 0;
-       return -1;
-}
-
-void update_iostream()
-{
-       int i;
-       int header_offset = 2;
-       struct processtop *tmp;
-       int nblinedisplayed = 0;
-       int current_line = 0;
-
-       set_window_title(center, "IO Top");
-       wattron(center, A_BOLD);
-       mvwprintw(center, 1, 1, "READ (B/s)");
-       mvwprintw(center, 1, 20, "WRITE (B/s)");
-
-       mvwprintw(center, 1, 40, "TOTAL STREAM");
-
-       mvwprintw(center, 1, 60, "TGID");
-       mvwprintw(center, 1, 80, "PID");
-
-       mvwprintw(center, 1, 92, "NAME");
-       wattroff(center, A_BOLD);
-
-       g_ptr_array_sort(data->process_table, sort_by_ret_desc);
-
-       for (i = list_offset; i < data->process_table->len &&
-                       nblinedisplayed < max_center_lines; i++) {
-               tmp = g_ptr_array_index(data->process_table, i);
-
-               if (current_line == selected_line) {
-                       selected_process = tmp;
-                       selected_tid = tmp->tid;
-                       selected_comm = tmp->comm;
-                       wattron(center, COLOR_PAIR(5));
-                       mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
-               }
-               /* READ (bytes/sec) */
-               mvwprintw(center, current_line + header_offset, 1, "%lu",
-                               tmp->iostream->ret_read);
-
-               /* WRITE (bytes/sec) */
-               mvwprintw(center, current_line + header_offset, 20, "%lu",
-                               tmp->iostream->ret_write);
-
-               /* TOTAL STREAM */
-               if(tmp->iostream->ret_total >= 1000000)
-                       mvwprintw(center, current_line + header_offset, 40, "%lu MB",
-                                       tmp->iostream->ret_total/1000000);
-               else if(tmp->iostream->ret_total >=1000)
-                       mvwprintw(center, current_line + header_offset, 40, "%lu KB",
-                                       tmp->iostream->ret_total/1000);
-               else
-                       mvwprintw(center, current_line + header_offset, 40, "%lu B",
-                                       tmp->iostream->ret_total);
-               /* TGID */
-               mvwprintw(center, current_line + header_offset, 60, "%d", tmp->pid);
-               /* PID */
-               mvwprintw(center, current_line + header_offset, 80, "%d", tmp->tid);
-               /* NAME */
-               mvwprintw(center, current_line + header_offset, 92, "%s", tmp->comm);
-               wattroff(center, COLOR_PAIR(5));
-               nblinedisplayed++;
-               current_line++;
-       }
-}
-
-void update_current_view()
-{
-       sem_wait(&update_display_sem);
-       if (!data)
-               return;
-       update_header();
-
-       werase(center);
-       box(center, 0, 0);
-       switch (current_view) {
-       case cpu:
-               update_cputop_display();
-               break;
-       case perf:
-               update_perf();
-               break;
-       case process_details:
-               update_process_details();
-               break;
-       case fileio:
-               update_fileio();
-               break;
-       case iostream:
-               update_iostream();
-               break;
-       case tree:
-               update_cputop_display();
-               break;
-       default:
-               break;
-       }
-       update_panels();
-       doupdate();
-       sem_post(&update_display_sem);
-}
-
-void setup_perf_panel()
-{
-       int size;
-       if (!data)
-               return;
-       if (perf_panel_window) {
-               del_panel(perf_panel);
-               delwin(perf_panel_window);
-       }
-       size = g_hash_table_size(data->perf_list);
-       perf_panel_window = create_window(size + 2, 30, 10, 10);
-       perf_panel = new_panel(perf_panel_window);
-       perf_panel_visible = 0;
-       hide_panel(perf_panel);
-}
-
-void update_perf_panel(int line_selected, int toggle_view, int toggle_sort)
-{
-       int i;
-       struct perfcounter *perf;
-       GList *perflist;
-
-       if (!data)
-               return;
-
-       werase(perf_panel_window);
-       box(perf_panel_window, 0 , 0);
-       set_window_title(perf_panel_window, "Perf Preferences ");
-       wattron(perf_panel_window, A_BOLD);
-       mvwprintw(perf_panel_window, g_hash_table_size(data->perf_list) + 1, 1, " 's' to sort");
-       wattroff(perf_panel_window, A_BOLD);
-
-       if (toggle_sort == 1) {
-               i = 0;
-               perflist = g_list_first(g_hash_table_get_keys(data->perf_list));
-               while (perflist) {
-                       perf = g_hash_table_lookup(data->perf_list, perflist->data);
-                       if (i != line_selected)
-                               perf->sort = 0;
-                       else
-                               perf->sort = 1;
-                       i++;
-                       perflist = g_list_next(perflist);
-               }
-               update_current_view();
-       }
-
-       i = 0;
-       perflist = g_list_first(g_hash_table_get_keys(data->perf_list));
-       while (perflist) {
-               perf = g_hash_table_lookup(data->perf_list, perflist->data);
-               if (i == line_selected && toggle_view == 1) {
-                       perf->visible = perf->visible == 1 ? 0:1;
-                       update_current_view();
-               }
-               if (i == line_selected) {
-                       wattron(perf_panel_window, COLOR_PAIR(5));
-                       mvwhline(perf_panel_window, i + 1, 1, ' ', 30 - 2);
-               }
-               if (perf->sort == 1)
-                       wattron(perf_panel_window, A_BOLD);
-               mvwprintw(perf_panel_window, i + 1, 1, "[%c] %s",
-                               perf->visible == 1 ? 'x' : ' ',
-                               (char *) perflist->data + 6);
-               wattroff(perf_panel_window, A_BOLD);
-               wattroff(perf_panel_window, COLOR_PAIR(5));
-               i++;
-               perflist = g_list_next(perflist);
-       }
-       update_panels();
-       doupdate();
-}
-
-
-void toggle_perf_panel(void)
-{
-       if (perf_panel_visible) {
-               hide_panel(perf_panel);
-               perf_panel_visible = 0;
-       } else {
-               setup_perf_panel();
-               update_perf_panel(perf_line_selected, 0, 0);
-               show_panel(perf_panel);
-               perf_panel_visible = 1;
-       }
-       update_panels();
-       doupdate();
-}
-
-void display(unsigned int index)
-{
-       last_display_index = index;
-       currently_displayed_index = index;
-       data = g_ptr_array_index(copies, index);
-       if (!data)
-               return;
-       max_elements = data->process_table->len;
-       update_current_view();
-       update_footer();
-       update_panels();
-       doupdate();
-}
-
-void pause_display()
-{
-       toggle_pause = 1;
-       print_log("Pause");
-       sem_wait(&pause_sem);
-}
-
-void resume_display()
-{
-       toggle_pause = -1;
-       print_log("Resume");
-       sem_post(&pause_sem);
-}
-
-void *handle_keyboard(void *p)
-{
-       int ch;
-       while((ch = getch())) {
-               switch(ch) {
-               /* Move the cursor and scroll */
-               case KEY_DOWN:
-                       if (perf_panel_visible) {
-                               if (perf_line_selected < g_hash_table_size(data->perf_list) - 1)
-                                       perf_line_selected++;
-                               update_perf_panel(perf_line_selected, 0, 0);
-                       } else {
-                               if (selected_line < (max_center_lines - 1) &&
-                                               selected_line < max_elements - 1) {
-                                       selected_line++;
-                                       selected_in_list++;
-                               } else if (selected_in_list < (max_elements - 1)
-                                               && (list_offset < (max_elements - max_center_lines))) {
-                                       selected_in_list++;
-                                       list_offset++;
-                               }
-                               update_current_view();
-                       }
-                       break;
-               case KEY_NPAGE:
-                       if ((selected_line + 10 < max_center_lines - 1) &&
-                                       ((selected_line + 10) < max_elements - 1)) {
-                               selected_line += 10;
-                               selected_in_list += 10;
-                       } else if (max_elements > max_center_lines) {
-                               selected_line = max_center_lines - 1;
-                               if (selected_in_list + 10 < max_elements - 1) {
-                                       selected_in_list += 10;
-                                       list_offset += (selected_in_list - max_center_lines + 1);
-                               }
-                       } else if (selected_line + 10 > max_elements) {
-                               selected_line = max_elements - 1;
-                       }
-                       update_current_view();
-                       break;
-               case KEY_UP:
-                       if (perf_panel_visible) {
-                               if (perf_line_selected > 0)
-                                       perf_line_selected--;
-                               update_perf_panel(perf_line_selected, 0, 0);
-                       } else {
-                               if (selected_line > 0) {
-                                       selected_line--;
-                                       selected_in_list--;
-                               } else if (selected_in_list > 0 && list_offset > 0) {
-                                       selected_in_list--;
-                                       list_offset--;
-                               }
-                               update_current_view();
-                       }
-                       break;
-               case KEY_PPAGE:
-                       if (selected_line - 10 > 0)
-                               selected_line -= 10;
-                       else
-                               selected_line = 0;
-                       update_current_view();
-                       break;
-
-               /* Navigate the history with arrows */
-               case KEY_LEFT:
-                       if (currently_displayed_index > 0) {
-                               currently_displayed_index--;
-                               print_log("Going back in time");
-                       } else {
-                               print_log("Cannot rewind, last data is already displayed");
-                       }
-                       data = g_ptr_array_index(copies, currently_displayed_index);
-                       max_elements = data->process_table->len;
-
-                       /* we force to pause the display when moving in time */
-                       if (toggle_pause < 0)
-                               pause_display();
-
-                       update_current_view();
-                       update_footer();
-                       break;
-               case KEY_RIGHT:
-                       if (currently_displayed_index < last_display_index) {
-                               currently_displayed_index++;
-                               print_log("Going forward in time");
-                               data = g_ptr_array_index(copies, currently_displayed_index);
-                               max_elements = data->process_table->len;
-                               update_current_view();
-                               update_footer();
-                       } else {
-                               print_log("Manually moving forward");
-                               sem_post(&timer);
-                               /* we force to resume the refresh when moving forward */
-                               if (toggle_pause > 0)
-                                       resume_display();
-                       }
-
-                       break;
-               case ' ':
-                       if (perf_panel_visible)
-                               update_perf_panel(perf_line_selected, 1, 0);
-                       break;
-               case 's':
-                       if (perf_panel_visible)
-                               update_perf_panel(perf_line_selected, 0, 1);
-                       break;
-
-               case 13: /* FIXME : KEY_ENTER ?? */
-                       if (current_view == cpu) {
-                               current_view = process_details;
-                       }
-                       update_current_view();
-                       break;
-
-               case KEY_F(1):
-                       toggle_tree *= -1;
-                       current_view = cpu;
-                       update_current_view();
-                       break;
-               case KEY_F(2):
-                       current_view = cpu;
-                       update_current_view();
-                       break;
-               case KEY_F(3):
-                       current_view = perf;
-                       toggle_tree = -1;
-                       update_current_view();
-                       break;
-               case KEY_F(4):
-                       current_view = fileio;
-                       toggle_tree = -1;
-                       update_current_view();
-                       break;
-               case KEY_F(5):
-                       current_view = netio;
-                       toggle_tree = -1;
-                       update_current_view();
-                       break;
-               case KEY_F(6):
-                       current_view = iostream;
-                       toggle_tree = -1;
-                       update_current_view();
-                       break;
-               case KEY_F(10):
-               case 'q':
-                       reset_ncurses();
-                       break;
-               case 't':
-                       toggle_threads *= -1;
-                       update_current_view();
-                       break;
-               case 'p':
-                       if (toggle_pause < 0) {
-                               pause_display();
-                       } else {
-                               resume_display();
-                       }
-                       break;
-               case 'P':
-                       toggle_perf_panel();
-                       break;
-               default:
-                       /*
-                        * commented because it makes the list refresh in different order
-                        * if we sort and there are equal values
-                        if (data)
-                        update_current_view();
-                        */
-                       break;
-               }
-               update_footer();
-       }
-       return NULL;
-}
-
-void init_ncurses()
-{
-       sem_init(&update_display_sem, 0, 1);
-       init_screen();
-
-       header = create_window(7, COLS - 1, 0, 0);
-       center = create_window(LINES - 7 - 7, COLS - 1, 7, 0);
-       status = create_window(MAX_LOG_LINES + 2, COLS - 1, LINES - 7, 0);
-       footer = create_window(1, COLS - 1, LINES - 1, 0);
-
-       print_log("Starting display");
-
-       main_panel = new_panel(center);
-       setup_perf_panel();
-
-       current_view = cpu;
-
-       basic_header();
-       update_footer();
-
-       pthread_create(&keyboard_thread, NULL, handle_keyboard, (void *)NULL);
-}
-
diff --git a/lttngtop/cursesdisplay.h b/lttngtop/cursesdisplay.h
deleted file mode 100644 (file)
index 6a54252..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2011 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
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#ifndef CURSESDISPLAY_H
-#define CURSESDISPLAY_H
-
-#include <glib.h>
-#include <ncurses.h>
-#include "common.h"
-
-enum current_view_list
-{
-       cpu = 1,
-       perf,
-       process_details,
-       fileio,
-       netio,
-       iostream,
-       tree,
-} current_view;
-
-void display(unsigned int);
-void init_ncurses();
-void reset_ncurses();
-
-#endif // CURSESDISPLAY_H
diff --git a/lttngtop/iostreamtop.c b/lttngtop/iostreamtop.c
deleted file mode 100644 (file)
index 1594df7..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2011 Mathieu Bain <mathieu.bain@polymtl.ca>
- *
- * 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
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#include <babeltrace/babeltrace.h>
-
-#include "lttngtoptypes.h"
-#include "common.h"
-#include "iostreamtop.h"
-
-#include <stdlib.h>
-
-int update_iostream_ret(struct lttngtop *ctx, int tid, char *comm,
-               unsigned long timestamp, int cpu_id, int ret)
-{
-       struct processtop *tmp;
-       int err = 0;
-
-       tmp = get_proc(ctx, tid, comm, timestamp);
-       if ((tmp->iostream->syscall_info != NULL) && (tmp->iostream->syscall_info->cpu_id == cpu_id)) {
-               if (tmp->iostream->syscall_info->type == __NR_read && ret > 0) {
-                       tmp->iostream->ret_read += ret;
-                       tmp->iostream->ret_total += ret;
-               } else if(tmp->iostream->syscall_info->type == __NR_write && ret > 0) {
-                       tmp->iostream->ret_write += ret;
-                       tmp->iostream->ret_total += ret;
-               } else{
-                       err = -1;
-               }
-               free(tmp->iostream->syscall_info);
-               tmp->iostream->syscall_info = NULL;
-       }
-
-       return err;
-}
-
-enum bt_cb_ret handle_exit_syscall(struct bt_ctf_event *call_data,
-               void *private_data)
-{
-       struct definition *scope;
-       unsigned long timestamp;
-       char *comm;
-       uint64_t ret, tid;
-       int64_t cpu_id;
-
-       timestamp = bt_ctf_get_timestamp(call_data);
-       if (timestamp == -1ULL)
-               goto error;
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_STREAM_EVENT_CONTEXT);
-       comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
-                               scope, "_procname"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing procname context info\n");
-               goto error;
-       }
-
-       tid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
-                               scope, "_tid"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing tid context info\n");
-               goto error;
-       }
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_EVENT_FIELDS);
-       ret = bt_ctf_get_int64(bt_ctf_get_field(call_data,
-                               scope, "_ret"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing ret context info\n");
-               goto error;
-       }
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_STREAM_PACKET_CONTEXT);
-       cpu_id = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
-                               scope, "cpu_id"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing cpu_id context info\n");
-               goto error;
-       }
-
-       /*
-        * if we encounter an exit_syscall and it is not for a syscall read or write
-        * we just abort the execution of this callback
-        */
-       if ((update_iostream_ret(&lttngtop, tid, comm, timestamp, cpu_id, ret)) < 0)
-               return BT_CB_ERROR_CONTINUE;
-
-       return BT_CB_OK;
-
-error:
-       return BT_CB_ERROR_STOP;
-}
-
-
-enum bt_cb_ret handle_sys_write(struct bt_ctf_event *call_data,
-               void *private_data)
-{
-       struct definition *scope;
-       struct processtop *tmp;
-       struct syscalls *syscall_info;
-       unsigned long timestamp;
-       uint64_t cpu_id;
-       char *comm;
-       int64_t tid;
-
-       timestamp = bt_ctf_get_timestamp(call_data);
-       if (timestamp == -1ULL)
-               goto error;
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_STREAM_EVENT_CONTEXT);
-       comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
-                               scope, "_procname"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing procname context info\n");
-               goto error;
-       }
-
-       tid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
-                               scope, "_tid"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing tid context info\n");
-               goto error;
-       }
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_STREAM_PACKET_CONTEXT);
-       cpu_id = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
-                               scope, "cpu_id"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing cpu_id context info\n");
-               goto error;
-       }
-
-       syscall_info = malloc(sizeof(struct syscalls));
-       syscall_info->cpu_id = cpu_id;
-       syscall_info->type = __NR_write;
-       syscall_info->tid =  tid;
-       tmp = get_proc(&lttngtop, tid, comm, timestamp);
-       tmp->iostream->syscall_info = syscall_info;
-
-       return BT_CB_OK;
-
-error:
-       return BT_CB_ERROR_STOP;
-}
-
-enum bt_cb_ret handle_sys_read(struct bt_ctf_event *call_data,
-               void *private_data)
-{
-       struct processtop *tmp;
-       struct definition *scope;
-       struct syscalls * syscall_info;
-       unsigned long timestamp;
-       uint64_t cpu_id;
-       char *comm;
-       int64_t tid;
-
-       timestamp = bt_ctf_get_timestamp(call_data);
-       if (timestamp == -1ULL)
-               goto error;
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_STREAM_EVENT_CONTEXT);
-       comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
-                               scope, "_procname"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing procname context info\n");
-               goto error;
-       }
-
-       tid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
-                               scope, "_tid"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing tid context info\n");
-               goto error;
-       }
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_STREAM_PACKET_CONTEXT);
-       cpu_id = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
-                               scope, "cpu_id"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing cpu_id context info\n");
-               goto error;
-       }
-
-       syscall_info = malloc(sizeof(struct syscalls));
-       syscall_info->cpu_id = cpu_id;
-       syscall_info->type = __NR_read;
-       syscall_info->tid =  tid;
-       tmp = get_proc(&lttngtop, tid, comm, timestamp);
-       tmp->iostream->syscall_info = syscall_info;
-
-       return BT_CB_OK;
-
-error:
-       return BT_CB_ERROR_STOP;
-}
-
diff --git a/lttngtop/iostreamtop.h b/lttngtop/iostreamtop.h
deleted file mode 100644 (file)
index bde4dbf..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2011 Mathieu Bain <mathieu.bain@polymtl.ca>
- *
- * 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
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#ifndef _IOSTREANTOP_H
-#define _IOSTREAMTOP_H
-
-#include <babeltrace/babeltrace.h>
-#include <inttypes.h>
-#include <glib.h>
-#include <asm/unistd.h>
-
-/*
-#define SYS_READ  1
-#define SYS_WRITE 2
-*/
-
-enum bt_cb_ret handle_exit_syscall(struct bt_ctf_event *call_data,
-               void *private_data);
-
-enum bt_cb_ret handle_sys_write(struct bt_ctf_event *call_data,
-               void *private_data);
-
-enum bt_cb_ret handle_sys_read(struct bt_ctf_event *call_data,
-               void *private_data);
-
-#endif /* _IOSTREAMTOP_H */
diff --git a/lttngtop/lttngtop.c b/lttngtop/lttngtop.c
deleted file mode 100644 (file)
index 5d526f3..0000000
+++ /dev/null
@@ -1,572 +0,0 @@
-/*
- * Copyright (C) 2011 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
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#define _GNU_SOURCE
-#include <config.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <babeltrace/babeltrace.h>
-#include <babeltrace/ctf/events.h>
-#include <babeltrace/ctf/callbacks.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <popt.h>
-#include <stdlib.h>
-#include <ftw.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <fts.h>
-
-#include "lttngtoptypes.h"
-#include "cputop.h"
-#include "iostreamtop.h"
-#include "cursesdisplay.h"
-#include "common.h"
-
-#define DEFAULT_FILE_ARRAY_SIZE 1
-
-const char *opt_input_path;
-
-struct lttngtop *copy;
-pthread_t display_thread;
-pthread_t timer_thread;
-
-unsigned long refresh_display = 1 * NSEC_PER_SEC;
-unsigned long last_display_update = 0;
-int quit = 0;
-
-enum {
-       OPT_NONE = 0,
-       OPT_HELP,
-       OPT_LIST,
-       OPT_VERBOSE,
-       OPT_DEBUG,
-       OPT_NAMES,
-};
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
-       { NULL, 0, 0, NULL, 0, NULL, NULL },
-};
-
-void *refresh_thread(void *p)
-{
-       while (1) {
-               sem_wait(&pause_sem);
-               sem_post(&pause_sem);
-               sem_post(&timer);
-               sleep(refresh_display/NSEC_PER_SEC);
-       }
-}
-
-void *ncurses_display(void *p)
-{
-       unsigned int current_display_index = 0;
-
-       sem_wait(&bootstrap);
-       init_ncurses();
-
-       while (1) {
-               sem_wait(&timer);
-               sem_wait(&goodtodisplay);
-               sem_wait(&pause_sem);
-
-               copy = g_ptr_array_index(copies, current_display_index);
-               if (copy)
-                       display(current_display_index++);
-
-               sem_post(&goodtoupdate);
-               sem_post(&pause_sem);
-
-               if (quit) {
-                       reset_ncurses();
-                       pthread_exit(0);
-               }
-       }
-}
-
-/*
- * hook on each event to check the timestamp and refresh the display if
- * necessary
- */
-enum bt_cb_ret check_timestamp(struct bt_ctf_event *call_data, void *private_data)
-{
-       unsigned long timestamp;
-
-       timestamp = bt_ctf_get_timestamp(call_data);
-       if (timestamp == -1ULL)
-               goto error;
-
-       if (last_display_update == 0)
-               last_display_update = timestamp;
-
-       if (timestamp - last_display_update >= refresh_display) {
-               sem_wait(&goodtoupdate);
-               g_ptr_array_add(copies, get_copy_lttngtop(last_display_update,
-                                       timestamp));
-               sem_post(&goodtodisplay);
-               sem_post(&bootstrap);
-               last_display_update = timestamp;
-       }
-       return BT_CB_OK;
-
-error:
-       fprintf(stderr, "check_timestamp callback error\n");
-       return BT_CB_ERROR_STOP;
-}
-
-/*
- * get_perf_counter : get or create and return a perf_counter struct for
- * either a process or a cpu (only one of the 2 parameters mandatory)
- */
-struct perfcounter *get_perf_counter(const char *name, struct processtop *proc,
-               struct cputime *cpu)
-{
-       struct perfcounter *ret, *global;
-       GHashTable *table;
-
-       if (proc)
-               table = proc->perf;
-       else if (cpu)
-               table = cpu->perf;
-       else
-               goto error;
-
-       ret = g_hash_table_lookup(table, (gpointer) name);
-       if (ret)
-               goto end;
-
-       ret = malloc(sizeof(struct perfcounter));
-       memset(ret, 0, sizeof(struct perfcounter));
-       /* by default, make it visible in the UI */
-       ret->visible = 1;
-       g_hash_table_insert(table, (gpointer) name, ret);
-
-       global = g_hash_table_lookup(lttngtop.perf_list, (gpointer) name);
-       if (!global) {
-               global = malloc(sizeof(struct perfcounter));
-               memset(global, 0, sizeof(struct perfcounter));
-               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) name, global);
-       }
-
-end:
-       return ret;
-
-error:
-       return NULL;
-}
-
-void update_perf_value(struct processtop *proc, struct cputime *cpu,
-               const char *name, int value)
-{
-       struct perfcounter *cpu_perf, *process_perf;
-
-       cpu_perf = get_perf_counter(name, NULL, cpu);
-       if (cpu_perf->count < value) {
-               process_perf = get_perf_counter(name, proc, NULL);
-               process_perf->count += value - cpu_perf->count;
-               cpu_perf->count = value;
-       }
-}
-
-void extract_perf_counter_scope(struct bt_ctf_event *event,
-               struct definition *scope,
-               struct processtop *proc,
-               struct cputime *cpu)
-{
-       struct definition const * const *list = NULL;
-       unsigned int count;
-       int i, ret;
-
-       if (!scope)
-               goto end;
-
-       ret = bt_ctf_get_field_list(event, scope, &list, &count);
-       if (ret < 0)
-               goto end;
-
-       for (i = 0; i < count; i++) {
-               const char *name = bt_ctf_field_name(list[i]);
-               if (strncmp(name, "_perf_", 6) == 0) {
-                       int value = bt_ctf_get_uint64(list[i]);
-                       if (bt_ctf_field_get_error())
-                               continue;
-                       update_perf_value(proc, cpu, name, value);
-               }
-       }
-
-end:
-       return;
-}
-
-void update_perf_counter(struct processtop *proc, struct bt_ctf_event *event)
-{
-       struct definition *scope;
-       uint64_t cpu_id;
-       struct cputime *cpu;
-
-       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_PACKET_CONTEXT);
-       cpu_id = bt_ctf_get_uint64(bt_ctf_get_field(event, scope, "cpu_id"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "[error] get cpu_id\n");
-               goto end;
-       }
-       cpu = get_cpu(cpu_id);
-
-       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT);
-       extract_perf_counter_scope(event, scope, proc, cpu);
-
-       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_PACKET_CONTEXT);
-       extract_perf_counter_scope(event, scope, proc, cpu);
-
-       scope = bt_ctf_get_top_level_scope(event, BT_EVENT_CONTEXT);
-       extract_perf_counter_scope(event, scope, proc, cpu);
-
-end:
-       return;
-}
-
-enum bt_cb_ret fix_process_table(struct bt_ctf_event *call_data,
-               void *private_data)
-{
-       int pid, tid, ppid;
-       char *comm;
-       struct processtop *parent, *child;
-       struct definition *scope;
-       unsigned long timestamp;
-
-       /* FIXME : check context pid, tid, ppid and comm */
-
-       timestamp = bt_ctf_get_timestamp(call_data);
-       if (timestamp == -1ULL)
-               goto error;
-
-       scope = bt_ctf_get_top_level_scope(call_data, BT_STREAM_EVENT_CONTEXT);
-
-       pid = bt_ctf_get_int64(bt_ctf_get_field(call_data, scope, "_pid"));
-       if (bt_ctf_field_get_error()) {
-//             fprintf(stderr, "Missing pid context info\n");
-               goto error;
-       }
-       tid = bt_ctf_get_int64(bt_ctf_get_field(call_data, scope, "_tid"));
-       if (bt_ctf_field_get_error()) {
-//             fprintf(stderr, "Missing tid context info\n");
-               goto error;
-       }
-       ppid = bt_ctf_get_int64(bt_ctf_get_field(call_data, scope, "_ppid"));
-       if (bt_ctf_field_get_error()) {
-//             fprintf(stderr, "Missing ppid context info\n");
-               goto error;
-       }
-       comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data, scope, "_procname"));
-       if (bt_ctf_field_get_error()) {
-//             fprintf(stderr, "Missing procname context info\n");
-               goto error;
-       }
-
-       /* find or create the current process */
-       child = find_process_tid(&lttngtop, tid, comm);
-       if (!child)
-               child = add_proc(&lttngtop, tid, comm, timestamp);
-       update_proc(child, pid, tid, ppid, comm);
-
-       if (pid != tid) {
-               /* find or create the parent */
-               parent = find_process_tid(&lttngtop, pid, comm);
-               if (!parent) {
-                       parent = add_proc(&lttngtop, pid, comm, timestamp);
-                       parent->pid = pid;
-               }
-
-               /* attach the parent to the current process */
-               child->threadparent = parent;
-               add_thread(parent, child);
-       }
-
-       update_perf_counter(child, call_data);
-
-       return BT_CB_OK;
-
-error:
-       return BT_CB_ERROR_STOP;
-}
-
-void init_lttngtop()
-{
-       copies = g_ptr_array_new();
-       lttngtop.perf_list = g_hash_table_new(g_direct_hash, g_direct_equal);
-
-       sem_init(&goodtodisplay, 0, 0);
-       sem_init(&goodtoupdate, 0, 1);
-       sem_init(&timer, 0, 1);
-       sem_init(&bootstrap, 0, 0);
-       sem_init(&pause_sem, 0, 1);
-       sem_init(&end_trace_sem, 0, 0);
-
-       lttngtop.process_table = g_ptr_array_new();
-       lttngtop.files_table = g_ptr_array_new();
-       lttngtop.cpu_table = g_ptr_array_new();
-}
-
-void usage(FILE *fd)
-{
-
-}
-
-/*
- * Return 0 if caller should continue, < 0 if caller should return
- * error, > 0 if caller should exit without reporting error.
- */
-static int parse_options(int argc, char **argv)
-{
-       poptContext pc;
-       int opt, ret = 0;
-
-       if (argc == 1) {
-               usage(stdout);
-               return 1;   /* exit cleanly */
-       }
-
-       pc = poptGetContext(NULL, argc, (const char **) argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-                       case OPT_HELP:
-                               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;
-               }
-       }
-
-       opt_input_path = poptGetArg(pc);
-       if (!opt_input_path) {
-               ret = -EINVAL;
-               goto end;
-       }
-end:
-       if (pc) {
-               poptFreeContext(pc);
-       }
-       return ret;
-}
-
-void iter_trace(struct bt_context *bt_ctx)
-{
-       struct bt_ctf_iter *iter;
-       struct bt_iter_pos begin_pos;
-       struct bt_ctf_event *event;
-       int ret = 0;
-
-       begin_pos.type = BT_SEEK_BEGIN;
-       iter = bt_ctf_iter_create(bt_ctx, &begin_pos, NULL);
-
-       /* at each event check if we need to refresh */
-       bt_ctf_iter_add_callback(iter, 0, NULL, 0,
-                       check_timestamp,
-                       NULL, NULL, NULL);
-       /* at each event, verify the status of the process table */
-       bt_ctf_iter_add_callback(iter, 0, NULL, 0,
-                       fix_process_table,
-                       NULL, NULL, NULL);
-       /* to handle the scheduling events */
-       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);
-
-       /* for IO top */
-       bt_ctf_iter_add_callback(iter,
-                       g_quark_from_static_string("exit_syscall"),
-                       NULL, 0, handle_exit_syscall, NULL, NULL, NULL);
-       bt_ctf_iter_add_callback(iter,
-                       g_quark_from_static_string("sys_write"),
-                       NULL, 0, handle_sys_write, NULL, NULL, NULL);
-       bt_ctf_iter_add_callback(iter,
-                       g_quark_from_static_string("sys_read"),
-                       NULL, 0, handle_sys_read, NULL, NULL, NULL);
-       while ((event = bt_ctf_iter_read_event(iter)) != NULL) {
-               ret = bt_iter_next(bt_ctf_get_iter(iter));
-               if (ret < 0)
-                       goto end_iter;
-       }
-
-       /* block until quit, we reached the end of the trace */
-       sem_wait(&end_trace_sem);
-
-end_iter:
-       bt_iter_destroy(bt_ctf_get_iter(iter));
-}
-
-/*
- * bt_context_add_traces_recursive: Open a trace recursively
- * (copied from BSD code in converter/babeltrace.c)
- *
- * Find each trace present in the subdirectory starting from the given
- * path, and add them to the context. The packet_seek parameter can be
- * NULL: this specify to use the default format packet_seek.
- *
- * Return: 0 on success, nonzero on failure.
- * Unable to open toplevel: failure.
- * Unable to open some subdirectory or file: warn and continue;
- */
-int bt_context_add_traces_recursive(struct bt_context *ctx, const char *path,
-               const char *format_str,
-               void (*packet_seek)(struct stream_pos *pos,
-                       size_t offset, int whence))
-{
-       FTS *tree;
-       FTSENT *node;
-       GArray *trace_ids;
-       char lpath[PATH_MAX];
-       char * const paths[2] = { lpath, NULL };
-       int ret;
-
-       /*
-        * Need to copy path, because fts_open can change it.
-        * It is the pointer array, not the strings, that are constant.
-        */
-       strncpy(lpath, path, PATH_MAX);
-       lpath[PATH_MAX - 1] = '\0';
-
-       tree = fts_open(paths, FTS_NOCHDIR | FTS_LOGICAL, 0);
-       if (tree == NULL) {
-               fprintf(stderr, "[error] [Context] Cannot traverse \"%s\" for reading.\n",
-                               path);
-               return -EINVAL;
-       }
-
-       trace_ids = g_array_new(FALSE, TRUE, sizeof(int));
-
-       while ((node = fts_read(tree))) {
-               int dirfd, metafd;
-
-               if (!(node->fts_info & FTS_D))
-                       continue;
-
-               dirfd = open(node->fts_accpath, 0);
-               if (dirfd < 0) {
-                       fprintf(stderr, "[error] [Context] Unable to open trace "
-                               "directory file descriptor.\n");
-                       ret = dirfd;
-                       goto error;
-               }
-               metafd = openat(dirfd, "metadata", O_RDONLY);
-               if (metafd < 0) {
-                       ret = close(dirfd);
-                       if (ret < 0) {
-                               perror("close");
-                               goto error;
-                       }
-               } else {
-                       int trace_id;
-
-                       ret = close(metafd);
-                       if (ret < 0) {
-                               perror("close");
-                               goto error;
-                       }
-                       ret = close(dirfd);
-                       if (ret < 0) {
-                               perror("close");
-                               goto error;
-                       }
-
-                       trace_id = bt_context_add_trace(ctx,
-                               node->fts_accpath, format_str,
-                               packet_seek, NULL, NULL);
-                       if (trace_id < 0) {
-                               fprintf(stderr, "[error] [Context] opening trace \"%s\" from %s "
-                                       "for reading.\n", node->fts_accpath, path);
-                               ret = trace_id;
-                               goto error;
-                       }
-                       g_array_append_val(trace_ids, trace_id);
-               }
-       }
-
-       g_array_free(trace_ids, TRUE);
-       return 0;
-
-error:
-       return ret;
-}
-
-int main(int argc, char **argv)
-{
-       int ret;
-       struct bt_context *bt_ctx = NULL;
-
-       ret = parse_options(argc, argv);
-       if (ret < 0) {
-               fprintf(stdout, "Error parsing options.\n\n");
-               usage(stdout);
-               exit(EXIT_FAILURE);
-       } else if (ret > 0) {
-               exit(EXIT_SUCCESS);
-       }
-
-       init_lttngtop();
-
-       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");
-               goto end;
-       }
-
-       pthread_create(&display_thread, NULL, ncurses_display, (void *) NULL);
-       pthread_create(&timer_thread, NULL, refresh_thread, (void *) NULL);
-
-       iter_trace(bt_ctx);
-
-       quit = 1;
-       pthread_join(display_thread, NULL);
-
-end:
-       return 0;
-}
diff --git a/lttngtop/lttngtoptypes.h b/lttngtop/lttngtoptypes.h
deleted file mode 100644 (file)
index f10a684..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2011 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
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#ifndef LTTNGTOPTYPES_H
-#define LTTNGTOPTYPES_H
-
-#include <glib.h>
-
-struct lttngtop {
-       GPtrArray *process_table;       /* struct processtop */
-       GPtrArray *files_table;         /* struct files */
-       GPtrArray *cpu_table;           /* struct cputime */
-       GHashTable *perf_list;          /* struct perfcounter */
-       unsigned long start;
-       unsigned long end;
-       unsigned int nbproc;
-       unsigned int nbnewproc;
-       unsigned int nbdeadproc;
-       unsigned int nbthreads;
-       unsigned int nbnewthreads;
-       unsigned int nbdeadthreads;
-       unsigned int nbfiles;
-       unsigned int nbnewfiles;
-       unsigned int nbclosedfiles;
-} lttngtop;
-
-struct processtop {
-       unsigned int puuid;
-       int pid;
-       char *comm;
-       int tid;
-       int ppid;
-       int oldpid;
-       int oldtid;
-       int oldppid;
-       unsigned long birth;
-       unsigned long death;
-       unsigned long lastactivity;
-       GPtrArray *process_files_table;
-       GPtrArray *threads;
-       GHashTable *perf;
-       struct processtop *threadparent;
-       unsigned long totalfileread;
-       unsigned long totalfilewrite;
-       unsigned long totalcpunsec;
-       unsigned long threadstotalcpunsec;
-       /* IO speed for this process */
-       struct iostream *iostream;
-};
-
-struct perfcounter
-{
-       unsigned long count;
-       int visible;
-       int sort;
-};
-
-struct cputime {
-       guint id;
-       struct processtop *current_task;
-       unsigned long task_start;
-       GHashTable *perf;
-};
-
-/*
- * used for "relative seeks" (with fd, for example fs.lseek)
- * and for "absolute seeks" (events occuring on a device without
- * any link to a particular process)
- */
-struct seeks {
-       unsigned long offset;
-       unsigned long count;
-};
-
-struct ioctls {
-       unsigned int command;
-       unsigned long count;
-};
-
-struct files {
-       struct processtop *ref;
-       unsigned int fuuid;
-       int fd;
-       char *name;
-       int oldfd;
-       int device;
-       int openmode;
-       unsigned long openedat;
-       unsigned long closedat;
-       unsigned long lastaccess;
-       unsigned long read;
-       unsigned long write;
-       unsigned long nbpoll;
-       unsigned long nbselect;
-       unsigned long nbopen;
-       unsigned long nbclose;
-       //struct *seeks; /* relative seeks inside the file */
-       //struct *ioctls;
-       /* XXX : average wait time */
-};
-
-struct sockets {
-       int fd;
-       int parent_fd;  /* on accept a new fd is created from the bound socket */
-       int family;
-       int type;
-       int protocol;
-       int sock_address;
-       unsigned long openedat;
-       unsigned long closedat;
-       unsigned long bind_address;
-       unsigned long remote_address;
-       //struct *sock_options;
-};
-
-struct sock_options {
-       int name;
-       int value;
-};
-
-struct vmas {
-       unsigned long start;
-       unsigned long end;
-       unsigned long flags;
-       unsigned long prot;
-       char *description; /* filename or description if possible (stack, heap) */
-       unsigned long page_faults;
-};
-
-struct syscalls {
-       unsigned int id;
-       unsigned long count;
-        unsigned int cpu_id;
-        unsigned int type;
-        unsigned int tid;
-};
-
-struct signals {
-       int dest_pid;
-       int id;
-       unsigned long count;
-};
-
-struct iostream {
-        struct syscalls *syscall_info; /* NULL if there is no waiting for an exit_syscall */
-        unsigned long ret_read;        /* value returned by an I/O syscall_exit for a sys_read*/
-        unsigned long ret_write;       /* value returned by an I/O syscall_exit for a sys_write*/
-        unsigned long ret_total;
-};
-
-#endif /* LTTNGTOPTYPES_H */
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..5d6ca3e
--- /dev/null
@@ -0,0 +1,12 @@
+AM_CFLAGS = $(PACKAGE_CFLAGS)
+
+bin_PROGRAMS = lttngtop
+
+lttngtop_SOURCES = \
+       lttngtop.c \
+       common.c \
+       cursesdisplay.c \
+       cputop.c \
+       iostreamtop.c
+
+lttngtop_LDADD = -lbabeltrace -lctf
diff --git a/src/common.c b/src/common.c
new file mode 100644 (file)
index 0000000..2a0f1f4
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2011 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "common.h"
+
+struct processtop *find_process_tid(struct lttngtop *ctx, int tid, char *comm)
+{
+       gint i;
+       struct processtop *tmp;
+
+       for (i = 0; i < ctx->process_table->len; i++) {
+               tmp = g_ptr_array_index(ctx->process_table, i);
+               if (tmp && tmp->tid == tid)
+                       return tmp;
+       }
+       return NULL;
+}
+
+struct processtop* add_proc(struct lttngtop *ctx, int tid, char *comm,
+               unsigned long timestamp)
+{
+       struct processtop *newproc;
+
+       /* if the PID already exists, we just rename the process */
+       /* FIXME : need to integrate with clone/fork/exit to be accurate */
+       newproc = find_process_tid(ctx, tid, comm);
+       if (!newproc) {
+               newproc = malloc(sizeof(struct processtop));
+               memset(newproc, 0, sizeof(struct processtop));
+               newproc->tid = tid;
+               newproc->birth = timestamp;
+               newproc->process_files_table = g_ptr_array_new();
+               newproc->threads = g_ptr_array_new();
+               newproc->perf = g_hash_table_new(g_direct_hash, g_direct_equal);
+               newproc->iostream = malloc(sizeof(struct iostream));
+               newproc->iostream->ret_read = 0;
+               newproc->iostream->ret_write = 0;
+               newproc->iostream->ret_total = 0;
+               newproc->iostream->syscall_info = NULL;
+               g_ptr_array_add(ctx->process_table, newproc);
+       }
+       newproc->comm = strdup(comm);
+
+       return newproc;
+}
+
+struct processtop* update_proc(struct processtop* proc, int pid, int tid,
+               int ppid, char *comm)
+{
+       if (proc) {
+               proc->pid = pid;
+               proc->tid = tid;
+               proc->ppid = ppid;
+               if (strcmp(proc->comm, comm) != 0) {
+                       free(proc->comm);
+                       proc->comm = strdup(comm);
+               }
+       }
+       return proc;
+}
+
+/*
+ * This function just sets the time of death of a process.
+ * When we rotate the cputime we remove it from the process list.
+ */
+void death_proc(struct lttngtop *ctx, int tid, char *comm,
+               unsigned long timestamp)
+{
+       struct processtop *tmp;
+       tmp = find_process_tid(ctx, tid, comm);
+       if (tmp && strcmp(tmp->comm, comm) == 0)
+               tmp->death = timestamp;
+}
+
+struct processtop* get_proc(struct lttngtop *ctx, int tid, char *comm,
+               unsigned long timestamp)
+{
+       struct processtop *tmp;
+       tmp = find_process_tid(ctx, tid, comm);
+       if (tmp && strcmp(tmp->comm, comm) == 0)
+               return tmp;
+       return add_proc(ctx, tid, comm, timestamp);
+}
+
+void add_thread(struct processtop *parent, struct processtop *thread)
+{
+       gint i;
+       struct processtop *tmp;
+
+       for (i = 0; i < parent->threads->len; i++) {
+               tmp = g_ptr_array_index(parent->threads, i);
+               if (tmp == thread)
+                       return;
+       }
+       g_ptr_array_add(parent->threads, thread);
+}
+
+struct cputime* add_cpu(int cpu)
+{
+       struct cputime *newcpu;
+
+       newcpu = malloc(sizeof(struct cputime));
+       newcpu->id = cpu;
+       newcpu->current_task = NULL;
+       newcpu->perf = g_hash_table_new(g_direct_hash, g_direct_equal);
+
+       g_ptr_array_add(lttngtop.cpu_table, newcpu);
+
+       return newcpu;
+}
+struct cputime* get_cpu(int cpu)
+{
+       gint i;
+       struct cputime *tmp;
+
+       for (i = 0; i < lttngtop.cpu_table->len; i++) {
+               tmp = g_ptr_array_index(lttngtop.cpu_table, i);
+               if (tmp->id == cpu)
+                       return tmp;
+       }
+
+       return add_cpu(cpu);
+}
+
+/*
+ * At the end of a sampling period, we need to display the cpu time for each
+ * process and to reset it to zero for the next period
+ */
+void rotate_cputime(unsigned long end)
+{
+       gint i;
+       struct cputime *tmp;
+       unsigned long elapsed;
+
+       for (i = 0; i < lttngtop.cpu_table->len; i++) {
+               tmp = g_ptr_array_index(lttngtop.cpu_table, i);
+               elapsed = end - tmp->task_start;
+               if (tmp->current_task) {
+                       tmp->current_task->totalcpunsec += elapsed;
+                       tmp->current_task->threadstotalcpunsec += elapsed;
+                       if (tmp->current_task->pid != tmp->current_task->tid &&
+                                       tmp->current_task->threadparent) {
+                               tmp->current_task->threadparent->threadstotalcpunsec += elapsed;
+                       }
+               }
+               tmp->task_start = end;
+       }
+}
+
+void reset_perf_counter(gpointer key, gpointer value, gpointer user_data)
+{
+       ((struct perfcounter*) value)->count = 0;
+}
+
+void copy_perf_counter(gpointer key, gpointer value, gpointer new_table)
+{
+       struct perfcounter *newperf;
+       
+       newperf = malloc(sizeof(struct perfcounter));
+       newperf->count = ((struct perfcounter *) value)->count;
+       newperf->visible = ((struct perfcounter *) value)->visible;
+       newperf->sort = ((struct perfcounter *) value)->sort;
+       g_hash_table_insert((GHashTable *) new_table, key, newperf);
+}
+
+void rotate_perfcounter() {
+       int i;
+       struct processtop *tmp;
+       for (i = 0; i < lttngtop.process_table->len; i++) {
+               tmp = g_ptr_array_index(lttngtop.process_table, i);
+               g_hash_table_foreach(tmp->perf, reset_perf_counter, NULL);
+       }
+}
+
+void cleanup_processtop()
+{
+       gint i;
+       struct processtop *tmp;
+
+       for (i = 0; i < lttngtop.process_table->len; i++) {
+               tmp = g_ptr_array_index(lttngtop.process_table, i);
+               tmp->totalcpunsec = 0;
+               tmp->threadstotalcpunsec = 0;
+               tmp->iostream->ret_read = 0;
+               tmp->iostream->ret_write = 0;
+       }
+}
+
+struct lttngtop* get_copy_lttngtop(unsigned long start, unsigned long end)
+{
+       gint i, j;
+       unsigned long time;
+       struct lttngtop *dst;
+       struct processtop *tmp, *tmp2, *new;
+       struct cputime *tmpcpu, *newcpu;
+       struct files *tmpfile, *newfile;
+
+       dst = malloc(sizeof(struct lttngtop));
+       dst = memset(dst, 0, sizeof(struct lttngtop));
+       dst->start = start;
+       dst->end = end;
+       dst->process_table = g_ptr_array_new();
+       dst->files_table = g_ptr_array_new();
+       dst->cpu_table = g_ptr_array_new();
+       dst->perf_list = g_hash_table_new(g_direct_hash, g_direct_equal);
+
+       rotate_cputime(end);
+
+       g_hash_table_foreach(lttngtop.perf_list, copy_perf_counter, dst->perf_list);
+       for (i = 0; i < lttngtop.process_table->len; i++) {
+               tmp = g_ptr_array_index(lttngtop.process_table, i);
+               new = malloc(sizeof(struct processtop));
+
+               memcpy(new, tmp, sizeof(struct processtop));
+               new->threads = g_ptr_array_new();
+               new->comm = strdup(tmp->comm);
+               new->process_files_table = g_ptr_array_new();
+               new->perf = g_hash_table_new(g_direct_hash, g_direct_equal);
+               g_hash_table_foreach(tmp->perf, copy_perf_counter, new->perf);
+
+               new->iostream = malloc(sizeof(struct iostream));
+               memcpy(new->iostream, tmp->iostream, sizeof(struct iostream));
+               /* compute the stream speed */
+               if (end - start != 0)
+               {
+                       time = (end - start)/NSEC_PER_SEC;
+                       new->iostream->ret_read = new->iostream->ret_read/(time);
+                       new->iostream->ret_write = new->iostream->ret_write/(time);
+               }
+
+               for (j = 0; j < tmp->process_files_table->len; j++) {
+                       tmpfile = g_ptr_array_index(tmp->process_files_table, j);
+                       newfile = malloc(sizeof(struct files));
+
+                       memcpy(newfile, tmpfile, sizeof(struct files));
+
+                       newfile->name = strdup(tmpfile->name);
+                       newfile->ref = new;
+
+                       g_ptr_array_add(new->process_files_table, newfile);
+                       g_ptr_array_add(dst->files_table, newfile);
+
+                       /*
+                        * if the process died during the last period, we remove all
+                        * files associated with if after the copy
+                        */
+                       if (tmp->death > 0 && tmp->death < end) {
+                               g_ptr_array_remove(tmp->process_files_table, tmpfile);
+                               free(tmpfile);
+                       }
+               }
+               g_ptr_array_add(dst->process_table, new);
+
+               /*
+                * if the process died during the last period, we remove it from
+                * the current process list after the copy
+                */
+               if (tmp->death > 0 && tmp->death < end) {
+                       g_ptr_array_remove(lttngtop.process_table, tmp);
+                       g_ptr_array_free(tmp->threads, TRUE);
+                       free(tmp->comm);
+                       g_ptr_array_free(tmp->process_files_table, TRUE);
+                       g_hash_table_destroy(tmp->perf);
+                       free(tmp);
+               }
+       }
+       rotate_perfcounter();
+
+       for (i = 0; i < lttngtop.cpu_table->len; i++) {
+               tmpcpu = g_ptr_array_index(lttngtop.cpu_table, i);
+               newcpu = malloc(sizeof(struct cputime));
+               memcpy(newcpu, tmpcpu, sizeof(struct cputime));
+               newcpu->perf = g_hash_table_new(g_direct_hash, g_direct_equal);
+               g_hash_table_foreach(tmpcpu->perf, copy_perf_counter, newcpu->perf);
+               /*
+                * note : we don't care about the current process pointer in the copy
+                * so the reference is invalid after the memcpy
+                */
+               g_ptr_array_add(dst->cpu_table, newcpu);
+       }
+       /* create the threads index if required */
+       for (i = 0; i < dst->process_table->len; i++) {
+               tmp = g_ptr_array_index(dst->process_table, i);
+               if (tmp->pid == tmp->tid) {
+                       for (j = 0; j < dst->process_table->len; j++) {
+                               tmp2 = g_ptr_array_index(dst->process_table, j);
+                               if (tmp2->pid == tmp->pid) {
+                                       tmp2->threadparent = tmp;
+                                       g_ptr_array_add(tmp->threads, tmp2);
+                               }
+                       }
+               }
+       }
+
+       //  update_global_stats(dst);
+       cleanup_processtop();
+
+       return dst;
+}
+
diff --git a/src/common.h b/src/common.h
new file mode 100644 (file)
index 0000000..e81256c
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef _COMMON_H
+#define _COMMON_H
+
+#include <semaphore.h>
+#include <babeltrace/ctf/events.h>
+#include "lttngtoptypes.h"
+#include "cputop.h"
+
+#define NSEC_PER_USEC 1000
+#define NSEC_PER_SEC 1000000000L
+
+sem_t goodtodisplay, goodtoupdate, timer, pause_sem, end_trace_sem, bootstrap;
+
+GPtrArray *copies; /* struct lttngtop */
+pthread_mutex_t perf_list_mutex;
+
+struct lttngtop *data;
+
+struct processtop *find_process_tid(struct lttngtop *ctx, int pid, char *comm);
+struct processtop* add_proc(struct lttngtop *ctx, int pid, char *comm,
+               unsigned long timestamp);
+struct processtop* update_proc(struct processtop* proc, int pid, int tid,
+               int ppid, char *comm);
+void add_thread(struct processtop *parent, struct processtop *thread);
+struct processtop* get_proc(struct lttngtop *ctx, int tid, char *comm,
+               unsigned long timestamp);
+void death_proc(struct lttngtop *ctx, int tid, char *comm,
+               unsigned long timestamp);
+struct cputime* add_cpu(int cpu);
+struct cputime* get_cpu(int cpu);
+struct lttngtop* get_copy_lttngtop(unsigned long start, unsigned long end);
+struct perfcounter *add_perf_counter(GPtrArray *perf, GQuark quark,
+               unsigned long count);
+struct perfcounter *get_perf_counter(const char *name, struct processtop *proc,
+               struct cputime *cpu);
+
+#endif /* _COMMON_H */
diff --git a/src/cputop.c b/src/cputop.c
new file mode 100644 (file)
index 0000000..2ade0db
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2011 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include <babeltrace/babeltrace.h>
+
+#include "lttngtoptypes.h"
+#include "common.h"
+#include "cputop.h"
+
+void update_cputop_data(unsigned long timestamp, int64_t cpu, int prev_pid,
+               int next_pid, char *prev_comm, char *next_comm)
+{
+       struct cputime *tmpcpu;
+       unsigned long elapsed;
+
+       tmpcpu = get_cpu(cpu);
+
+       if (tmpcpu->current_task && tmpcpu->current_task->pid == prev_pid) {
+               elapsed = timestamp - tmpcpu->task_start;
+               tmpcpu->current_task->totalcpunsec += elapsed;
+               tmpcpu->current_task->threadstotalcpunsec += elapsed;
+               if (tmpcpu->current_task->pid != tmpcpu->current_task->tid)
+                       tmpcpu->current_task->threadparent->threadstotalcpunsec += elapsed;
+       }
+
+       if (next_pid != 0)
+               tmpcpu->current_task = get_proc(&lttngtop, next_pid, next_comm, timestamp);
+       else
+               tmpcpu->current_task = NULL;
+
+       tmpcpu->task_start = timestamp;
+}
+
+enum bt_cb_ret handle_sched_switch(struct bt_ctf_event *call_data,
+               void *private_data)
+{
+       struct definition *scope;
+       unsigned long timestamp;
+       uint64_t cpu_id;
+       char *prev_comm, *next_comm;
+       int prev_tid, next_tid;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                       BT_EVENT_FIELDS);
+       prev_comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
+                               scope, "_prev_comm"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing prev_comm context info\n");
+               goto error;
+       }
+
+       next_comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
+                               scope, "_next_comm"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing next_comm context info\n");
+               goto error;
+       }
+
+       prev_tid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
+                               scope, "_prev_tid"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing prev_tid context info\n");
+               goto error;
+       }
+
+       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 context info\n");
+               goto error;
+       }
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                       BT_STREAM_PACKET_CONTEXT);
+       cpu_id = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
+                               scope, "cpu_id"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing cpu_id context info\n");
+               goto error;
+       }
+
+       update_cputop_data(timestamp, cpu_id, prev_tid, next_tid,
+                       prev_comm, next_comm);
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
+
+enum bt_cb_ret handle_sched_process_free(struct bt_ctf_event *call_data,
+               void *private_data)
+{
+       struct definition *scope;
+       unsigned long timestamp;
+       char *comm;
+       int tid;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                       BT_EVENT_FIELDS);
+       comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
+                               scope, "_comm"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing procname context info\n");
+               goto error;
+       }
+
+       tid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
+                               scope, "_tid"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing tid context info\n");
+               goto error;
+       }
+
+       death_proc(&lttngtop, tid, comm, timestamp);
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+
+}
+
diff --git a/src/cputop.h b/src/cputop.h
new file mode 100644 (file)
index 0000000..8b57823
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef _LTTNGTOP_H
+#define _LTTNGTOP_H
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/callbacks.h>
+#include <inttypes.h>
+#include <glib.h>
+
+enum bt_cb_ret handle_sched_switch(struct bt_ctf_event *hook_data,
+               void *call_data);
+
+enum bt_cb_ret handle_sched_process_free(struct bt_ctf_event *call_data,
+               void *private_data);
+
+#endif /* _LTTNGTOP_H */
diff --git a/src/cursesdisplay.c b/src/cursesdisplay.c
new file mode 100644 (file)
index 0000000..0f79485
--- /dev/null
@@ -0,0 +1,1003 @@
+/*
+ * Copyright (C) 2011 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <ncurses.h>
+#include <panel.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#include "cursesdisplay.h"
+#include "lttngtoptypes.h"
+#include "common.h"
+
+#define DEFAULT_DELAY 15
+#define MAX_LINE_LENGTH 50
+#define MAX_LOG_LINES 4
+
+/* to prevent concurrent updates of the different windows */
+sem_t update_display_sem;
+
+char *termtype;
+WINDOW *footer, *header, *center, *status;
+WINDOW *perf_panel_window = NULL;
+PANEL *perf_panel, *main_panel;
+
+int perf_panel_visible = 0;
+int perf_line_selected = 0;
+
+int last_display_index, currently_displayed_index;
+
+struct processtop *selected_process = NULL;
+int selected_tid;
+char *selected_comm;
+int selected_ret;
+
+int selected_line = 0; /* select bar position */
+int selected_in_list = 0; /* selection relative to the whole list */
+int list_offset = 0; /* first index in the list to display (scroll) */
+int nb_log_lines = 0;
+char log_lines[MAX_LINE_LENGTH * MAX_LOG_LINES + MAX_LOG_LINES];
+
+int max_elements = 80;
+
+int toggle_threads = -1;
+int toggle_pause = -1;
+int toggle_tree = -1;
+
+int max_center_lines;
+
+pthread_t keyboard_thread;
+
+void reset_ncurses()
+{
+       curs_set(1);
+       endwin();
+       exit(0);
+}
+
+static void handle_sigterm(int signal)
+{
+       reset_ncurses();
+}
+
+void init_screen()
+{
+       initscr();
+       noecho();
+       halfdelay(DEFAULT_DELAY);
+       nonl();
+       intrflush(stdscr, false);
+       keypad(stdscr, true);
+       curs_set(0);
+
+       if (has_colors()) {
+               start_color();
+               init_pair(1, COLOR_RED, COLOR_BLACK); /* - */
+               init_pair(2, COLOR_GREEN, COLOR_BLACK); /* + */
+               init_pair(3, COLOR_BLACK, COLOR_WHITE); /* keys */
+               init_pair(4, COLOR_WHITE, COLOR_GREEN); /* keys activated */
+               init_pair(5, COLOR_WHITE, COLOR_BLUE); /* select line */
+       }
+       termtype = getenv("TERM");
+       if (!strcmp(termtype, "xterm") ||  !strcmp(termtype, "xterm-color") ||
+                       !strcmp(termtype, "vt220")) {
+               define_key("\033[H", KEY_HOME);
+               define_key("\033[F", KEY_END);
+               define_key("\033OP", KEY_F(1));
+               define_key("\033OQ", KEY_F(2));
+               define_key("\033OR", KEY_F(3));
+               define_key("\033OS", KEY_F(4));
+               define_key("\0330U", KEY_F(6));
+               define_key("\033[11~", KEY_F(1));
+               define_key("\033[12~", KEY_F(2));
+               define_key("\033[13~", KEY_F(3));
+               define_key("\033[14~", KEY_F(4));
+               define_key("\033[16~", KEY_F(6));
+               define_key("\033[17;2~", KEY_F(18));
+       }
+       signal(SIGTERM, handle_sigterm);
+       mousemask(BUTTON1_CLICKED, NULL);
+       refresh();
+}
+
+WINDOW *create_window(int height, int width, int startx, int starty)
+{
+       WINDOW *win;
+       win = newwin(height, width, startx, starty);
+       box(win, 0 , 0);
+       wrefresh(win);
+       return win;
+}
+
+WINDOW *create_window_no_border(int height, int width, int startx, int starty)
+{
+       WINDOW *win;
+       win = newwin(height, width, startx, starty);
+       wrefresh(win);
+       return win;
+}
+
+void print_digit(WINDOW *win, int digit)
+{
+       if (digit < 0) {
+               wattron(win, COLOR_PAIR(1));
+               wprintw(win, "%d", digit);
+               wattroff(win, COLOR_PAIR(1));
+       } else if (digit > 0) {
+               wattron(win, COLOR_PAIR(2));
+               wprintw(win, "+%d", digit);
+               wattroff(win, COLOR_PAIR(2));
+       } else {
+               wprintw(win, "0");
+       }
+}
+
+void print_digits(WINDOW *win, int first, int second)
+{
+       wprintw(win, "(");
+       print_digit(win, first);
+       wprintw(win, ", ");
+       print_digit(win, second);
+       wprintw(win, ")");
+}
+
+void print_headers(int line, char *desc, int value, int first, int second)
+{
+       wattron(header, A_BOLD);
+       mvwprintw(header, line, 4, "%s", desc);
+       wattroff(header, A_BOLD);
+       mvwprintw(header, line, 16, "N/A", value);
+       wmove(header, line, 24);
+       print_digits(header, first, second);
+       wmove(header, line, 40);
+}
+
+void set_window_title(WINDOW *win, char *title)
+{
+       wattron(win, A_BOLD);
+       mvwprintw(win, 0, 1, title);
+       wattroff(win, A_BOLD);
+}
+
+void print_log(char *str)
+{
+       int i;
+       int current_line = 1;
+       int current_char = 1;
+       char *tmp, *tmp2;
+       /* rotate the line buffer */
+       if (nb_log_lines >= MAX_LOG_LINES) {
+               tmp = strndup(log_lines, MAX_LINE_LENGTH * MAX_LOG_LINES + MAX_LOG_LINES);
+               tmp2 = strchr(tmp, '\n');
+               memset(log_lines, '\0', strlen(log_lines));
+               strncat(log_lines, tmp2 + 1, strlen(tmp2) - 1);
+               log_lines[strlen(log_lines)] = '\n';
+               log_lines[strlen(log_lines)] = '\0';
+               free(tmp);
+       }
+       nb_log_lines++;
+
+       strncat(log_lines, str, MAX_LINE_LENGTH - 1);
+
+       if (nb_log_lines < MAX_LOG_LINES)
+               log_lines[strlen(log_lines)] = '\n';
+       log_lines[strlen(log_lines)] = '\0';
+
+       werase(status);
+       box(status, 0 , 0);
+       set_window_title(status, "Status");
+       for (i = 0; i < strlen(log_lines); i++) {
+               if (log_lines[i] == '\n') {
+                       wmove(status, ++current_line, 1);
+                       current_char = 1;
+               } else {
+                       mvwprintw(status, current_line, current_char++, "%c", log_lines[i]);
+               }
+       }
+       wrefresh(status);
+}
+
+void print_key(WINDOW *win, char *key, char *desc, int toggle)
+{
+       int pair;
+       if (toggle > 0)
+               pair = 4;
+       else
+               pair = 3;
+       wattron(win, COLOR_PAIR(pair));
+       wprintw(footer, "%s", key);
+       wattroff(win, COLOR_PAIR(pair));
+       wprintw(footer, ":%s", desc);
+}
+
+void update_footer()
+{
+       sem_wait(&update_display_sem);
+       werase(footer);
+       wmove(footer, 1, 1);
+       print_key(footer, "F2", "CPUtop  ", current_view == cpu);
+       print_key(footer, "F3", "PerfTop  ", current_view == perf);
+       print_key(footer, "F6", "IOTop  ", current_view == iostream);
+       print_key(footer, "Enter", "Details  ", current_view == process_details);
+       print_key(footer, "q", "Quit | ", 0);
+       print_key(footer, "P", "Perf Pref  ", 0);
+       print_key(footer, "p", "Pause  ", toggle_pause);
+
+       wrefresh(footer);
+       sem_post(&update_display_sem);
+}
+
+void basic_header()
+{
+       werase(header);
+       box(header, 0 , 0);
+       set_window_title(header, "Statistics for interval [gathering data...[");
+       wattron(header, A_BOLD);
+       mvwprintw(header, 1, 4, "CPUs");
+       mvwprintw(header, 2, 4, "Processes");
+       mvwprintw(header, 3, 4, "Threads");
+       mvwprintw(header, 4, 4, "Files");
+       mvwprintw(header, 5, 4, "Network");
+       mvwprintw(header, 6, 4, "IO");
+       wattroff(header, A_BOLD);
+       wrefresh(header);
+}
+
+void update_header()
+{
+       werase(header);
+       box(header, 0 , 0);
+       set_window_title(header, "Statistics for interval ");
+       wattron(header, A_BOLD);
+       /*
+       wprintw(header, "[%lu.%lu, %lu.%lu[",
+                       data->start.tv_sec, data->start.tv_nsec,
+                       data->end.tv_sec, data->end.tv_nsec);
+                       */
+       wprintw(header, "[%lu, %lu[",
+            data->start,
+            data->end);
+       mvwprintw(header, 1, 4, "CPUs");
+       wattroff(header, A_BOLD);
+       wprintw(header, "\t%d\t(max/cpu : %0.2f%)", data->cpu_table->len,
+                       100.0/data->cpu_table->len);
+       print_headers(2, "Processes", data->nbproc, data->nbnewproc,
+                       -1*(data->nbdeadproc));
+       print_headers(3, "Threads", data->nbthreads, data->nbnewthreads,
+                       -1*(data->nbdeadthreads));
+       print_headers(4, "Files", data->nbfiles, data->nbnewfiles,
+                       -1*(data->nbclosedfiles));
+       mvwprintw(header, 4, 43, "N/A kbytes/sec");
+       print_headers(5, "Network", 114, 0, 0);
+       mvwprintw(header, 5, 43, "N/A Mbytes/sec");
+       wrefresh(header);
+}
+
+gint sort_by_cpu_desc(gconstpointer p1, gconstpointer p2)
+{
+       struct processtop *n1 = *(struct processtop **)p1;
+       struct processtop *n2 = *(struct processtop **)p2;
+       unsigned long totaln1 = n1->totalcpunsec;
+       unsigned long totaln2 = n2->totalcpunsec;
+
+       if (totaln1 < totaln2)
+               return 1;
+       if (totaln1 == totaln2)
+               return 0;
+       return -1;
+}
+
+gint sort_by_cpu_group_by_threads_desc(gconstpointer p1, gconstpointer p2)
+{
+       struct processtop *n1 = *(struct processtop **)p1;
+       struct processtop *n2 = *(struct processtop **)p2;
+       unsigned long totaln1 = n1->threadstotalcpunsec;
+       unsigned long totaln2 = n2->threadstotalcpunsec;
+
+       if (totaln1 < totaln2)
+               return 1;
+       if (totaln1 == totaln2)
+               return 0;
+       return -1;
+}
+
+void update_cputop_display()
+{
+       int i;
+       int header_offset = 2;
+       struct processtop *tmp;
+       unsigned long elapsed;
+       double maxcputime;
+       int nblinedisplayed = 0;
+       int current_line = 0;
+
+       elapsed = data->end - data->start;
+       maxcputime = elapsed * data->cpu_table->len / 100.0;
+
+       g_ptr_array_sort(data->process_table, sort_by_cpu_desc);
+
+       set_window_title(center, "CPU Top");
+       wattron(center, A_BOLD);
+       mvwprintw(center, 1, 1, "CPU(%)");
+       mvwprintw(center, 1, 12, "TGID");
+       mvwprintw(center, 1, 22, "PID");
+       mvwprintw(center, 1, 32, "NAME");
+       wattroff(center, A_BOLD);
+
+       max_center_lines = LINES - 7 - 7 - 1 - header_offset;
+
+       /* iterate the process (thread) list */
+       for (i = list_offset; i < data->process_table->len &&
+                       nblinedisplayed < max_center_lines; i++) {
+               tmp = g_ptr_array_index(data->process_table, i);
+
+               if (current_line == selected_line) {
+                       selected_process = tmp;
+                       selected_tid = tmp->tid;
+                       selected_comm = tmp->comm;
+                       wattron(center, COLOR_PAIR(5));
+                       mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
+               }
+               /* CPU(%) */
+               mvwprintw(center, current_line + header_offset, 1, "%1.2f",
+                               tmp->totalcpunsec / maxcputime);
+               /* TGID */
+               mvwprintw(center, current_line + header_offset, 12, "%d", tmp->pid);
+               /* PID */
+               mvwprintw(center, current_line + header_offset, 22, "%d", tmp->tid);
+               /* NAME */
+               mvwprintw(center, current_line + header_offset, 32, "%s", tmp->comm);
+               wattroff(center, COLOR_PAIR(5));
+               nblinedisplayed++;
+               current_line++;
+       }
+}
+
+gint sort_perf(gconstpointer p1, gconstpointer p2, gpointer key)
+{
+       struct processtop *n1 = *(struct processtop **) p1;
+       struct processtop *n2 = *(struct processtop **) p2;
+
+       struct perfcounter *tmp1, *tmp2;
+       unsigned long totaln2 = 0;
+       unsigned long totaln1 = 0;
+
+       if (!key)
+               return 0;
+
+       tmp1 = g_hash_table_lookup(n1->perf, key);
+       if (!tmp1)
+               totaln1 = 0;
+       else
+               totaln1 = tmp1->count;
+
+       tmp2 = g_hash_table_lookup(n2->perf, key);
+       if (!tmp2)
+               totaln2 = 0;
+       else
+               totaln2 = tmp2->count;
+
+       if (totaln1 < totaln2)
+               return 1;
+       if (totaln1 == totaln2) {
+               totaln1 = n1->tid;
+               totaln2 = n2->tid;
+               if (totaln1 < totaln2)
+                       return 1;
+               return -1;
+       }
+       return -1;
+}
+
+void print_key_title(char *key, int line)
+{
+       wattron(center, A_BOLD);
+       mvwprintw(center, line, 1, "%s\t", key);
+       wattroff(center, A_BOLD);
+}
+
+void update_process_details()
+{
+       unsigned long elapsed;
+       double maxcputime;
+       struct processtop *tmp = find_process_tid(data, selected_tid, selected_comm);
+
+       set_window_title(center, "Process details");
+
+
+       elapsed = data->end - data->start;
+       maxcputime = elapsed * data->cpu_table->len / 100.0;
+
+       print_key_title("Name", 1);
+       wprintw(center, "%s", selected_comm);
+       print_key_title("TID", 2);
+       wprintw(center, "%d", selected_tid);
+       if (!tmp) {
+               print_key_title("Does not exit at this time", 3);
+               return;
+       }
+
+       print_key_title("PID", 3);
+       wprintw(center, "%d", tmp->pid);
+       print_key_title("PPID", 4);
+       wprintw(center, "%d", tmp->ppid);
+       print_key_title("CPU", 5);
+       wprintw(center, "%1.2f %%", tmp->totalcpunsec/maxcputime);
+}
+
+void update_perf()
+{
+       int i, j;
+       int nblinedisplayed = 0;
+       int current_line = 0;
+       struct processtop *tmp;
+       int header_offset = 2;
+       int perf_row = 40;
+       struct perfcounter *perfn1, *perfn2;
+       GList *perflist;
+       char *perf_key = NULL;
+       int value;
+
+       set_window_title(center, "Perf Top");
+       wattron(center, A_BOLD);
+       mvwprintw(center, 1, 1, "PID");
+       mvwprintw(center, 1, 11, "TID");
+       mvwprintw(center, 1, 22, "NAME");
+
+       perf_row = 40;
+       perflist = g_list_first(g_hash_table_get_keys(data->perf_list));
+       while (perflist) {
+               perfn1 = g_hash_table_lookup(data->perf_list, perflist->data);
+               /* + 6 to strip the "_perf_" prefix */
+               if (perfn1->visible) {
+                       mvwprintw(center, 1, perf_row, "%s",
+                                       (char *) perflist->data + 6);
+                       perf_row += 20;
+               }
+               if (perfn1->sort) {
+                       perf_key = (char *) perflist->data;
+               }
+               perflist = g_list_next(perflist);
+       }
+       wattroff(center, A_BOLD);
+
+       g_ptr_array_sort_with_data(data->process_table, sort_perf, perf_key);
+       for (i = 0; i < data->process_table->len && 
+                       nblinedisplayed < max_center_lines; i++) {
+               GList *perf_keys;
+               tmp = g_ptr_array_index(data->process_table, i);
+
+               if (current_line == selected_line) {
+                       selected_process = tmp;
+                       wattron(center, COLOR_PAIR(5));
+                       mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
+               }
+
+               mvwprintw(center, current_line + header_offset, 1, "%d", tmp->pid);
+               mvwprintw(center, current_line + header_offset, 11, "%d", tmp->tid);
+               mvwprintw(center, current_line + header_offset, 22, "%s", tmp->comm);
+
+               /* FIXME : sometimes there is a segfault here, I have no idea why :-( */
+               perf_keys = g_hash_table_get_keys(data->perf_list);
+               if (perf_keys)
+                       perflist = g_list_first(perf_keys);
+               else
+                       perflist = NULL;
+
+               perf_row = 40;
+               j = 0;
+               while (perflist) {
+                       j++;
+                       perfn1 = g_hash_table_lookup(data->perf_list, perflist->data);
+                       if (!perfn1) {
+                               perflist = g_list_next(perflist);
+                               continue;
+                       }
+                       if (perfn1->visible) {
+                               perfn2 = g_hash_table_lookup(tmp->perf, perflist->data);
+                               if (perfn2)
+                                       value = perfn2->count;
+                               else
+                                       value = 0;
+                               mvwprintw(center, current_line + header_offset, perf_row, "%d", value);
+                               perf_row += 20;
+                       }
+                       perflist = g_list_next(perflist);
+               }
+
+               wattroff(center, COLOR_PAIR(5));
+               nblinedisplayed++;
+               current_line++;
+       }
+}
+
+void update_fileio()
+{
+       int i;
+       int offset;
+
+       set_window_title(center, "IO Top");
+       wattron(center, A_BOLD);
+       mvwprintw(center, 1, 10, "READ");
+       mvwprintw(center, 2, 1, "bytes");
+       mvwprintw(center, 2, 15, "bytes/sec");
+
+       mvwprintw(center, 1, 39, "WRITE");
+       mvwprintw(center, 2, 33, "bytes");
+       mvwprintw(center, 2, 45, "bytes/sec");
+
+       if (toggle_threads > 0) {
+               mvwprintw(center, 1, 60, "TGID");
+               mvwprintw(center, 1, 70, "PID");
+               offset = 8;
+       } else {
+               mvwprintw(center, 1, 60, "PID(TGID)");
+               offset = 0;
+       }
+       mvwprintw(center, 1, 72 + offset, "NAME");
+       wattroff(center, A_BOLD);
+
+       for (i = 3; i < LINES - 3 - 8 - 1; i++) {
+               mvwprintw(center, i, 1, "%d", i*1000);
+               mvwprintw(center, i, 15, "%dk", i);
+               mvwprintw(center, i, 28, "|    %d", i*2000);
+               mvwprintw(center, i, 45, "%dk", i*2);
+               if (toggle_threads > 0) {
+                       mvwprintw(center, i, 57, "|  %d", i);
+                       mvwprintw(center, i, 70, "%d", i);
+               } else {
+                       mvwprintw(center, i, 57, "|  %d", i);
+               }
+               mvwprintw(center, i, 72 + offset, "process_%d", i);
+       }
+}
+
+gint sort_by_ret_desc(gconstpointer p1, gconstpointer p2)
+{
+       struct processtop *n1 = *(struct processtop **)p1;
+       struct processtop *n2 = *(struct processtop **)p2;
+       unsigned long totaln1 = n1->iostream->ret_total;
+       unsigned long totaln2 = n2->iostream->ret_total;
+
+       if (totaln1 < totaln2)
+               return 1;
+       if (totaln1 == totaln2)
+               return 0;
+       return -1;
+}
+
+void update_iostream()
+{
+       int i;
+       int header_offset = 2;
+       struct processtop *tmp;
+       int nblinedisplayed = 0;
+       int current_line = 0;
+
+       set_window_title(center, "IO Top");
+       wattron(center, A_BOLD);
+       mvwprintw(center, 1, 1, "READ (B/s)");
+       mvwprintw(center, 1, 20, "WRITE (B/s)");
+
+       mvwprintw(center, 1, 40, "TOTAL STREAM");
+
+       mvwprintw(center, 1, 60, "TGID");
+       mvwprintw(center, 1, 80, "PID");
+
+       mvwprintw(center, 1, 92, "NAME");
+       wattroff(center, A_BOLD);
+
+       g_ptr_array_sort(data->process_table, sort_by_ret_desc);
+
+       for (i = list_offset; i < data->process_table->len &&
+                       nblinedisplayed < max_center_lines; i++) {
+               tmp = g_ptr_array_index(data->process_table, i);
+
+               if (current_line == selected_line) {
+                       selected_process = tmp;
+                       selected_tid = tmp->tid;
+                       selected_comm = tmp->comm;
+                       wattron(center, COLOR_PAIR(5));
+                       mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
+               }
+               /* READ (bytes/sec) */
+               mvwprintw(center, current_line + header_offset, 1, "%lu",
+                               tmp->iostream->ret_read);
+
+               /* WRITE (bytes/sec) */
+               mvwprintw(center, current_line + header_offset, 20, "%lu",
+                               tmp->iostream->ret_write);
+
+               /* TOTAL STREAM */
+               if(tmp->iostream->ret_total >= 1000000)
+                       mvwprintw(center, current_line + header_offset, 40, "%lu MB",
+                                       tmp->iostream->ret_total/1000000);
+               else if(tmp->iostream->ret_total >=1000)
+                       mvwprintw(center, current_line + header_offset, 40, "%lu KB",
+                                       tmp->iostream->ret_total/1000);
+               else
+                       mvwprintw(center, current_line + header_offset, 40, "%lu B",
+                                       tmp->iostream->ret_total);
+               /* TGID */
+               mvwprintw(center, current_line + header_offset, 60, "%d", tmp->pid);
+               /* PID */
+               mvwprintw(center, current_line + header_offset, 80, "%d", tmp->tid);
+               /* NAME */
+               mvwprintw(center, current_line + header_offset, 92, "%s", tmp->comm);
+               wattroff(center, COLOR_PAIR(5));
+               nblinedisplayed++;
+               current_line++;
+       }
+}
+
+void update_current_view()
+{
+       sem_wait(&update_display_sem);
+       if (!data)
+               return;
+       update_header();
+
+       werase(center);
+       box(center, 0, 0);
+       switch (current_view) {
+       case cpu:
+               update_cputop_display();
+               break;
+       case perf:
+               update_perf();
+               break;
+       case process_details:
+               update_process_details();
+               break;
+       case fileio:
+               update_fileio();
+               break;
+       case iostream:
+               update_iostream();
+               break;
+       case tree:
+               update_cputop_display();
+               break;
+       default:
+               break;
+       }
+       update_panels();
+       doupdate();
+       sem_post(&update_display_sem);
+}
+
+void setup_perf_panel()
+{
+       int size;
+       if (!data)
+               return;
+       if (perf_panel_window) {
+               del_panel(perf_panel);
+               delwin(perf_panel_window);
+       }
+       size = g_hash_table_size(data->perf_list);
+       perf_panel_window = create_window(size + 2, 30, 10, 10);
+       perf_panel = new_panel(perf_panel_window);
+       perf_panel_visible = 0;
+       hide_panel(perf_panel);
+}
+
+void update_perf_panel(int line_selected, int toggle_view, int toggle_sort)
+{
+       int i;
+       struct perfcounter *perf;
+       GList *perflist;
+
+       if (!data)
+               return;
+
+       werase(perf_panel_window);
+       box(perf_panel_window, 0 , 0);
+       set_window_title(perf_panel_window, "Perf Preferences ");
+       wattron(perf_panel_window, A_BOLD);
+       mvwprintw(perf_panel_window, g_hash_table_size(data->perf_list) + 1, 1, " 's' to sort");
+       wattroff(perf_panel_window, A_BOLD);
+
+       if (toggle_sort == 1) {
+               i = 0;
+               perflist = g_list_first(g_hash_table_get_keys(data->perf_list));
+               while (perflist) {
+                       perf = g_hash_table_lookup(data->perf_list, perflist->data);
+                       if (i != line_selected)
+                               perf->sort = 0;
+                       else
+                               perf->sort = 1;
+                       i++;
+                       perflist = g_list_next(perflist);
+               }
+               update_current_view();
+       }
+
+       i = 0;
+       perflist = g_list_first(g_hash_table_get_keys(data->perf_list));
+       while (perflist) {
+               perf = g_hash_table_lookup(data->perf_list, perflist->data);
+               if (i == line_selected && toggle_view == 1) {
+                       perf->visible = perf->visible == 1 ? 0:1;
+                       update_current_view();
+               }
+               if (i == line_selected) {
+                       wattron(perf_panel_window, COLOR_PAIR(5));
+                       mvwhline(perf_panel_window, i + 1, 1, ' ', 30 - 2);
+               }
+               if (perf->sort == 1)
+                       wattron(perf_panel_window, A_BOLD);
+               mvwprintw(perf_panel_window, i + 1, 1, "[%c] %s",
+                               perf->visible == 1 ? 'x' : ' ',
+                               (char *) perflist->data + 6);
+               wattroff(perf_panel_window, A_BOLD);
+               wattroff(perf_panel_window, COLOR_PAIR(5));
+               i++;
+               perflist = g_list_next(perflist);
+       }
+       update_panels();
+       doupdate();
+}
+
+
+void toggle_perf_panel(void)
+{
+       if (perf_panel_visible) {
+               hide_panel(perf_panel);
+               perf_panel_visible = 0;
+       } else {
+               setup_perf_panel();
+               update_perf_panel(perf_line_selected, 0, 0);
+               show_panel(perf_panel);
+               perf_panel_visible = 1;
+       }
+       update_panels();
+       doupdate();
+}
+
+void display(unsigned int index)
+{
+       last_display_index = index;
+       currently_displayed_index = index;
+       data = g_ptr_array_index(copies, index);
+       if (!data)
+               return;
+       max_elements = data->process_table->len;
+       update_current_view();
+       update_footer();
+       update_panels();
+       doupdate();
+}
+
+void pause_display()
+{
+       toggle_pause = 1;
+       print_log("Pause");
+       sem_wait(&pause_sem);
+}
+
+void resume_display()
+{
+       toggle_pause = -1;
+       print_log("Resume");
+       sem_post(&pause_sem);
+}
+
+void *handle_keyboard(void *p)
+{
+       int ch;
+       while((ch = getch())) {
+               switch(ch) {
+               /* Move the cursor and scroll */
+               case KEY_DOWN:
+                       if (perf_panel_visible) {
+                               if (perf_line_selected < g_hash_table_size(data->perf_list) - 1)
+                                       perf_line_selected++;
+                               update_perf_panel(perf_line_selected, 0, 0);
+                       } else {
+                               if (selected_line < (max_center_lines - 1) &&
+                                               selected_line < max_elements - 1) {
+                                       selected_line++;
+                                       selected_in_list++;
+                               } else if (selected_in_list < (max_elements - 1)
+                                               && (list_offset < (max_elements - max_center_lines))) {
+                                       selected_in_list++;
+                                       list_offset++;
+                               }
+                               update_current_view();
+                       }
+                       break;
+               case KEY_NPAGE:
+                       if ((selected_line + 10 < max_center_lines - 1) &&
+                                       ((selected_line + 10) < max_elements - 1)) {
+                               selected_line += 10;
+                               selected_in_list += 10;
+                       } else if (max_elements > max_center_lines) {
+                               selected_line = max_center_lines - 1;
+                               if (selected_in_list + 10 < max_elements - 1) {
+                                       selected_in_list += 10;
+                                       list_offset += (selected_in_list - max_center_lines + 1);
+                               }
+                       } else if (selected_line + 10 > max_elements) {
+                               selected_line = max_elements - 1;
+                       }
+                       update_current_view();
+                       break;
+               case KEY_UP:
+                       if (perf_panel_visible) {
+                               if (perf_line_selected > 0)
+                                       perf_line_selected--;
+                               update_perf_panel(perf_line_selected, 0, 0);
+                       } else {
+                               if (selected_line > 0) {
+                                       selected_line--;
+                                       selected_in_list--;
+                               } else if (selected_in_list > 0 && list_offset > 0) {
+                                       selected_in_list--;
+                                       list_offset--;
+                               }
+                               update_current_view();
+                       }
+                       break;
+               case KEY_PPAGE:
+                       if (selected_line - 10 > 0)
+                               selected_line -= 10;
+                       else
+                               selected_line = 0;
+                       update_current_view();
+                       break;
+
+               /* Navigate the history with arrows */
+               case KEY_LEFT:
+                       if (currently_displayed_index > 0) {
+                               currently_displayed_index--;
+                               print_log("Going back in time");
+                       } else {
+                               print_log("Cannot rewind, last data is already displayed");
+                       }
+                       data = g_ptr_array_index(copies, currently_displayed_index);
+                       max_elements = data->process_table->len;
+
+                       /* we force to pause the display when moving in time */
+                       if (toggle_pause < 0)
+                               pause_display();
+
+                       update_current_view();
+                       update_footer();
+                       break;
+               case KEY_RIGHT:
+                       if (currently_displayed_index < last_display_index) {
+                               currently_displayed_index++;
+                               print_log("Going forward in time");
+                               data = g_ptr_array_index(copies, currently_displayed_index);
+                               max_elements = data->process_table->len;
+                               update_current_view();
+                               update_footer();
+                       } else {
+                               print_log("Manually moving forward");
+                               sem_post(&timer);
+                               /* we force to resume the refresh when moving forward */
+                               if (toggle_pause > 0)
+                                       resume_display();
+                       }
+
+                       break;
+               case ' ':
+                       if (perf_panel_visible)
+                               update_perf_panel(perf_line_selected, 1, 0);
+                       break;
+               case 's':
+                       if (perf_panel_visible)
+                               update_perf_panel(perf_line_selected, 0, 1);
+                       break;
+
+               case 13: /* FIXME : KEY_ENTER ?? */
+                       if (current_view == cpu) {
+                               current_view = process_details;
+                       }
+                       update_current_view();
+                       break;
+
+               case KEY_F(1):
+                       toggle_tree *= -1;
+                       current_view = cpu;
+                       update_current_view();
+                       break;
+               case KEY_F(2):
+                       current_view = cpu;
+                       update_current_view();
+                       break;
+               case KEY_F(3):
+                       current_view = perf;
+                       toggle_tree = -1;
+                       update_current_view();
+                       break;
+               case KEY_F(4):
+                       current_view = fileio;
+                       toggle_tree = -1;
+                       update_current_view();
+                       break;
+               case KEY_F(5):
+                       current_view = netio;
+                       toggle_tree = -1;
+                       update_current_view();
+                       break;
+               case KEY_F(6):
+                       current_view = iostream;
+                       toggle_tree = -1;
+                       update_current_view();
+                       break;
+               case KEY_F(10):
+               case 'q':
+                       reset_ncurses();
+                       break;
+               case 't':
+                       toggle_threads *= -1;
+                       update_current_view();
+                       break;
+               case 'p':
+                       if (toggle_pause < 0) {
+                               pause_display();
+                       } else {
+                               resume_display();
+                       }
+                       break;
+               case 'P':
+                       toggle_perf_panel();
+                       break;
+               default:
+                       /*
+                        * commented because it makes the list refresh in different order
+                        * if we sort and there are equal values
+                        if (data)
+                        update_current_view();
+                        */
+                       break;
+               }
+               update_footer();
+       }
+       return NULL;
+}
+
+void init_ncurses()
+{
+       sem_init(&update_display_sem, 0, 1);
+       init_screen();
+
+       header = create_window(7, COLS - 1, 0, 0);
+       center = create_window(LINES - 7 - 7, COLS - 1, 7, 0);
+       status = create_window(MAX_LOG_LINES + 2, COLS - 1, LINES - 7, 0);
+       footer = create_window(1, COLS - 1, LINES - 1, 0);
+
+       print_log("Starting display");
+
+       main_panel = new_panel(center);
+       setup_perf_panel();
+
+       current_view = cpu;
+
+       basic_header();
+       update_footer();
+
+       pthread_create(&keyboard_thread, NULL, handle_keyboard, (void *)NULL);
+}
+
diff --git a/src/cursesdisplay.h b/src/cursesdisplay.h
new file mode 100644 (file)
index 0000000..6a54252
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef CURSESDISPLAY_H
+#define CURSESDISPLAY_H
+
+#include <glib.h>
+#include <ncurses.h>
+#include "common.h"
+
+enum current_view_list
+{
+       cpu = 1,
+       perf,
+       process_details,
+       fileio,
+       netio,
+       iostream,
+       tree,
+} current_view;
+
+void display(unsigned int);
+void init_ncurses();
+void reset_ncurses();
+
+#endif // CURSESDISPLAY_H
diff --git a/src/iostreamtop.c b/src/iostreamtop.c
new file mode 100644 (file)
index 0000000..1594df7
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2011 Mathieu Bain <mathieu.bain@polymtl.ca>
+ *
+ * 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include <babeltrace/babeltrace.h>
+
+#include "lttngtoptypes.h"
+#include "common.h"
+#include "iostreamtop.h"
+
+#include <stdlib.h>
+
+int update_iostream_ret(struct lttngtop *ctx, int tid, char *comm,
+               unsigned long timestamp, int cpu_id, int ret)
+{
+       struct processtop *tmp;
+       int err = 0;
+
+       tmp = get_proc(ctx, tid, comm, timestamp);
+       if ((tmp->iostream->syscall_info != NULL) && (tmp->iostream->syscall_info->cpu_id == cpu_id)) {
+               if (tmp->iostream->syscall_info->type == __NR_read && ret > 0) {
+                       tmp->iostream->ret_read += ret;
+                       tmp->iostream->ret_total += ret;
+               } else if(tmp->iostream->syscall_info->type == __NR_write && ret > 0) {
+                       tmp->iostream->ret_write += ret;
+                       tmp->iostream->ret_total += ret;
+               } else{
+                       err = -1;
+               }
+               free(tmp->iostream->syscall_info);
+               tmp->iostream->syscall_info = NULL;
+       }
+
+       return err;
+}
+
+enum bt_cb_ret handle_exit_syscall(struct bt_ctf_event *call_data,
+               void *private_data)
+{
+       struct definition *scope;
+       unsigned long timestamp;
+       char *comm;
+       uint64_t ret, tid;
+       int64_t cpu_id;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                       BT_STREAM_EVENT_CONTEXT);
+       comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
+                               scope, "_procname"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing procname context info\n");
+               goto error;
+       }
+
+       tid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
+                               scope, "_tid"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing tid context info\n");
+               goto error;
+       }
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                       BT_EVENT_FIELDS);
+       ret = bt_ctf_get_int64(bt_ctf_get_field(call_data,
+                               scope, "_ret"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing ret context info\n");
+               goto error;
+       }
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                       BT_STREAM_PACKET_CONTEXT);
+       cpu_id = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
+                               scope, "cpu_id"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing cpu_id context info\n");
+               goto error;
+       }
+
+       /*
+        * if we encounter an exit_syscall and it is not for a syscall read or write
+        * we just abort the execution of this callback
+        */
+       if ((update_iostream_ret(&lttngtop, tid, comm, timestamp, cpu_id, ret)) < 0)
+               return BT_CB_ERROR_CONTINUE;
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
+
+
+enum bt_cb_ret handle_sys_write(struct bt_ctf_event *call_data,
+               void *private_data)
+{
+       struct definition *scope;
+       struct processtop *tmp;
+       struct syscalls *syscall_info;
+       unsigned long timestamp;
+       uint64_t cpu_id;
+       char *comm;
+       int64_t tid;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                       BT_STREAM_EVENT_CONTEXT);
+       comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
+                               scope, "_procname"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing procname context info\n");
+               goto error;
+       }
+
+       tid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
+                               scope, "_tid"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing tid context info\n");
+               goto error;
+       }
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                       BT_STREAM_PACKET_CONTEXT);
+       cpu_id = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
+                               scope, "cpu_id"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing cpu_id context info\n");
+               goto error;
+       }
+
+       syscall_info = malloc(sizeof(struct syscalls));
+       syscall_info->cpu_id = cpu_id;
+       syscall_info->type = __NR_write;
+       syscall_info->tid =  tid;
+       tmp = get_proc(&lttngtop, tid, comm, timestamp);
+       tmp->iostream->syscall_info = syscall_info;
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
+
+enum bt_cb_ret handle_sys_read(struct bt_ctf_event *call_data,
+               void *private_data)
+{
+       struct processtop *tmp;
+       struct definition *scope;
+       struct syscalls * syscall_info;
+       unsigned long timestamp;
+       uint64_t cpu_id;
+       char *comm;
+       int64_t tid;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                       BT_STREAM_EVENT_CONTEXT);
+       comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
+                               scope, "_procname"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing procname context info\n");
+               goto error;
+       }
+
+       tid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
+                               scope, "_tid"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing tid context info\n");
+               goto error;
+       }
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                       BT_STREAM_PACKET_CONTEXT);
+       cpu_id = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
+                               scope, "cpu_id"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing cpu_id context info\n");
+               goto error;
+       }
+
+       syscall_info = malloc(sizeof(struct syscalls));
+       syscall_info->cpu_id = cpu_id;
+       syscall_info->type = __NR_read;
+       syscall_info->tid =  tid;
+       tmp = get_proc(&lttngtop, tid, comm, timestamp);
+       tmp->iostream->syscall_info = syscall_info;
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
+
diff --git a/src/iostreamtop.h b/src/iostreamtop.h
new file mode 100644 (file)
index 0000000..bde4dbf
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 Mathieu Bain <mathieu.bain@polymtl.ca>
+ *
+ * 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef _IOSTREANTOP_H
+#define _IOSTREAMTOP_H
+
+#include <babeltrace/babeltrace.h>
+#include <inttypes.h>
+#include <glib.h>
+#include <asm/unistd.h>
+
+/*
+#define SYS_READ  1
+#define SYS_WRITE 2
+*/
+
+enum bt_cb_ret handle_exit_syscall(struct bt_ctf_event *call_data,
+               void *private_data);
+
+enum bt_cb_ret handle_sys_write(struct bt_ctf_event *call_data,
+               void *private_data);
+
+enum bt_cb_ret handle_sys_read(struct bt_ctf_event *call_data,
+               void *private_data);
+
+#endif /* _IOSTREAMTOP_H */
diff --git a/src/lttngtop.c b/src/lttngtop.c
new file mode 100644 (file)
index 0000000..5d526f3
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2011 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#define _GNU_SOURCE
+#include <config.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/callbacks.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <popt.h>
+#include <stdlib.h>
+#include <ftw.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <fts.h>
+
+#include "lttngtoptypes.h"
+#include "cputop.h"
+#include "iostreamtop.h"
+#include "cursesdisplay.h"
+#include "common.h"
+
+#define DEFAULT_FILE_ARRAY_SIZE 1
+
+const char *opt_input_path;
+
+struct lttngtop *copy;
+pthread_t display_thread;
+pthread_t timer_thread;
+
+unsigned long refresh_display = 1 * NSEC_PER_SEC;
+unsigned long last_display_update = 0;
+int quit = 0;
+
+enum {
+       OPT_NONE = 0,
+       OPT_HELP,
+       OPT_LIST,
+       OPT_VERBOSE,
+       OPT_DEBUG,
+       OPT_NAMES,
+};
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
+       { NULL, 0, 0, NULL, 0, NULL, NULL },
+};
+
+void *refresh_thread(void *p)
+{
+       while (1) {
+               sem_wait(&pause_sem);
+               sem_post(&pause_sem);
+               sem_post(&timer);
+               sleep(refresh_display/NSEC_PER_SEC);
+       }
+}
+
+void *ncurses_display(void *p)
+{
+       unsigned int current_display_index = 0;
+
+       sem_wait(&bootstrap);
+       init_ncurses();
+
+       while (1) {
+               sem_wait(&timer);
+               sem_wait(&goodtodisplay);
+               sem_wait(&pause_sem);
+
+               copy = g_ptr_array_index(copies, current_display_index);
+               if (copy)
+                       display(current_display_index++);
+
+               sem_post(&goodtoupdate);
+               sem_post(&pause_sem);
+
+               if (quit) {
+                       reset_ncurses();
+                       pthread_exit(0);
+               }
+       }
+}
+
+/*
+ * hook on each event to check the timestamp and refresh the display if
+ * necessary
+ */
+enum bt_cb_ret check_timestamp(struct bt_ctf_event *call_data, void *private_data)
+{
+       unsigned long timestamp;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       if (last_display_update == 0)
+               last_display_update = timestamp;
+
+       if (timestamp - last_display_update >= refresh_display) {
+               sem_wait(&goodtoupdate);
+               g_ptr_array_add(copies, get_copy_lttngtop(last_display_update,
+                                       timestamp));
+               sem_post(&goodtodisplay);
+               sem_post(&bootstrap);
+               last_display_update = timestamp;
+       }
+       return BT_CB_OK;
+
+error:
+       fprintf(stderr, "check_timestamp callback error\n");
+       return BT_CB_ERROR_STOP;
+}
+
+/*
+ * get_perf_counter : get or create and return a perf_counter struct for
+ * either a process or a cpu (only one of the 2 parameters mandatory)
+ */
+struct perfcounter *get_perf_counter(const char *name, struct processtop *proc,
+               struct cputime *cpu)
+{
+       struct perfcounter *ret, *global;
+       GHashTable *table;
+
+       if (proc)
+               table = proc->perf;
+       else if (cpu)
+               table = cpu->perf;
+       else
+               goto error;
+
+       ret = g_hash_table_lookup(table, (gpointer) name);
+       if (ret)
+               goto end;
+
+       ret = malloc(sizeof(struct perfcounter));
+       memset(ret, 0, sizeof(struct perfcounter));
+       /* by default, make it visible in the UI */
+       ret->visible = 1;
+       g_hash_table_insert(table, (gpointer) name, ret);
+
+       global = g_hash_table_lookup(lttngtop.perf_list, (gpointer) name);
+       if (!global) {
+               global = malloc(sizeof(struct perfcounter));
+               memset(global, 0, sizeof(struct perfcounter));
+               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) name, global);
+       }
+
+end:
+       return ret;
+
+error:
+       return NULL;
+}
+
+void update_perf_value(struct processtop *proc, struct cputime *cpu,
+               const char *name, int value)
+{
+       struct perfcounter *cpu_perf, *process_perf;
+
+       cpu_perf = get_perf_counter(name, NULL, cpu);
+       if (cpu_perf->count < value) {
+               process_perf = get_perf_counter(name, proc, NULL);
+               process_perf->count += value - cpu_perf->count;
+               cpu_perf->count = value;
+       }
+}
+
+void extract_perf_counter_scope(struct bt_ctf_event *event,
+               struct definition *scope,
+               struct processtop *proc,
+               struct cputime *cpu)
+{
+       struct definition const * const *list = NULL;
+       unsigned int count;
+       int i, ret;
+
+       if (!scope)
+               goto end;
+
+       ret = bt_ctf_get_field_list(event, scope, &list, &count);
+       if (ret < 0)
+               goto end;
+
+       for (i = 0; i < count; i++) {
+               const char *name = bt_ctf_field_name(list[i]);
+               if (strncmp(name, "_perf_", 6) == 0) {
+                       int value = bt_ctf_get_uint64(list[i]);
+                       if (bt_ctf_field_get_error())
+                               continue;
+                       update_perf_value(proc, cpu, name, value);
+               }
+       }
+
+end:
+       return;
+}
+
+void update_perf_counter(struct processtop *proc, struct bt_ctf_event *event)
+{
+       struct definition *scope;
+       uint64_t cpu_id;
+       struct cputime *cpu;
+
+       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_PACKET_CONTEXT);
+       cpu_id = bt_ctf_get_uint64(bt_ctf_get_field(event, scope, "cpu_id"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "[error] get cpu_id\n");
+               goto end;
+       }
+       cpu = get_cpu(cpu_id);
+
+       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT);
+       extract_perf_counter_scope(event, scope, proc, cpu);
+
+       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_PACKET_CONTEXT);
+       extract_perf_counter_scope(event, scope, proc, cpu);
+
+       scope = bt_ctf_get_top_level_scope(event, BT_EVENT_CONTEXT);
+       extract_perf_counter_scope(event, scope, proc, cpu);
+
+end:
+       return;
+}
+
+enum bt_cb_ret fix_process_table(struct bt_ctf_event *call_data,
+               void *private_data)
+{
+       int pid, tid, ppid;
+       char *comm;
+       struct processtop *parent, *child;
+       struct definition *scope;
+       unsigned long timestamp;
+
+       /* FIXME : check context pid, tid, ppid and comm */
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       scope = bt_ctf_get_top_level_scope(call_data, BT_STREAM_EVENT_CONTEXT);
+
+       pid = bt_ctf_get_int64(bt_ctf_get_field(call_data, scope, "_pid"));
+       if (bt_ctf_field_get_error()) {
+//             fprintf(stderr, "Missing pid context info\n");
+               goto error;
+       }
+       tid = bt_ctf_get_int64(bt_ctf_get_field(call_data, scope, "_tid"));
+       if (bt_ctf_field_get_error()) {
+//             fprintf(stderr, "Missing tid context info\n");
+               goto error;
+       }
+       ppid = bt_ctf_get_int64(bt_ctf_get_field(call_data, scope, "_ppid"));
+       if (bt_ctf_field_get_error()) {
+//             fprintf(stderr, "Missing ppid context info\n");
+               goto error;
+       }
+       comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data, scope, "_procname"));
+       if (bt_ctf_field_get_error()) {
+//             fprintf(stderr, "Missing procname context info\n");
+               goto error;
+       }
+
+       /* find or create the current process */
+       child = find_process_tid(&lttngtop, tid, comm);
+       if (!child)
+               child = add_proc(&lttngtop, tid, comm, timestamp);
+       update_proc(child, pid, tid, ppid, comm);
+
+       if (pid != tid) {
+               /* find or create the parent */
+               parent = find_process_tid(&lttngtop, pid, comm);
+               if (!parent) {
+                       parent = add_proc(&lttngtop, pid, comm, timestamp);
+                       parent->pid = pid;
+               }
+
+               /* attach the parent to the current process */
+               child->threadparent = parent;
+               add_thread(parent, child);
+       }
+
+       update_perf_counter(child, call_data);
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
+
+void init_lttngtop()
+{
+       copies = g_ptr_array_new();
+       lttngtop.perf_list = g_hash_table_new(g_direct_hash, g_direct_equal);
+
+       sem_init(&goodtodisplay, 0, 0);
+       sem_init(&goodtoupdate, 0, 1);
+       sem_init(&timer, 0, 1);
+       sem_init(&bootstrap, 0, 0);
+       sem_init(&pause_sem, 0, 1);
+       sem_init(&end_trace_sem, 0, 0);
+
+       lttngtop.process_table = g_ptr_array_new();
+       lttngtop.files_table = g_ptr_array_new();
+       lttngtop.cpu_table = g_ptr_array_new();
+}
+
+void usage(FILE *fd)
+{
+
+}
+
+/*
+ * Return 0 if caller should continue, < 0 if caller should return
+ * error, > 0 if caller should exit without reporting error.
+ */
+static int parse_options(int argc, char **argv)
+{
+       poptContext pc;
+       int opt, ret = 0;
+
+       if (argc == 1) {
+               usage(stdout);
+               return 1;   /* exit cleanly */
+       }
+
+       pc = poptGetContext(NULL, argc, (const char **) argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+                       case OPT_HELP:
+                               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;
+               }
+       }
+
+       opt_input_path = poptGetArg(pc);
+       if (!opt_input_path) {
+               ret = -EINVAL;
+               goto end;
+       }
+end:
+       if (pc) {
+               poptFreeContext(pc);
+       }
+       return ret;
+}
+
+void iter_trace(struct bt_context *bt_ctx)
+{
+       struct bt_ctf_iter *iter;
+       struct bt_iter_pos begin_pos;
+       struct bt_ctf_event *event;
+       int ret = 0;
+
+       begin_pos.type = BT_SEEK_BEGIN;
+       iter = bt_ctf_iter_create(bt_ctx, &begin_pos, NULL);
+
+       /* at each event check if we need to refresh */
+       bt_ctf_iter_add_callback(iter, 0, NULL, 0,
+                       check_timestamp,
+                       NULL, NULL, NULL);
+       /* at each event, verify the status of the process table */
+       bt_ctf_iter_add_callback(iter, 0, NULL, 0,
+                       fix_process_table,
+                       NULL, NULL, NULL);
+       /* to handle the scheduling events */
+       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);
+
+       /* for IO top */
+       bt_ctf_iter_add_callback(iter,
+                       g_quark_from_static_string("exit_syscall"),
+                       NULL, 0, handle_exit_syscall, NULL, NULL, NULL);
+       bt_ctf_iter_add_callback(iter,
+                       g_quark_from_static_string("sys_write"),
+                       NULL, 0, handle_sys_write, NULL, NULL, NULL);
+       bt_ctf_iter_add_callback(iter,
+                       g_quark_from_static_string("sys_read"),
+                       NULL, 0, handle_sys_read, NULL, NULL, NULL);
+       while ((event = bt_ctf_iter_read_event(iter)) != NULL) {
+               ret = bt_iter_next(bt_ctf_get_iter(iter));
+               if (ret < 0)
+                       goto end_iter;
+       }
+
+       /* block until quit, we reached the end of the trace */
+       sem_wait(&end_trace_sem);
+
+end_iter:
+       bt_iter_destroy(bt_ctf_get_iter(iter));
+}
+
+/*
+ * bt_context_add_traces_recursive: Open a trace recursively
+ * (copied from BSD code in converter/babeltrace.c)
+ *
+ * Find each trace present in the subdirectory starting from the given
+ * path, and add them to the context. The packet_seek parameter can be
+ * NULL: this specify to use the default format packet_seek.
+ *
+ * Return: 0 on success, nonzero on failure.
+ * Unable to open toplevel: failure.
+ * Unable to open some subdirectory or file: warn and continue;
+ */
+int bt_context_add_traces_recursive(struct bt_context *ctx, const char *path,
+               const char *format_str,
+               void (*packet_seek)(struct stream_pos *pos,
+                       size_t offset, int whence))
+{
+       FTS *tree;
+       FTSENT *node;
+       GArray *trace_ids;
+       char lpath[PATH_MAX];
+       char * const paths[2] = { lpath, NULL };
+       int ret;
+
+       /*
+        * Need to copy path, because fts_open can change it.
+        * It is the pointer array, not the strings, that are constant.
+        */
+       strncpy(lpath, path, PATH_MAX);
+       lpath[PATH_MAX - 1] = '\0';
+
+       tree = fts_open(paths, FTS_NOCHDIR | FTS_LOGICAL, 0);
+       if (tree == NULL) {
+               fprintf(stderr, "[error] [Context] Cannot traverse \"%s\" for reading.\n",
+                               path);
+               return -EINVAL;
+       }
+
+       trace_ids = g_array_new(FALSE, TRUE, sizeof(int));
+
+       while ((node = fts_read(tree))) {
+               int dirfd, metafd;
+
+               if (!(node->fts_info & FTS_D))
+                       continue;
+
+               dirfd = open(node->fts_accpath, 0);
+               if (dirfd < 0) {
+                       fprintf(stderr, "[error] [Context] Unable to open trace "
+                               "directory file descriptor.\n");
+                       ret = dirfd;
+                       goto error;
+               }
+               metafd = openat(dirfd, "metadata", O_RDONLY);
+               if (metafd < 0) {
+                       ret = close(dirfd);
+                       if (ret < 0) {
+                               perror("close");
+                               goto error;
+                       }
+               } else {
+                       int trace_id;
+
+                       ret = close(metafd);
+                       if (ret < 0) {
+                               perror("close");
+                               goto error;
+                       }
+                       ret = close(dirfd);
+                       if (ret < 0) {
+                               perror("close");
+                               goto error;
+                       }
+
+                       trace_id = bt_context_add_trace(ctx,
+                               node->fts_accpath, format_str,
+                               packet_seek, NULL, NULL);
+                       if (trace_id < 0) {
+                               fprintf(stderr, "[error] [Context] opening trace \"%s\" from %s "
+                                       "for reading.\n", node->fts_accpath, path);
+                               ret = trace_id;
+                               goto error;
+                       }
+                       g_array_append_val(trace_ids, trace_id);
+               }
+       }
+
+       g_array_free(trace_ids, TRUE);
+       return 0;
+
+error:
+       return ret;
+}
+
+int main(int argc, char **argv)
+{
+       int ret;
+       struct bt_context *bt_ctx = NULL;
+
+       ret = parse_options(argc, argv);
+       if (ret < 0) {
+               fprintf(stdout, "Error parsing options.\n\n");
+               usage(stdout);
+               exit(EXIT_FAILURE);
+       } else if (ret > 0) {
+               exit(EXIT_SUCCESS);
+       }
+
+       init_lttngtop();
+
+       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");
+               goto end;
+       }
+
+       pthread_create(&display_thread, NULL, ncurses_display, (void *) NULL);
+       pthread_create(&timer_thread, NULL, refresh_thread, (void *) NULL);
+
+       iter_trace(bt_ctx);
+
+       quit = 1;
+       pthread_join(display_thread, NULL);
+
+end:
+       return 0;
+}
diff --git a/src/lttngtoptypes.h b/src/lttngtoptypes.h
new file mode 100644 (file)
index 0000000..f10a684
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2011 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef LTTNGTOPTYPES_H
+#define LTTNGTOPTYPES_H
+
+#include <glib.h>
+
+struct lttngtop {
+       GPtrArray *process_table;       /* struct processtop */
+       GPtrArray *files_table;         /* struct files */
+       GPtrArray *cpu_table;           /* struct cputime */
+       GHashTable *perf_list;          /* struct perfcounter */
+       unsigned long start;
+       unsigned long end;
+       unsigned int nbproc;
+       unsigned int nbnewproc;
+       unsigned int nbdeadproc;
+       unsigned int nbthreads;
+       unsigned int nbnewthreads;
+       unsigned int nbdeadthreads;
+       unsigned int nbfiles;
+       unsigned int nbnewfiles;
+       unsigned int nbclosedfiles;
+} lttngtop;
+
+struct processtop {
+       unsigned int puuid;
+       int pid;
+       char *comm;
+       int tid;
+       int ppid;
+       int oldpid;
+       int oldtid;
+       int oldppid;
+       unsigned long birth;
+       unsigned long death;
+       unsigned long lastactivity;
+       GPtrArray *process_files_table;
+       GPtrArray *threads;
+       GHashTable *perf;
+       struct processtop *threadparent;
+       unsigned long totalfileread;
+       unsigned long totalfilewrite;
+       unsigned long totalcpunsec;
+       unsigned long threadstotalcpunsec;
+       /* IO speed for this process */
+       struct iostream *iostream;
+};
+
+struct perfcounter
+{
+       unsigned long count;
+       int visible;
+       int sort;
+};
+
+struct cputime {
+       guint id;
+       struct processtop *current_task;
+       unsigned long task_start;
+       GHashTable *perf;
+};
+
+/*
+ * used for "relative seeks" (with fd, for example fs.lseek)
+ * and for "absolute seeks" (events occuring on a device without
+ * any link to a particular process)
+ */
+struct seeks {
+       unsigned long offset;
+       unsigned long count;
+};
+
+struct ioctls {
+       unsigned int command;
+       unsigned long count;
+};
+
+struct files {
+       struct processtop *ref;
+       unsigned int fuuid;
+       int fd;
+       char *name;
+       int oldfd;
+       int device;
+       int openmode;
+       unsigned long openedat;
+       unsigned long closedat;
+       unsigned long lastaccess;
+       unsigned long read;
+       unsigned long write;
+       unsigned long nbpoll;
+       unsigned long nbselect;
+       unsigned long nbopen;
+       unsigned long nbclose;
+       //struct *seeks; /* relative seeks inside the file */
+       //struct *ioctls;
+       /* XXX : average wait time */
+};
+
+struct sockets {
+       int fd;
+       int parent_fd;  /* on accept a new fd is created from the bound socket */
+       int family;
+       int type;
+       int protocol;
+       int sock_address;
+       unsigned long openedat;
+       unsigned long closedat;
+       unsigned long bind_address;
+       unsigned long remote_address;
+       //struct *sock_options;
+};
+
+struct sock_options {
+       int name;
+       int value;
+};
+
+struct vmas {
+       unsigned long start;
+       unsigned long end;
+       unsigned long flags;
+       unsigned long prot;
+       char *description; /* filename or description if possible (stack, heap) */
+       unsigned long page_faults;
+};
+
+struct syscalls {
+       unsigned int id;
+       unsigned long count;
+        unsigned int cpu_id;
+        unsigned int type;
+        unsigned int tid;
+};
+
+struct signals {
+       int dest_pid;
+       int id;
+       unsigned long count;
+};
+
+struct iostream {
+        struct syscalls *syscall_info; /* NULL if there is no waiting for an exit_syscall */
+        unsigned long ret_read;        /* value returned by an I/O syscall_exit for a sys_read*/
+        unsigned long ret_write;       /* value returned by an I/O syscall_exit for a sys_write*/
+        unsigned long ret_total;
+};
+
+#endif /* LTTNGTOPTYPES_H */
This page took 0.117943 seconds and 4 git commands to generate.