Convert LTTngTop to C++ and state system state-system
authorPierre-Bernard Thiffault <pbthiffault@gmail.com>
Fri, 21 Dec 2012 18:39:17 +0000 (13:39 -0500)
committerJulien Desfossez <jdesfossez@efficios.com>
Fri, 21 Dec 2012 19:16:48 +0000 (14:16 -0500)
This commit integrates LTTngTop with a generic C++ state system.
This creates a cleaner code base as the analysis won't require any
ad-hoc state system anymore.
Since the library is in C++, this commit also converts LTTngTop
to C++, most of the code written in C stays the same.

New dependencies (that should be integrated in the tree) :
git://git.dorsal.polymtl.ca/~smarchi/libstate.git
git://git.dorsal.polymtl.ca/~frajotte/librbrntrvll.git

The code is not yet working, but it is close.

Signed-off-by: Pierre-Bernard Thiffault <pbthiffault@gmail.com>
Signed-off-by: Julien Desfossez <jdesfossez@efficios.com>
20 files changed:
configure.ac
src/Makefile.am
src/attributes.txt [new file with mode: 0644]
src/common.c [deleted file]
src/common.cpp [new file with mode: 0644]
src/common.h
src/cputop.c [deleted file]
src/cputop.cpp [new file with mode: 0644]
src/cputop.h
src/cursesdisplay.c [deleted file]
src/cursesdisplay.cpp [new file with mode: 0644]
src/cursesdisplay.h
src/iostreamtop.c [deleted file]
src/iostreamtop.cpp [new file with mode: 0644]
src/iostreamtop.h
src/libStateIntegrationPrototype.cpp [new file with mode: 0644]
src/libStateIntegrationPrototype.h [new file with mode: 0644]
src/lttngtop.c [deleted file]
src/lttngtop.cpp [new file with mode: 0644]
src/lttngtoptypes.h

index 358ead88e2443705c69a7e98003a13dba55a87b0..6eb66610a8821073d837b27c17b64190305ad248 100644 (file)
@@ -14,6 +14,7 @@ AC_CONFIG_HEADERS([config.h])
 
 # Checks for programs.
 AC_PROG_CC
+AC_PROG_CXX
 AC_PROG_MAKE_SET
 LT_INIT
 AC_PROG_YACC
index 382cfc2b1d6ae1f13ad03cd5f0873faa0738d99e..e060d65ff639a8575a123c662337d4d7653ed0c5 100644 (file)
@@ -1,4 +1,5 @@
 AM_CFLAGS = $(PACKAGE_CFLAGS)
+AM_CXXFLAGS = $(PACKAGE_CFLAGS)
 
 bin_PROGRAMS = lttngtop
 
@@ -6,14 +7,18 @@ noinst_HEADERS = \
        lttngtoptypes.h \
        common.h \
        cputop.h \
-       cursesdisplay.h \
-       iostreamtop.h
+       iostreamtop.h \
+       cursesdisplay.h
 
 lttngtop_SOURCES = \
-       lttngtop.c \
-       common.c \
-       cursesdisplay.c \
-       cputop.c \
-       iostreamtop.c
+       lttngtop.cpp \
+       common.cpp \
+       cputop.cpp \
+       iostreamtop.cpp \
+       cursesdisplay.cpp
 
-lttngtop_LDADD = -lbabeltrace -lbabeltrace-ctf
+lttngtop_LDADD = \
+       -lbabeltrace \
+       -lbabeltrace-ctf \
+       -lboost_system \
+       -lstate
diff --git a/src/attributes.txt b/src/attributes.txt
new file mode 100644 (file)
index 0000000..120ad12
--- /dev/null
@@ -0,0 +1,61 @@
+List of available attributes
+
+cpu: pointer to first cpu
+cpus/[cpuid]/perf: pointer to first perf counter for cpu cpuid
+cpus/[cpuid]/perf/[perfname]/count: count for perf counter perfname on cpu cpuid
+cpus/[cpuid]/perf/[perfname]/visible: visibility for perf counter perfname on cpu cpuid
+cpus/[cpuid]/perf/[perfname]/next: pointer to next perf counter in linked list
+cpus/[cpuid]/task_start: timestamp for the start of current_task
+cpus/[cpuid]/current_task: pointer to current_task
+cpus/[cpuid]/next: pointer to next cpu in linked list
+proc: pointer to first process
+processes/[tid]/perf: pointer to first perf counter for task tid
+processes/[tid]/perf/[perfname]/count: count for perf counter perfname on task tid
+processes/[tid]/perf/[perfname]/visible: visibility for perf counter perfname on task tid
+processes/[tid]/perf/[perfname]/next: pointer to next perf counter in linked list
+processes/[tid]/files_history/current: pointer to first file for task tid
+processes/[tid]/file_history[x]: file history entry for file x (sequential) for task tid
+processes/[tid]/file_history[x]/file: file entry for file x (sequential) for task tid
+processes/[tid]/file_history[x]/file/name: file name for file x (sequential) for task tid
+processes/[tid]/file_history[x]/file/read: bytes read from file x (sequential) for task tid
+processes/[tid]/file_history[x]/file/write: bytes written to file x (sequential) for task tid
+processes/[tid]/file_history[x]/file/flag: status flag for file x (sequential) for task tid
+processes/[tid]/file_history[x]/file/fd: file descriptor for file x (sequential) for task tid
+processes/[tid]/file_history[x]/file/birth: timestamp for the opening of file x (sequential) for task tid
+processes/[tid]/file_history[x]/next: pointer to next file history entry in linked list
+processes/[tid]/files/[fd]: pointer to file entry for file fd for task tid
+processes/[tid]/threads: pointer to first descendant thread for task tid
+processes/[tid]/threads/[dtid]: pointer to descendant thread dtid for task tid
+processes/[tid]/threads/next: pointer to next descendant thread in linked list
+processes/[tid]/threadparent: pointer to parent thread for task tid
+processes/[tid]/syscall_info/type: type for last syscall in task tid
+processes/[tid]/syscall_info/cpu_id: cpuid for last syscall in task tid
+processes/[tid]/syscall_info/tid: tid for last syscall in task tid
+processes/[tid]/syscall_info/fd: fd for last syscall in task tid
+processes/[tid]/tid: tid for task tid
+processes/[tid]/comm: procname for task tid
+processes/[tid]/pid: pid for task tid
+processes/[tid]/ppid: ppid for task tid
+processes/[tid]/birth: timestamp for beginning of task tid
+processes/[tid]/totalfileread: bytes read from all files for task tid
+processes/[tid]/totalfilewrite: bytes written to all files for task tid
+processes/[tid]/read: read stream (B/s) for task tid
+processes/[tid]/write: write stream (B/s) for task tid
+processes/[tid]/totalcpunsec: execution time (ns) for task tid
+processes/[tid]/threadstotalcpunsec: execution time (ns) for task tid and its descendants
+processes/[tid]/selected: whether the task tid is selected by the UI
+perf: pointer to first perf counter in global list
+perf/[perfname]/count: global count for perf counter perfname
+perf/[perfname]/visible: visibility of gloabl perf counter perfname
+perf/[perfname]/sort: whether the global perf counter list is sorted by perf counter perfname's count
+perf/[perfname]/next: next perf counter in linked list
+nbproc: number of active processes
+nbnewproc: number of processes created
+nbdeadproc: number of processes destroyed
+nbthreads: number of active threads
+nbnewthreads: number of threads created
+nbdeadthreads: number of threads destroyed
+nbfiles: number of active files
+nbnewfiles: number of files opened
+nbdeadfiles: number of files destroyed
+
diff --git a/src/common.c b/src/common.c
deleted file mode 100644 (file)
index c939847..0000000
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * Copyright (C) 2011-2012 Julien Desfossez
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <babeltrace/ctf/events.h>
-#include <stdlib.h>
-#include <linux/unistd.h>
-#include <string.h>
-#include "common.h"
-
-uint64_t get_cpu_id(const struct bt_ctf_event *event)
-{
-       const struct definition *scope;
-       uint64_t cpu_id;
-
-       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");
-               return -1ULL;
-       }
-
-       return cpu_id;
-}
-
-uint64_t get_context_tid(const struct bt_ctf_event *event)
-{
-       const struct definition *scope;
-       uint64_t tid;
-
-       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT);
-       tid = bt_ctf_get_int64(bt_ctf_get_field(event,
-                               scope, "_tid"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing tid context info\n");
-               return -1ULL;
-       }
-
-       return tid;
-}
-
-uint64_t get_context_pid(const struct bt_ctf_event *event)
-{
-       const struct definition *scope;
-       uint64_t pid;
-
-       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT);
-       pid = bt_ctf_get_int64(bt_ctf_get_field(event,
-                               scope, "_pid"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing pid context info\n");
-               return -1ULL;
-       }
-
-       return pid;
-}
-
-uint64_t get_context_ppid(const struct bt_ctf_event *event)
-{
-       const struct definition *scope;
-       uint64_t ppid;
-
-       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT);
-       ppid = bt_ctf_get_int64(bt_ctf_get_field(event,
-                               scope, "_ppid"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing ppid context info\n");
-               return -1ULL;
-       }
-
-       return ppid;
-}
-
-char *get_context_comm(const struct bt_ctf_event *event)
-{
-       const struct definition *scope;
-       char *comm;
-
-       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT);
-       comm = bt_ctf_get_char_array(bt_ctf_get_field(event,
-                               scope, "_procname"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing comm context info\n");
-               return NULL;
-       }
-
-       return comm;
-}
-
-/*
- * To get the parent process, put the pid in the tid field
- * because the parent process gets pid = tid
- *
- * FIXME : char *comm useful ???
- */
-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 = g_new0(struct processtop, 1);
-               newproc->tid = tid;
-               newproc->birth = timestamp;
-               newproc->process_files_table = g_ptr_array_new();
-               newproc->files_history = NULL;
-               newproc->totalfileread = 0;
-               newproc->totalfilewrite = 0;
-               newproc->fileread = 0;
-               newproc->filewrite = 0;
-               newproc->syscall_info = NULL;
-               newproc->threadparent = NULL;
-               newproc->threads = g_ptr_array_new();
-               newproc->perf = g_hash_table_new(g_str_hash, g_str_equal);
-               g_ptr_array_add(ctx->process_table, newproc);
-
-               ctx->nbnewthreads++;
-               ctx->nbthreads++;
-       }
-       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;
-               ctx->nbdeadthreads++;
-               ctx->nbthreads--;
-       }
-}
-
-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);
-}
-
-struct processtop *get_proc_pid(struct lttngtop *ctx, int tid, int pid,
-               unsigned long timestamp)
-{
-       struct processtop *tmp;
-       tmp = find_process_tid(ctx, tid, NULL);
-       if (tmp && tmp->pid == pid)
-               return tmp;
-       return add_proc(ctx, tid, "Unknown", 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 = g_new0(struct cputime, 1);
-       newcpu->id = cpu;
-       newcpu->current_task = NULL;
-       newcpu->perf = g_hash_table_new(g_str_hash, g_str_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 = g_new0(struct perfcounter, 1);
-       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, strdup(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, j;
-       struct processtop *tmp;
-       struct files *tmpf; /* a temporary file */
-
-       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->fileread = 0;
-               tmp->filewrite = 0;
-
-               for (j = 0; j < tmp->process_files_table->len; j++) {
-                       tmpf = g_ptr_array_index(tmp->process_files_table, j);
-                       if (tmpf != NULL) {
-                               tmpf->read = 0;
-                               tmpf->write = 0;
-
-                               if (tmpf->flag == __NR_close)
-                                       g_ptr_array_index(
-                                               tmp->process_files_table, j
-                                       ) = NULL;
-                       }
-               }
-       }
-}
-
-void reset_global_counters()
-{
-       lttngtop.nbnewproc = 0;
-       lttngtop.nbdeadproc = 0;
-       lttngtop.nbnewthreads = 0;
-       lttngtop.nbdeadthreads = 0;
-       lttngtop.nbnewfiles = 0;
-       lttngtop.nbclosedfiles = 0;
-}
-
-void copy_global_counters(struct lttngtop *dst)
-{
-       dst->nbproc = lttngtop.nbproc;
-       dst->nbnewproc = lttngtop.nbnewproc;
-       dst->nbdeadproc = lttngtop.nbdeadproc;
-       dst->nbthreads = lttngtop.nbthreads;
-       dst->nbnewthreads = lttngtop.nbnewthreads;
-       dst->nbdeadthreads = lttngtop.nbdeadthreads;
-       dst->nbfiles = lttngtop.nbfiles;
-       dst->nbnewfiles = lttngtop.nbnewfiles;
-       dst->nbclosedfiles = lttngtop.nbclosedfiles;
-       reset_global_counters();
-}
-
-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 = g_new0(struct lttngtop, 1);
-       dst->start = start;
-       dst->end = end;
-       copy_global_counters(dst);
-       dst->process_table = g_ptr_array_new();
-       dst->files_table = g_ptr_array_new();
-       dst->cpu_table = g_ptr_array_new();
-
-       rotate_cputime(end);
-
-       for (i = 0; i < lttngtop.process_table->len; i++) {
-               tmp = g_ptr_array_index(lttngtop.process_table, i);
-               new = g_new0(struct processtop, 1);
-
-               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->files_history = tmp->files_history;
-               new->perf = g_hash_table_new(g_str_hash, g_str_equal);
-               g_hash_table_foreach(tmp->perf, copy_perf_counter, new->perf);
-
-               /* compute the stream speed */
-               if (end - start != 0) {
-                       time = (end - start) / NSEC_PER_SEC;
-                       new->fileread = new->fileread/(time);
-                       new->filewrite = new->filewrite/(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));
-
-                       if (tmpfile != NULL) {
-                               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);
-                       } else {
-                               g_ptr_array_add(new->process_files_table, NULL);
-                               g_ptr_array_add(dst->files_table, NULL);
-                       }
-                       /*
-                        * 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) {
-                               /* FIXME : close the files before */
-                               g_ptr_array_remove(tmp->process_files_table, tmpfile);
-                               g_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);
-                       /* FIXME : TRUE does not mean clears the object in it */
-                       g_ptr_array_free(tmp->threads, TRUE);
-                       free(tmp->comm);
-                       g_ptr_array_free(tmp->process_files_table, TRUE);
-                       /* FIXME : clear elements */
-                       g_hash_table_destroy(tmp->perf);
-                       g_free(tmp);
-               }
-       }
-       rotate_perfcounter();
-
-       for (i = 0; i < lttngtop.cpu_table->len; i++) {
-               tmpcpu = g_ptr_array_index(lttngtop.cpu_table, i);
-               newcpu = g_new0(struct cputime, 1);
-               memcpy(newcpu, tmpcpu, sizeof(struct cputime));
-               newcpu->perf = g_hash_table_new(g_str_hash, g_str_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);
-       }
-       /* FIXME : better algo */
-       /* 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;
-}
-
-
-enum bt_cb_ret handle_statedump_process_state(struct bt_ctf_event *call_data,
-               void *private_data)
-{
-       const struct definition *scope;
-       struct processtop *proc;
-       unsigned long timestamp;
-       int64_t pid, tid;
-       char *procname;
-
-       timestamp = bt_ctf_get_timestamp(call_data);
-       if (timestamp == -1ULL)
-               goto error;
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                        BT_EVENT_FIELDS);
-       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;
-       }
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_EVENT_FIELDS);
-       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;
-       }
-
-       /*
-        * FIXME
-        * I first tried with bt_ctf_get_string but doesn`t work at all
-        * It couldn`t find the field _name because it is an integer in
-        * the metadata and not a string like _filename for the
-        * statedump_file_descriptor
-        */
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_EVENT_FIELDS);
-       procname = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
-                               scope, "_name"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing process name context info\n");
-               goto error;
-       }
-
-       proc = find_process_tid(&lttngtop, tid, procname);
-       if (proc == NULL)
-               proc = add_proc(&lttngtop, tid, procname, timestamp);
-
-       free(proc->comm);
-       proc->comm = strdup(procname);
-       proc->pid = pid;
-
-       /*
-        * FIXME
-        * I would like to free procname because it is duplicated
-        * when the process is created but it segfaults...
-        *
-        * free(procname);
-        */
-
-       return BT_CB_OK;
-
-error:
-       return BT_CB_ERROR_STOP;
-}
diff --git a/src/common.cpp b/src/common.cpp
new file mode 100644 (file)
index 0000000..7ca08b4
--- /dev/null
@@ -0,0 +1,1089 @@
+/*
+ * Copyright (C) 2011-2012 Julien Desfossez
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+extern "C" {
+#include <babeltrace/ctf/events.h>
+}
+#include <stdlib.h>
+#include <linux/unistd.h>
+#include <string.h>
+#include "common.h"
+
+StateSystem *state_system;
+std::set<Quark> modified_quarks;
+unsigned long last_display_update = 0;
+unsigned long first_display_update = 0;
+sem_t goodtodisplay, goodtoupdate, timer, pause_sem, end_trace_sem, bootstrap;
+
+int get_cpu_id(const struct bt_ctf_event *event)
+{
+       const struct definition *scope;
+       int cpu_id;
+
+       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");
+               return -1;
+       }
+
+       return cpu_id;
+}
+
+int get_context_tid(const struct bt_ctf_event *event)
+{
+       const struct definition *scope;
+       int tid;
+
+       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT);
+       tid = bt_ctf_get_int64(bt_ctf_get_field(event, scope, "_tid"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing tid context info\n");
+               return -1;
+       }
+
+       return tid;
+}
+
+int get_context_pid(const struct bt_ctf_event *event)
+{
+       const struct definition *scope;
+       int pid;
+
+       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT);
+       pid = bt_ctf_get_int64(bt_ctf_get_field(event, scope, "_pid"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing pid context info\n");
+               return -1;
+       }
+
+       return pid;
+}
+
+int get_context_ppid(const struct bt_ctf_event *event)
+{
+       const struct definition *scope;
+       int ppid;
+
+       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT);
+       ppid = bt_ctf_get_int64(bt_ctf_get_field(event, scope, "_ppid"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing ppid context info\n");
+               return -1;
+       }
+
+       return ppid;
+}
+
+char *get_context_comm(const struct bt_ctf_event *event)
+{
+       const struct definition *scope;
+       char *comm;
+
+       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT);
+       comm = bt_ctf_get_char_array(bt_ctf_get_field(event,
+                                                     scope, "_procname"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing comm context info\n");
+               return NULL;
+       }
+
+       return comm;
+}
+
+/*
+ * To get the parent process, put the pid in the tid field
+ * because the parent process gets pid = tid
+ */
+bool find_process_tid(int tid, Quark &ret_proc_quark)
+{
+       std::string path_name = path_name_from_tid(tid);
+
+       if (state_system->attributeExists(path_name)) {
+               ret_proc_quark = state_system->getQuark(path_name);
+               return true;
+       } else {
+               return false;
+       }
+}
+
+Quark add_proc(int tid, std::string comm, unsigned long timestamp)
+{
+       Quark proc_quark = state_system->getQuark(path_name_from_tid(tid));
+
+       modify_attribute(timestamp, &proc_quark, "comm", comm);
+       modify_attribute(timestamp, &proc_quark, "tid", tid);
+       modify_attribute(timestamp, &proc_quark, "birth", timestamp);
+       modify_attribute(timestamp, &proc_quark, "totalfileread", 0);
+       modify_attribute(timestamp, &proc_quark, "totalfilewrite", 0);
+       modify_attribute(timestamp, &proc_quark, "fileread", 0);
+       modify_attribute(timestamp, &proc_quark, "filewrite", 0);
+       modify_attribute(timestamp, &proc_quark, "totalcpunsec", 0UL);
+       modify_attribute(timestamp, &proc_quark, "threadstotalcpunsec", 0UL);
+       modify_attribute(timestamp, &proc_quark, "selected", 0);
+
+       increment_attribute(timestamp, NULL, "nbnewthreads");
+       increment_attribute(timestamp, NULL, "nbthreads");
+
+       add_in_sequence(timestamp, proc_quark, state_system->getQuark("proc"));
+
+       return proc_quark;
+}
+
+void update_proc(unsigned long timestamp, Quark proc, int pid, int tid,
+                int ppid, char *comm)
+{
+       modify_attribute(timestamp, &proc, "pid", pid);
+       modify_attribute(timestamp, &proc, "tid", tid);
+       modify_attribute(timestamp, &proc, "ppid", ppid);
+       modify_attribute(timestamp, &proc, "comm", comm);
+}
+
+/*
+ * 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(int tid, char *comm, unsigned long timestamp)
+{
+       Quark proc_quark;
+       std::string procname;
+       bool proc_found;
+       bool procname_found;
+
+       proc_found = find_process_tid(tid, proc_quark);
+       if (proc_found) {
+               procname_found = get_current_attribute_value_string(
+                       &proc_quark, "comm", procname);
+               if (procname_found && procname == comm) {
+                       modify_attribute(timestamp, &proc_quark, "death",
+                                        timestamp);
+                       increment_attribute(timestamp, NULL, "nbdeadthreads");
+                       decrement_attribute(timestamp, NULL, "nbthreads");
+               }
+       }
+}
+
+Quark get_proc(int tid, char *comm, unsigned long timestamp)
+{
+       Quark proc_quark;
+       std::string proc_comm;
+       bool exists = find_process_tid(tid, proc_quark);
+       std::string comm_str(comm);
+
+       if (!exists)
+               proc_quark = add_proc(tid, comm_str, timestamp);
+
+       /* If PID already exists under different name,
+          we just rename the process */
+       /* FIXME : need to integrate with clone/fork/exit to be accurate */
+       else {
+               get_current_attribute_value_string(&proc_quark, "comm",
+                                                  proc_comm);
+               if (comm_str != proc_comm)
+                       modify_attribute(timestamp, &proc_quark, "comm", comm);
+       }
+
+       return proc_quark;
+}
+
+Quark get_proc_pid(int pid, int tid, unsigned long timestamp)
+{
+       Quark proc;
+       bool proc_found;
+       int proc_pid;
+       bool pid_found;
+
+       proc_found = find_process_tid(tid, proc);
+       if (proc_found) {
+               pid_found = get_current_attribute_value_int(&proc, "pid",
+                                                           proc_pid);
+               if (pid_found && proc_pid == pid)
+                       return proc;
+       }
+       return add_proc(tid, "Unknown", timestamp);
+}
+
+void add_thread(unsigned long timestamp, Quark parent, Quark thread)
+{
+       std::string path;
+       int tid;
+       Quark thread_in_parent;
+
+       get_current_attribute_value_int(&thread, "tid", tid);
+       path = thread_path_name_from_tid(tid);
+
+       if (!state_system->attributeExists(parent, path)) {
+               thread_in_parent = state_system->getQuark(parent, path);
+               modify_attribute(timestamp, &thread_in_parent, "", thread);
+               add_in_sequence(timestamp, thread_in_parent,
+                               state_system->getQuark(parent, "threads"));
+       }
+}
+
+Quark add_cpu(int cpu, unsigned long timestamp)
+{
+       Quark cpu_quark = state_system->getQuark(path_name_from_cpuid(cpu));
+       Quark cpu_root = state_system->getQuark("cpu");
+       modify_attribute(timestamp, &cpu_quark, "id", cpu);
+
+       add_in_sequence(timestamp, cpu_quark, cpu_root);
+
+       return cpu_quark;
+}
+
+Quark get_cpu(int cpu, unsigned long timestamp)
+{
+       std::string path = path_name_from_cpuid(cpu);
+       if (state_system->attributeExists(path))
+               return state_system->getQuark(path);
+       else
+               return add_cpu(cpu, timestamp);
+}
+
+/*
+ * At the end of a sampling period, we need to display the cpu time for each
+ * process
+ */
+void rotate_cputime(unsigned long end)
+{
+       Quark cpu;
+       Quark current_task;
+       unsigned long elapsed;
+       unsigned long start;
+       int tid;
+       int pid;
+
+       if (!get_current_attribute_value_quark(NULL, "cpu", cpu)) {
+               // No CPU to process
+               return;
+       }
+
+       do {
+               get_current_attribute_value_ulong(&cpu, "task_start", start);
+               elapsed = end - start;
+               if (get_current_attribute_value_quark(&cpu, "current_task",
+                                                     current_task)) {
+                       increase_attribute(
+                               end, &current_task, "totalcpunsec", elapsed);
+                       increase_attribute(
+                               end, &current_task, "threadstotalcpunsec",
+                               elapsed);
+                       get_current_attribute_value_int(
+                               &current_task, "pid", pid);
+                       get_current_attribute_value_int(
+                               &current_task, "tid", tid);
+                       if (pid != tid &&
+                           state_system->attributeExists(
+                                   current_task, "threadparent")) {
+                               increase_attribute(
+                                       end, &current_task,
+                                       "threadparent/threadstotalcpunsec",
+                                       elapsed);
+                       }
+               }
+               modify_attribute(end + 1, &cpu, "task_start", end);
+       } while (get_current_attribute_value_quark(&cpu, "next", cpu));
+}
+
+void update_state_on_refresh(unsigned long start, unsigned long end)
+{
+       Quark proc;
+
+       rotate_cputime(end);
+
+       if (get_current_attribute_value_quark(NULL, "proc", proc)) {
+               do {
+                       update_proc_on_refresh(proc, start, end);
+               } while (get_current_attribute_value_quark(
+                                &proc, "next", proc));
+       }
+}
+
+enum bt_cb_ret handle_statedump_process_state(
+       struct bt_ctf_event *call_data, void *private_data)
+{
+       const struct definition *scope;
+       unsigned long timestamp;
+       int pid, tid;
+        /* FIXME */
+       /* char *procname; */
+       Quark proc_quark;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       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;
+       }
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       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;
+       }
+
+       /*
+        * FIXME
+        * I first tried with bt_ctf_get_string but doesn`t work at all
+        * It couldn`t find the field _name because it is an integer in
+        * the metadata and not a string like _filename for the
+        * statedump_file_descriptor
+        */
+       /*
+        * FIXME
+        * We use "Dumped" instead of procname because procname sometimes
+        * causes memory corruption. All FIXME's in this function are
+        * related to this.
+        */
+       /* procname = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
+          scope, "_name")); */
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing process name context info\n");
+               goto error;
+       }
+
+       proc_quark = get_proc(tid, (char *)"Dumped", timestamp);
+       modify_attribute(timestamp, &proc_quark, "pid", pid);
+
+       /* FIXME */
+       /* free(procname); */
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
+
+std::string path_name_from_cpuid(int cpuid)
+{
+       std::stringstream ss;
+       ss << "cpus/" << cpuid;
+       return ss.str();
+}
+
+std::string thread_path_name_from_tid(int tid)
+{
+       std::stringstream ss;
+       ss << "threads/" << tid;
+       return ss.str();
+}
+
+std::string path_name_from_tid(int tid)
+{
+       std::stringstream ss;
+       ss << "processes/" << tid;
+       return ss.str();
+}
+
+std::string path_name_from_fd(int fd)
+{
+       std::stringstream ss;
+       ss << "files/" << fd;
+       return ss.str();
+}
+
+void update_file_on_refresh(Quark proc, Quark file, unsigned long end)
+{
+       int flag;
+       int fd;
+       std::string path;
+       Quark file_pointer;
+
+       /* File closed */
+       get_current_attribute_value_int(&file, "file/flag", flag);
+       if (flag == __NR_close) {
+               get_current_attribute_value_int(&file, "file/fd", fd);
+               if (fd != -1) {
+                       path = path_name_from_fd(fd);
+                       file_pointer = state_system->getQuark(proc, path);
+                       state_system->removeAttribute(end + 1, file_pointer);
+                       state_system->modifyAttribute(end + 1,
+                                                     state_system->getQuark(
+                                                             file, "file/fd"),
+                                                     -1);
+               }
+       }
+}
+
+void update_proc_on_refresh(Quark proc, unsigned long start, unsigned long end)
+{
+
+       int fileread = 0;
+       int filewrite = 0;
+       unsigned long time;
+       unsigned long death;
+       Quark parent;
+       Quark file;
+       int tid;
+       std::string path;
+
+       /* Process died */
+       if (get_current_attribute_value_ulong(&proc, "death", death) &&
+           death > 0 && death <= end) {
+               /* Remove thread from threadparent's threads */
+               if (get_current_attribute_value_quark(
+                           &proc, "threadparent", parent)) {
+                       get_current_attribute_value_int(&proc, "tid", tid);
+                       path = thread_path_name_from_tid(tid);
+                       remove_from_sequence(
+                               end + 1,
+                               state_system->getQuark(parent, path),
+                               state_system->getQuark(parent, "threads"));
+               }
+
+               remove_from_sequence(end + 1, proc,
+                                    state_system->getQuark("proc"));
+               return;
+       }
+
+        /* Files */
+       if (get_current_attribute_value_quark(
+                   &proc, "files_history/current", file)) {
+               do {
+                       update_file_on_refresh(proc, file, end);
+               } while (get_current_attribute_value_quark(
+                                &file, "next", file));
+       }
+
+        /* compute the stream speed */
+       if (end - start != 0) {
+               time = end - start;
+               get_current_attribute_value_int(&proc, "fileread", fileread);
+               get_current_attribute_value_int(&proc, "filewrite", filewrite);
+               modify_attribute(end, &proc, "fileread", (int)(fileread / time));
+               modify_attribute(end, &proc, "filewrite", (int)(filewrite / time));
+       }
+}
+
+void modify_attribute(unsigned long timestamp, const Quark *starting_node,
+                     std::string attribute, int value)
+{
+       Quark q;
+       if (starting_node)
+               q = state_system->getQuark(*starting_node, attribute);
+       else
+               q = state_system->getQuark(attribute);
+       state_system->updateCurrentState(q, value);
+
+       modified_quarks.insert(q);
+}
+
+void modify_attribute(unsigned long timestamp, const Quark *starting_node,
+                     std::string attribute, Quark value)
+{
+       Quark q;
+       if (starting_node)
+               q = state_system->getQuark(*starting_node, attribute);
+       else
+               q = state_system->getQuark(attribute);
+       state_system->updateCurrentState(q, StateValue::SharedPtr(
+                                                new QuarkStateValue(value)));
+
+       modified_quarks.insert(q);
+}
+
+void modify_attribute(unsigned long timestamp, const Quark *starting_node,
+                     std::string attribute, char *value)
+{
+       Quark q;
+       if (starting_node)
+               q = state_system->getQuark(*starting_node, attribute);
+       else
+               q = state_system->getQuark(attribute);
+       state_system->updateCurrentState(q, std::string(value));
+
+       modified_quarks.insert(q);
+}
+
+void modify_attribute(unsigned long timestamp, const Quark *starting_node,
+                     std::string attribute, std::string value)
+{
+       Quark q;
+       if (starting_node)
+               q = state_system->getQuark(*starting_node, attribute);
+       else
+               q = state_system->getQuark(attribute);
+       state_system->updateCurrentState(q, value);
+
+       modified_quarks.insert(q);
+}
+
+void modify_attribute(unsigned long timestamp, const Quark *starting_node,
+                     std::string attribute, unsigned long value)
+{
+       // Libstate works with 32-bit ints, we split the 64-bit ulong
+       // into 2 32-bit ints
+       unsigned int h = value >> 32;
+       unsigned int l = value & 0xffffffff;
+       Quark ql, qh;
+
+       if (starting_node) {
+               ql = state_system->getQuark(*starting_node, attribute + "/l");
+               qh = state_system->getQuark(*starting_node, attribute + "/h");
+       }
+       else {
+               ql = state_system->getQuark(attribute + "/l");
+               qh = state_system->getQuark(attribute + "/h");
+       }
+       state_system->updateCurrentState(ql, l);
+       state_system->updateCurrentState(qh, h);
+
+       modified_quarks.insert(ql);
+       modified_quarks.insert(qh);
+}
+
+void nullify_attribute(unsigned long timestamp, const Quark *starting_node,
+                      std::string attribute)
+{
+       Quark q;
+       q = state_system->getQuark(*starting_node, attribute);
+       state_system->updateCurrentState(q, StateValue::getNullValue());
+
+       modified_quarks.insert(q);
+}
+
+void increment_attribute(unsigned long timestamp, const Quark *starting_node,
+                        std::string attribute)
+{
+       increase_attribute(timestamp, starting_node, attribute, 1);
+}
+
+void increase_attribute(unsigned long timestamp, const Quark *starting_node,
+                       std::string attribute, int amount)
+{
+       int starting_value = 0;
+       get_current_attribute_value_int(starting_node, attribute,
+                                       starting_value);
+       modify_attribute(timestamp, starting_node, attribute,
+                        starting_value + amount);
+}
+
+void increase_attribute(unsigned long timestamp, const Quark *starting_node,
+                       std::string attribute, unsigned long amount)
+{
+       unsigned long starting_value = 0;
+       get_current_attribute_value_ulong(starting_node, attribute,
+                                       starting_value);
+       modify_attribute(timestamp, starting_node, attribute,
+                        starting_value + amount);
+}
+
+void decrement_attribute(unsigned long timestamp, const Quark *starting_node,
+                        std::string attribute)
+{
+       decrease_attribute(timestamp, starting_node, attribute, 1);
+}
+
+void decrease_attribute(unsigned long timestamp, const Quark *starting_node,
+                       std::string attribute, int amount)
+{
+       int starting_value = 0;
+       get_current_attribute_value_int(starting_node, attribute,
+                                       starting_value);
+       modify_attribute(timestamp, starting_node, attribute,
+                        starting_value - amount);
+}
+
+void decrease_attribute(unsigned long timestamp, const Quark *starting_node,
+                       std::string attribute, unsigned long amount)
+{
+       unsigned long starting_value = 0;
+       get_current_attribute_value_ulong(starting_node, attribute,
+                                       starting_value);
+       modify_attribute(timestamp, starting_node, attribute,
+                        starting_value - amount);
+}
+
+bool get_current_attribute_value_int(const Quark *starting_node,
+                                    std::string attribute, int &value)
+{
+       IntegerStateValue::SharedPtr value_ptr;
+       Quark q;
+
+       if (starting_node == NULL)
+               q = state_system->getQuark(attribute);
+       else
+               q = state_system->getQuark(*starting_node, attribute);
+       value_ptr = std::tr1::dynamic_pointer_cast<IntegerStateValue>(
+               state_system->getCurrentStateValue(q));
+
+       if (value_ptr) {
+               value = value_ptr->getValue();
+               return true;
+       }
+       return false;
+}
+
+bool get_current_attribute_value_ulong(const Quark *starting_node,
+                                      std::string attribute,
+                                      unsigned long &value)
+{
+       // Libstate works with 32-bit ints, we split the 64-bit ulong
+       // into 2 32-bit ints
+       IntegerStateValue::SharedPtr value_ptr_l, value_ptr_h;
+       Quark ql, qh;
+       unsigned int l, h;
+
+       if (starting_node == NULL) {
+               ql = state_system->getQuark(attribute + "/l");
+               qh = state_system->getQuark(attribute + "/h");
+       }
+       else {
+               ql = state_system->getQuark(*starting_node, attribute + "/l");
+               qh = state_system->getQuark(*starting_node, attribute + "/h");
+       }
+       value_ptr_l = std::tr1::dynamic_pointer_cast<IntegerStateValue>(
+               state_system->getCurrentStateValue(ql));
+       value_ptr_h = std::tr1::dynamic_pointer_cast<IntegerStateValue>(
+               state_system->getCurrentStateValue(qh));
+
+       if (value_ptr_l && value_ptr_h) {
+               l = value_ptr_l->getValue();
+               h = value_ptr_h->getValue();
+               value = (unsigned long)h << 32 | l;
+               return true;
+       }
+       return false;
+}
+
+bool get_current_attribute_value_quark(const Quark *starting_node,
+                                      std::string attribute, Quark &value)
+{
+       QuarkStateValue::SharedPtr value_ptr;
+       IntegerStateValue::SharedPtr value_ptr_int;
+       Quark q;
+
+       if (starting_node == NULL)
+               q = state_system->getQuark(attribute);
+       else
+               q = state_system->getQuark(*starting_node, attribute);
+       value_ptr = std::tr1::dynamic_pointer_cast<QuarkStateValue>(
+               state_system->getCurrentStateValue(q));
+
+       if (value_ptr) {
+               value = value_ptr->getValue();
+               return true;
+       } else {
+               /* Quark attribute support is not fully integrated in libstate
+                  and librbrntrvll so quarks may get demoted to ints */
+               value_ptr_int = std::tr1::dynamic_pointer_cast<IntegerStateValue>(
+                       state_system->getCurrentStateValue(q));
+               if (value_ptr_int) {
+                       value = (Quark)value_ptr_int->getValue();
+                       return true;
+               }
+       }
+       return false;
+}
+
+bool get_current_attribute_value_string(const Quark *starting_node,
+                                       std::string attribute, std::string &value)
+{
+       StringStateValue::SharedPtr value_ptr;
+       Quark q;
+
+       if (starting_node == NULL)
+               q = state_system->getQuark(attribute);
+       else
+               q = state_system->getQuark(*starting_node, attribute);
+       value_ptr = std::tr1::dynamic_pointer_cast<StringStateValue>(
+               state_system->getCurrentStateValue(q));
+
+       if (value_ptr) {
+               value = value_ptr->getValue();
+               return true;
+       }
+       return false;
+}
+
+bool get_attribute_value_at_int(unsigned long timestamp,
+                               const Quark *starting_node,
+                               std::string attribute,
+                               int &value)
+{
+       StateInterval interval;
+       Quark q;
+       IntegerStateValue::SharedPtr value_ptr;
+
+       if (starting_node == NULL)
+               q = state_system->getQuark(attribute);
+       else
+               q = state_system->getQuark(*starting_node, attribute);
+       interval = state_system->getStateOfAt(timestamp, q);
+       value_ptr = std::tr1::dynamic_pointer_cast<IntegerStateValue>(
+               interval.value);
+
+       if (value_ptr) {
+               value = value_ptr->getValue();
+               return true;
+       }
+       return false;
+}
+
+bool get_attribute_value_at_ulong(unsigned long timestamp,
+                                 const Quark *starting_node,
+                                 std::string attribute,
+                                 unsigned long &value)
+{
+       // Libstate works with 32-bit ints, we split the 64-bit ulong
+       // into 2 32-bit ints
+       StateInterval interval_l, interval_h;
+       Quark ql, qh;
+       IntegerStateValue::SharedPtr value_ptr_l, value_ptr_h;
+       unsigned int l, h;
+
+       if (starting_node == NULL) {
+               ql = state_system->getQuark(attribute + "/l");
+               qh = state_system->getQuark(attribute + "/h");
+       }
+       else {
+               ql = state_system->getQuark(*starting_node, attribute + "/l");
+               qh = state_system->getQuark(*starting_node, attribute + "/h");
+       }
+       interval_l = state_system->getStateOfAt(timestamp, ql);
+       interval_h = state_system->getStateOfAt(timestamp, qh);
+       value_ptr_l = std::tr1::dynamic_pointer_cast<IntegerStateValue>(
+               interval_l.value);
+       value_ptr_h = std::tr1::dynamic_pointer_cast<IntegerStateValue>(
+               interval_h.value);
+
+       if (value_ptr_l && value_ptr_h) {
+               l = value_ptr_l->getValue();
+               h = value_ptr_h->getValue();
+               value = (unsigned long)h << 32 | l;
+               return true;
+       }
+       return false;
+}
+
+bool get_attribute_value_at_quark(unsigned long timestamp,
+                                 const Quark *starting_node,
+                                 std::string attribute,
+                                 Quark &value)
+{
+       StateInterval interval;
+       Quark q;
+       QuarkStateValue::SharedPtr value_ptr;
+       IntegerStateValue::SharedPtr value_ptr_int;
+
+       if (starting_node == NULL)
+               q = state_system->getQuark(attribute);
+       else
+               q = state_system->getQuark(*starting_node, attribute);
+       interval = state_system->getStateOfAt(timestamp, q);
+       value_ptr = std::tr1::dynamic_pointer_cast<QuarkStateValue>(
+               interval.value);
+
+       if (value_ptr) {
+               value = value_ptr->getValue();
+               return true;
+       } else {
+               /* Quark attribute support is not fully integrated in libstate
+                  and librbrntrvll so quarks may get demoted to ints */
+               value_ptr_int = std::tr1::dynamic_pointer_cast<IntegerStateValue>(
+                       interval.value);
+               if (value_ptr_int) {
+                       value = (Quark)value_ptr_int->getValue();
+                       return true;
+               }
+       }
+       return false;
+}
+
+bool get_attribute_value_at_string(unsigned long timestamp,
+                                  const Quark *starting_node,
+                                  std::string attribute,
+                                  std::string &value)
+{
+       StateInterval interval;
+       Quark q;
+       StringStateValue::SharedPtr value_ptr;
+
+       if (starting_node == NULL)
+               q = state_system->getQuark(attribute);
+       else
+               q = state_system->getQuark(*starting_node, attribute);
+       interval = state_system->getStateOfAt(timestamp, q);
+       value_ptr = std::tr1::dynamic_pointer_cast<StringStateValue>(
+               interval.value);
+
+       if (value_ptr) {
+               value = value_ptr->getValue();
+               return true;
+       }
+       return false;
+}
+
+void add_in_sequence(unsigned long timestamp, Quark item, Quark beg)
+{
+       Quark old_newest;
+       if (get_current_attribute_value_quark(&beg, "", old_newest)) {
+               modify_attribute(timestamp, &item, "next", old_newest);
+               modify_attribute(timestamp, &old_newest, "prev", item);
+       }
+       modify_attribute(timestamp, &beg, "", item);
+
+}
+
+void remove_from_sequence(unsigned long timestamp, Quark item, Quark beg)
+{
+       Quark prev;
+       Quark next;
+       bool hasPrev;
+       bool hasNext;
+
+       hasPrev = get_current_attribute_value_quark(&item,
+                                                   "prev", prev);
+       hasNext = get_current_attribute_value_quark(&item,
+                                                   "next", next);
+       if (hasPrev && hasNext) {
+               state_system->modifyAttribute(timestamp,
+                                             state_system->getQuark(next, "prev"),
+                                             StateValue::SharedPtr(
+                                                     new QuarkStateValue(prev)));
+               state_system->modifyAttribute(timestamp,
+                                             state_system->getQuark(prev, "next"),
+                                             StateValue::SharedPtr(
+                                                     new QuarkStateValue(next)));
+       } else if (hasPrev) {
+               state_system->modifyAttribute(timestamp,
+                                             state_system->getQuark(prev, "next"),
+                                             StateValue::getNullValue());
+       } else if (hasNext) {
+               state_system->modifyAttribute(timestamp,
+                                             state_system->getQuark(next, "prev"),
+                                             StateValue::getNullValue());
+               state_system->modifyAttribute(timestamp, beg,
+                                             StateValue::SharedPtr(
+                                                     new QuarkStateValue(next)));
+       } else {
+               state_system->modifyAttribute(timestamp, beg,
+                                             StateValue::getNullValue());
+       }
+
+       state_system->removeAttribute(timestamp, item);
+}
+
+int get_sequence_length(unsigned long timestamp, Quark beg)
+{
+       int length = 0;
+       Quark it;
+
+       if (get_attribute_value_at_quark(timestamp, &beg, "", it)) {
+               do {
+                       length++;
+               } while (get_attribute_value_at_quark(
+                                timestamp, &it, "next", it));
+       }
+
+       return length;
+}
+
+bool get_interval_value_int(unsigned long start,
+                           unsigned long end,
+                           const Quark *starting_node,
+                           std::string attribute,
+                           int &value)
+{
+       int start_value, end_value;
+
+       if (get_attribute_value_at_int(
+                   start, starting_node, attribute, start_value) &&
+           get_attribute_value_at_int(
+                   end, starting_node, attribute, end_value)) {
+               value = end_value - start_value;
+               return true;
+       }
+       return false;
+}
+
+bool get_interval_value_ulong(unsigned long start,
+                             unsigned long end,
+                             const Quark *starting_node,
+                             std::string attribute,
+                             unsigned long &value)
+{
+       unsigned long start_value, end_value;
+
+       if (get_attribute_value_at_ulong(
+                   start, starting_node, attribute, start_value) &&
+           get_attribute_value_at_ulong(
+                   end, starting_node, attribute, end_value)) {
+               value = end_value - start_value;
+               return true;
+       }
+       return false;
+}
+
+int sequence_to_array(unsigned long timestamp, Quark beg, Quark *arr,
+                     int len)
+{
+       int ret = 0;
+       Quark it;
+
+       if (arr == NULL || len < 1)
+               return 0;
+
+       if (get_attribute_value_at_quark(timestamp, &beg, "", it)) {
+               do {
+                       arr[ret] = it;
+                       ret++;
+               } while (get_attribute_value_at_quark(
+                                timestamp, &it, "next", it) && ret < len);
+       }
+
+       return ret;
+}
+
+int get_global_perf_list(unsigned long timestamp, Quark *arr, int len)
+{
+       std::map<std::string, int> perfs;
+       std::string key;
+       int val;
+       int ret;
+       Quark proc;
+       Quark perf;
+       std::map<std::string, int>::const_iterator iter;
+
+       if (arr == NULL || len < 1)
+               return 0;
+
+       if (get_attribute_value_at_quark(timestamp, NULL, "proc", proc)) {
+               do {
+                       if (get_attribute_value_at_quark(timestamp, &proc,
+                                                        "perf", perf)) {
+                               do {
+                                       get_attribute_value_at_string(timestamp,
+                                                                     &perf,
+                                                                     "key",
+                                                                     key);
+                                       get_attribute_value_at_int(timestamp,
+                                                                  &perf,
+                                                                  "count",
+                                                                  val);
+                                       if (perfs.find(key) != perfs.end())
+                                               perfs[key] += val;
+                                       else
+                                               perfs[key] = val;
+                               } while (get_attribute_value_at_quark(timestamp,
+                                                                     &perf,
+                                                                     "next",
+                                                                     perf));
+                       }
+               } while (get_attribute_value_at_quark(timestamp, &proc, "next",
+                                                     proc));
+       }
+
+       for (iter = perfs.begin(), ret = 0; iter != perfs.end() && ret < len;
+            iter++, ret++) {
+               perf = state_system->getQuark("perf/" + iter->first);
+               modify_attribute(timestamp, &perf, "count", iter->second);
+               arr[ret] = perf;
+       }
+
+       return ret;
+}
+
+int get_global_perf_list_size(unsigned long timestamp)
+{
+       std::set<std::string> perfs;
+       std::string key;
+       int len = 0;
+       Quark proc;
+       Quark perf;
+
+       if (get_attribute_value_at_quark(timestamp, NULL, "proc", proc)) {
+               do {
+                       if (get_attribute_value_at_quark(timestamp, &proc,
+                                                        "perf", perf)) {
+                               do {
+                                       get_attribute_value_at_string(timestamp,
+                                                                     &perf,
+                                                                     "key",
+                                                                     key);
+                                       if (perfs.find(key) == perfs.end()) {
+                                               perfs.insert(key);
+                                               len++;
+                                       }
+                               } while (get_attribute_value_at_quark(timestamp,
+                                                                     &perf,
+                                                                     "next",
+                                                                     perf));
+                       }
+               } while (get_attribute_value_at_quark(timestamp, &proc, "next",
+                                                     proc));
+       }
+
+       return len;
+}
+
+int get_number_of_opened_files(unsigned long timestamp, Quark proc)
+{
+       int len = 0;
+       Quark fh;
+       int fd;
+
+       if (get_attribute_value_at_quark(timestamp, &proc,
+                                        "files_history/current", fh)) {
+               do {
+                       get_attribute_value_at_int(timestamp, &fh, "file/fd",
+                                                  fd);
+                       if (fd != -1)
+                               len++;
+               } while (get_attribute_value_at_quark(timestamp, &fh, "next",
+                                                     fh));
+       }
+
+       return len;
+}
+
+int get_opened_files(unsigned long timestamp, Quark proc, Quark *arr, int len)
+{
+       int ret = 0;
+       Quark file, fh;
+       int fd;
+
+       if (arr == NULL || len < 1)
+               return 0;
+
+       if (get_attribute_value_at_quark(timestamp, &proc,
+                                        "files_history/current", fh)) {
+               do {
+                       file = state_system->getQuark(fh, "file");
+                       get_attribute_value_at_int(timestamp, &file, "fd",
+                                                  fd);
+                       if (fd != -1) {
+                               arr[ret] = file;
+                               ret++;
+                       }
+                       if (ret == len)
+                               break;
+               } while (get_attribute_value_at_quark(timestamp, &fh, "next",
+                                                     fh));
+       }
+
+       return ret;
+}
index fd9a367211d799bbf7f5fac145fb06eb6bbb2b0b..4aad99290b4a0ced57a2e3cac62bf0bff8dc9de2 100644 (file)
 #define _COMMON_H
 
 #include <semaphore.h>
+extern "C" {
 #include <babeltrace/ctf/events.h>
+}
+#include <state/IntervalHistoryProvider.hpp>
+#include <state/StateSystem.hpp>
+#include <state/statevalue/StateValue.hpp>
+#include <state/statevalue/IntegerStateValue.hpp>
+#include <state/statevalue/StringStateValue.hpp>
+#include <state/statevalue/NullStateValue.hpp>
+#include <state/statevalue/QuarkStateValue.hpp>
+#include <sstream>
+#include <map>
+#include <vector>
+#include <set>
+
 #include "lttngtoptypes.h"
 #include "cputop.h"
 
+using namespace State;
+
 #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 */
-GHashTable *global_perf_liszt;
-
-struct lttngtop *data;
+extern StateSystem *state_system;
+extern std::set<Quark> modified_quarks;
+const unsigned long refresh_display = 1 * NSEC_PER_SEC;
+extern unsigned long last_display_update;
+extern unsigned long first_display_update;
 
-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);
+extern sem_t goodtodisplay, goodtoupdate, timer, pause_sem, end_trace_sem, bootstrap;
 
-struct processtop *get_proc_pid(struct lttngtop *ctx, int tid, int pid,
-               unsigned long timestamp);
+bool find_process_tid(int tid, Quark &ret_proc_quark);
+Quark add_proc(int tid, std::string comm, unsigned long timestamp);
+void update_proc(unsigned long timestamp, Quark proc, int pid, int tid,
+                int ppid, char *comm);
+void add_thread(unsigned long timestamp, Quark parent, Quark thread);
+Quark get_proc(int tid, char *comm, unsigned long timestamp);
+Quark get_proc_pid(int pid, int tid, unsigned long timestamp);
+void death_proc(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);
-void reset_global_counters(void);
+Quark add_cpu(int cpu, unsigned long timestamp);
+Quark get_cpu(int cpu, unsigned long timestamp);
+void update_state_on_refresh(unsigned long start, unsigned long end);
+Quark get_perf_counter(unsigned long timestamp, Quark root, std::string name);
 
 /* common field access functions */
-uint64_t get_cpu_id(const struct bt_ctf_event *event);
-uint64_t get_context_tid(const struct bt_ctf_event *event);
-uint64_t get_context_pid(const struct bt_ctf_event *event);
-uint64_t get_context_ppid(const struct bt_ctf_event *event);
+int get_cpu_id(const struct bt_ctf_event *event);
+int get_context_tid(const struct bt_ctf_event *event);
+int get_context_pid(const struct bt_ctf_event *event);
+int get_context_ppid(const struct bt_ctf_event *event);
 char *get_context_comm(const struct bt_ctf_event *event);
 
-enum bt_cb_ret handle_statedump_process_state(struct bt_ctf_event *call_data,
-                                             void *private_data);
+enum bt_cb_ret handle_statedump_process_state(
+       struct bt_ctf_event *call_data, void *private_data);
+
+std::string path_name_from_cpuid(int cpuid);
+std::string thread_path_name_from_tid(int tid);
+std::string path_name_from_tid(int tid);
+std::string path_name_from_fd(int fd);
+
+void update_file_on_refresh(Quark proc, Quark file, unsigned long end);
+void update_proc_on_refresh(Quark proc, unsigned long start, unsigned long end);
+
+void modify_attribute(unsigned long timestamp, const Quark *starting_node,
+                     std::string attribute, int value);
+void modify_attribute(unsigned long timestamp, const Quark *starting_node,
+                     std::string attribute, Quark value);
+void modify_attribute(unsigned long timestamp, const Quark *starting_node,
+                     std::string attribute, char *value);
+void modify_attribute(unsigned long timestamp, const Quark *starting_node,
+                     std::string attribute, unsigned long value);
+void modify_attribute(unsigned long timestamp, const Quark *starting_node,
+                     std::string attribute, std::string value);
+void nullify_attribute(unsigned long timestamp, const Quark *starting_node,
+                      std::string attribute);
+void increment_attribute(unsigned long timestamp, const Quark *starting_node,
+                        std::string attribute);
+void increase_attribute(unsigned long timestamp, const Quark *starting_node,
+                       std::string attribute, int amount);
+void increase_attribute(unsigned long timestamp, const Quark *starting_node,
+                       std::string attribute, unsigned long amount);
+void decrement_attribute(unsigned long timestamp, const Quark *starting_node,
+                        std::string attribute);
+void decrease_attribute(unsigned long timestamp, const Quark *starting_node,
+                       std::string attribute, int amount);
+void decrease_attribute(unsigned long timestamp, const Quark *starting_node,
+                       std::string attribute, unsigned long amount);
+bool get_current_attribute_value_int(const Quark *starting_node,
+                                    std::string attribute, int &value);
+bool get_current_attribute_value_ulong(const Quark *starting_node,
+                                      std::string attribute, unsigned long &value);
+bool get_current_attribute_value_quark(const Quark *starting_node,
+                                      std::string attribute, Quark &value);
+bool get_current_attribute_value_string(const Quark *starting_node,
+                                       std::string attribute, std::string &value);
+bool get_attribute_value_at_int(unsigned long timestamp,
+                               const Quark *starting_node,
+                               std::string attribute,
+                               int &value);
+bool get_attribute_value_at_ulong(unsigned long timestamp,
+                                 const Quark *starting_node,
+                                 std::string attribute,
+                                 unsigned long &value);
+bool get_attribute_value_at_quark(unsigned long timestamp,
+                                 const Quark *starting_node,
+                                 std::string attribute,
+                                 Quark &value);
+bool get_attribute_value_at_string(unsigned long timestamp,
+                                  const Quark *starting_node,
+                                  std::string attribute,
+                                  std::string &value);
+bool get_interval_value_int(unsigned long start,
+                           unsigned long end,
+                           const Quark *starting_node,
+                           std::string attribute,
+                           int &value);
+bool get_interval_value_ulong(unsigned long start,
+                             unsigned long end,
+                             const Quark *starting_node,
+                             std::string attribute,
+                             unsigned long &value);
+void add_in_sequence(unsigned long timestamp, Quark item, Quark beg);
+void remove_from_sequence(unsigned long timestamp, Quark item, Quark beg);
+int get_sequence_length(unsigned long timestamp, Quark beg);
+int sequence_to_array(unsigned long timestamp, Quark beg, Quark *arr,
+                     int len);
+int get_global_perf_list(unsigned long timestamp, Quark *arr, int len);
+int get_global_perf_list_size(unsigned long timestamp);
+int get_number_of_opened_files(unsigned long timestamp, Quark proc);
+int get_opened_files(unsigned long timestamp, Quark proc, Quark *arr, int len);
 
 #endif /* _COMMON_H */
diff --git a/src/cputop.c b/src/cputop.c
deleted file mode 100644 (file)
index eb7afb3..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2011-2012 Julien Desfossez
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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)
-{
-       const 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;
-       }
-
-       cpu_id = get_cpu_id(call_data);
-
-       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)
-{
-       const 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 field\n");
-               goto error;
-       }
-
-       death_proc(&lttngtop, tid, comm, timestamp);
-
-       return BT_CB_OK;
-
-error:
-       return BT_CB_ERROR_STOP;
-
-}
-
diff --git a/src/cputop.cpp b/src/cputop.cpp
new file mode 100644 (file)
index 0000000..4fde9a8
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2011-2012 Julien Desfossez
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+extern "C" {
+#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)
+{
+       Quark cpu_quark;
+       Quark current_task_quark;
+       bool current_task_found;
+       int current_task_pid;
+       int current_task_tid;
+       unsigned long elapsed;
+       unsigned long task_start;
+       bool current_task_threadparent_found;
+       Quark current_task_threadparent;
+
+       cpu_quark = get_cpu(cpu, timestamp);
+       current_task_found = get_current_attribute_value_quark(&cpu_quark,
+               "current_task", current_task_quark);
+
+       if (current_task_found) {
+               get_current_attribute_value_int(&current_task_quark, "pid",
+                       current_task_pid);
+               if (current_task_pid == prev_pid) {
+                       get_current_attribute_value_ulong(&cpu_quark,
+                               "task_start", task_start);
+                       elapsed = timestamp - task_start;
+                       increase_attribute(timestamp, &current_task_quark,
+                               "totalcpunsec", elapsed);
+                       increase_attribute(timestamp, &current_task_quark,
+                               "threadstotalcpunsec", elapsed);
+                       get_current_attribute_value_int(&current_task_quark,
+                               "tid", current_task_tid);
+                       if (current_task_tid != current_task_pid) {
+                               current_task_threadparent_found =
+                                       get_current_attribute_value_quark(
+                                               &current_task_quark,
+                                               "threadparent",
+                                               current_task_threadparent);
+                               if (current_task_threadparent_found)
+                                       increase_attribute(timestamp,
+                                               &current_task_threadparent,
+                                               "threadstotalcpuns", elapsed);
+                       }
+               }
+       }
+
+       if (next_pid != 0)
+               modify_attribute(timestamp, &cpu_quark, "current_task",
+                                get_proc(next_pid, next_comm, timestamp));
+       else
+               nullify_attribute(timestamp, &cpu_quark, "current_task");
+
+       modify_attribute(timestamp, &cpu_quark, "task_start", timestamp);
+}
+
+enum bt_cb_ret handle_sched_switch(struct bt_ctf_event *call_data,
+               void *private_data)
+{
+       const 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;
+       }
+
+       cpu_id = get_cpu_id(call_data);
+
+       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)
+{
+       const 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 field\n");
+               goto error;
+       }
+
+       death_proc(tid, comm, timestamp);
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+
+}
+
index c1466446b5704ad9d36bc07b532a0065d5eec501..e782c7f9696f7797b942cf70b02d66986a0c8820 100644 (file)
 #ifndef _LTTNGTOP_H
 #define _LTTNGTOP_H
 
+extern "C" {
 #include <babeltrace/babeltrace.h>
 #include <babeltrace/ctf/callbacks.h>
+}
 #include <inttypes.h>
 #include <glib.h>
 
diff --git a/src/cursesdisplay.c b/src/cursesdisplay.c
deleted file mode 100644 (file)
index beb7bdf..0000000
+++ /dev/null
@@ -1,1586 +0,0 @@
-/*
- * Copyright (C) 2011-2012 Julien Desfossez
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 "iostreamtop.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 *pref_panel_window = NULL;
-PANEL *pref_panel, *main_panel;
-
-int pref_panel_visible = 0;
-int pref_line_selected = 0;
-int pref_current_sort = 0;
-
-int last_display_index, currently_displayed_index;
-
-struct processtop *selected_process = NULL;
-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 max_center_lines;
-GPtrArray *selected_processes;
-
-pthread_t keyboard_thread;
-
-struct header_view cputopview[4];
-struct header_view iostreamtopview[3];
-struct header_view fileview[3];
-
-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 */
-               init_pair(6, COLOR_WHITE, COLOR_GREEN); /* selected process */
-       }
-       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, "%d", 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);
-}
-
-int process_selected(struct processtop *process)
-{
-       int i;
-       struct processtop *stored_process;
-
-       for (i = 0; i < selected_processes->len; i++) {
-               stored_process = g_ptr_array_index(selected_processes, i);
-               if (!stored_process)
-                       return 0;
-               if (stored_process->tid == process->tid)
-                       return 1;
-       }
-       return 0;
-}
-
-void update_selected_processes()
-{
-       int i;
-       struct processtop *stored_process;
-
-       if (process_selected(selected_process)) {
-               for (i = 0; i < selected_processes->len; i++) {
-                       stored_process = g_ptr_array_index(selected_processes, i);
-                       if (!stored_process)
-                               return;
-                       if (stored_process->tid == selected_process->tid)
-                               g_ptr_array_remove(selected_processes,
-                                               stored_process);
-                       print_log("Process removed");
-               }
-       } else {
-                       g_ptr_array_add(selected_processes, selected_process);
-               print_log("Process added");
-       }
-}
-
-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, "F4", "IOTop  ", current_view == iostream);
-       print_key(footer, "Enter", "Details  ", current_view == process_details);
-       print_key(footer, "Space", "Highlight  ", 0);
-       print_key(footer, "q", "Quit ", 0);
-       print_key(footer, "r", "Pref  ", 0);
-       print_key(footer, "t", "Threads  ", toggle_threads);
-       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, "Threads");
-       mvwprintw(header, 3, 4, "FDs");
-       wattroff(header, A_BOLD);
-       wrefresh(header);
-}
-
-struct tm format_timestamp(uint64_t timestamp)
-{
-       struct tm tm;
-       uint64_t ts_sec = 0, ts_nsec;
-       time_t time_s;
-
-       ts_nsec = timestamp;
-       ts_sec += ts_nsec / NSEC_PER_SEC;
-       ts_nsec = ts_nsec % NSEC_PER_SEC;
-
-       time_s = (time_t) ts_sec;
-
-       localtime_r(&time_s, &tm);
-
-       return tm;
-}
-
-static void scale_unit(uint64_t bytes, char *ret)
-{
-       if (bytes >= 1000000000)
-               sprintf(ret, "%" PRIu64 "G", bytes/1000000000);
-       if (bytes >= 1000000)
-               sprintf(ret, "%" PRIu64 "M", bytes/1000000);
-       else if (bytes >= 1000)
-               sprintf(ret, "%" PRIu64 "K", bytes/1000);
-       else
-               sprintf(ret, "%" PRIu64, bytes);
-}
-
-uint64_t total_io()
-{
-       int i;
-       struct processtop *tmp;
-       uint64_t total = 0;
-
-       for (i = 0; i < data->process_table->len; i++) {
-               tmp = g_ptr_array_index(data->process_table, i);
-               total += tmp->fileread;
-               total += tmp->filewrite;
-       }
-
-       return total;
-}
-
-void update_header()
-{
-       struct tm start, end;
-       uint64_t ts_nsec_start, ts_nsec_end;
-       char io[4];
-
-       ts_nsec_start = data->start % NSEC_PER_SEC;
-       start = format_timestamp(data->start);
-
-       ts_nsec_end = data->end % NSEC_PER_SEC;
-       end = format_timestamp(data->end);
-
-       werase(header);
-       box(header, 0 , 0);
-       set_window_title(header, "Statistics for interval ");
-       wattron(header, A_BOLD);
-
-       wprintw(header, "[%02d:%02d:%02d.%09" PRIu64 ", %02d:%02d:%02d.%09" PRIu64 "[",
-               start.tm_hour, start.tm_min, start.tm_sec, ts_nsec_start,
-               end.tm_hour, end.tm_min, end.tm_sec, ts_nsec_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, "Threads", data->nbthreads, data->nbnewthreads,
-                       -1*(data->nbdeadthreads));
-       print_headers(3, "FDs", data->nbfiles, data->nbnewfiles,
-                       -1*(data->nbclosedfiles));
-       scale_unit(total_io(), io);
-       mvwprintw(header, 3, 43, "%sB/sec", io);
-       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_tid_desc(gconstpointer p1, gconstpointer p2)
-{
-       struct processtop *n1 = *(struct processtop **)p1;
-       struct processtop *n2 = *(struct processtop **)p2;
-       unsigned long totaln1 = n1->tid;
-       unsigned long totaln2 = n2->tid;
-
-       if (totaln1 < totaln2)
-               return 1;
-       if (totaln1 == totaln2)
-               return 0;
-       return -1;
-}
-
-gint sort_by_pid_desc(gconstpointer p1, gconstpointer p2)
-{
-       struct processtop *n1 = *(struct processtop **)p1;
-       struct processtop *n2 = *(struct processtop **)p2;
-       unsigned long totaln1 = n1->pid;
-       unsigned long totaln2 = n2->pid;
-
-       if (totaln1 < totaln2)
-               return 1;
-       if (totaln1 == totaln2)
-               return 0;
-       return -1;
-}
-
-gint sort_by_process_read_desc(gconstpointer p1, gconstpointer p2)
-{
-       struct processtop *n1 = *(struct processtop **)p1;
-       struct processtop *n2 = *(struct processtop **)p2;
-       unsigned long totaln1 = n1->fileread;
-       unsigned long totaln2 = n2->fileread;
-
-       if (totaln1 < totaln2)
-               return 1;
-       if (totaln1 == totaln2)
-               return 0;
-       return -1;
-}
-
-gint sort_by_process_write_desc(gconstpointer p1, gconstpointer p2)
-{
-       struct processtop *n1 = *(struct processtop **)p1;
-       struct processtop *n2 = *(struct processtop **)p2;
-       unsigned long totaln1 = n1->filewrite;
-       unsigned long totaln2 = n2->filewrite;
-
-       if (totaln1 < totaln2)
-               return 1;
-       if (totaln1 == totaln2)
-               return 0;
-       return -1;
-}
-
-gint sort_by_process_total_desc(gconstpointer p1, gconstpointer p2)
-{
-       struct processtop *n1 = *(struct processtop **)p1;
-       struct processtop *n2 = *(struct processtop **)p2;
-       unsigned long totaln1 = n1->totalfilewrite + n1->totalfileread;
-       unsigned long totaln2 = n2->totalfilewrite + n2->totalfileread;
-
-       if (totaln1 < totaln2)
-               return 1;
-       if (totaln1 == totaln2)
-               return 0;
-       return -1;
-}
-
-gint sort_by_file_read_desc(gconstpointer p1, gconstpointer p2)
-{
-       struct files *n1 = *(struct files **)p1;
-       struct files *n2 = *(struct files **)p2;
-       unsigned long totaln1;
-       unsigned long totaln2;
-
-       totaln1 = n1->read;
-       totaln2 = n2->read;
-
-       if (totaln1 < totaln2)
-               return 1;
-       if (totaln1 == totaln2)
-               return 0;
-       return -1;
-}
-
-gint sort_by_file_write_desc(gconstpointer p1, gconstpointer p2)
-{
-       struct files *n1 = *(struct files **)p1;
-       struct files *n2 = *(struct files **)p2;
-       unsigned long totaln1;
-       unsigned long totaln2;
-
-       totaln1 = n1->write;
-       totaln2 = n2->write;
-
-       if (totaln1 < totaln2)
-               return 1;
-       if (totaln1 == totaln2)
-               return 0;
-       return -1;
-}
-
-gint sort_by_file_fd_desc(gconstpointer p1, gconstpointer p2)
-{
-       struct files *n1 = *(struct files **)p1;
-       struct files *n2 = *(struct files **)p2;
-       unsigned long totaln1;
-       unsigned long totaln2;
-
-       totaln1 = n1->fd;
-       totaln2 = n2->fd;
-
-       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;
-       int column;
-
-       elapsed = data->end - data->start;
-       maxcputime = elapsed * data->cpu_table->len / 100.0;
-
-       if (cputopview[0].sort == 1)
-               g_ptr_array_sort(data->process_table, sort_by_cpu_desc);
-       else if (cputopview[1].sort == 1)
-               g_ptr_array_sort(data->process_table, sort_by_pid_desc);
-       else if (cputopview[2].sort == 1)
-               g_ptr_array_sort(data->process_table, sort_by_tid_desc);
-       else if (cputopview[3].sort == 1)
-               g_ptr_array_sort(data->process_table, sort_by_cpu_desc);
-       else
-               g_ptr_array_sort(data->process_table, sort_by_cpu_desc);
-
-       set_window_title(center, "CPU Top");
-       wattron(center, A_BOLD);
-       column = 1;
-       for (i = 0; i < 4; i++) {
-               if (cputopview[i].sort) {
-                       wattron(center, A_UNDERLINE);
-                       pref_current_sort = i;
-               }
-               mvwprintw(center, 1, column, cputopview[i].title);
-               wattroff(center, A_UNDERLINE);
-               column += 10;
-       }
-       wattroff(center, A_BOLD);
-
-       max_center_lines = LINES - 5 - 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 (tmp->pid != tmp->tid)
-                       if (toggle_threads == -1)
-                               continue;
-
-               if (process_selected(tmp)) {
-                       wattron(center, COLOR_PAIR(6));
-                       mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
-               }
-               if (current_line == selected_line) {
-                       selected_process = tmp;
-                       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);
-               /* PID */
-               mvwprintw(center, current_line + header_offset, 11, "%d", tmp->pid);
-               /* TID */
-               mvwprintw(center, current_line + header_offset, 21, "%d", tmp->tid);
-               /* NAME */
-               mvwprintw(center, current_line + header_offset, 31, "%s", tmp->comm);
-               wattroff(center, COLOR_PAIR(6));
-               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", key);
-       mvwprintw(center, line, 30, " ");
-       wattroff(center, A_BOLD);
-}
-
-void update_process_details()
-{
-       unsigned long elapsed;
-       double maxcputime;
-       struct processtop *tmp;
-       struct files *file_tmp;
-       int i, j = 0;
-       char unit[4];
-       char filename_buf[COLS];
-       int line = 1;
-       int column;
-       GPtrArray *newfilearray = g_ptr_array_new();
-       GHashTableIter iter;
-       struct perfcounter *perfn1, *perfn2;
-       gpointer key;
-
-       set_window_title(center, "Process details");
-
-
-       tmp = find_process_tid(data,
-                       selected_process->tid,
-                       selected_process->comm);
-       elapsed = data->end - data->start;
-       maxcputime = elapsed * data->cpu_table->len / 100.0;
-
-       print_key_title("Name", line++);
-       wprintw(center, "%s", selected_process->comm);
-       print_key_title("TID", line++);
-       wprintw(center, "%d", selected_process->tid);
-       if (!tmp) {
-               print_key_title("Does not exit at this time", 3);
-               return;
-       }
-
-       print_key_title("PID", line++);
-       wprintw(center, "%d", tmp->pid);
-       print_key_title("PPID", line++);
-       wprintw(center, "%d", tmp->ppid);
-       print_key_title("CPU", line++);
-       wprintw(center, "%1.2f %%", tmp->totalcpunsec/maxcputime);
-
-       print_key_title("READ B/s", line++);
-       scale_unit(tmp->fileread, unit);
-       wprintw(center, "%s", unit);
-
-       print_key_title("WRITE B/s", line++);
-       scale_unit(tmp->filewrite, unit);
-       wprintw(center, "%s", unit);
-
-       g_hash_table_iter_init(&iter, global_perf_liszt);
-       while (g_hash_table_iter_next (&iter, &key, (gpointer) &perfn1)) {
-               print_key_title((char *) key, line++);
-               perfn2 = g_hash_table_lookup(tmp->perf, (char *) key);
-               wprintw(center, "%d", perfn2 ? perfn2->count : 0);
-       }
-       line++;
-
-       wattron(center, A_BOLD);
-       column = 1;
-       for (i = 0; i < 3; i++) {
-               if (fileview[i].sort) {
-                       pref_current_sort = i;
-                       wattron(center, A_UNDERLINE);
-               }
-               mvwprintw(center, line, column, fileview[i].title);
-               wattroff(center, A_UNDERLINE);
-               column += 10;
-       }
-       mvwprintw(center, line++, column, "FILENAME");
-       wattroff(center, A_BOLD);
-
-       /*
-        * since the process_files_table array could contain NULL file structures,
-        * and that the positions inside the array is important (it is the FD), we
-        * need to create a temporary array that we can sort.
-        */
-       for (i = 0; i < tmp->process_files_table->len; i++) {
-               file_tmp = g_ptr_array_index(tmp->process_files_table, i);
-               if (file_tmp)
-                       g_ptr_array_add(newfilearray, file_tmp);
-       }
-
-       if (fileview[0].sort == 1)
-               g_ptr_array_sort(newfilearray, sort_by_file_fd_desc);
-       else if (fileview[1].sort == 1)
-               g_ptr_array_sort(newfilearray, sort_by_file_read_desc);
-       else if (fileview[2].sort == 1)
-               g_ptr_array_sort(newfilearray, sort_by_file_write_desc);
-       else
-               g_ptr_array_sort(newfilearray, sort_by_file_read_desc);
-
-       for (i = selected_line; i < newfilearray->len &&
-                       i < (selected_line + max_center_lines - line + 2); i++) {
-               file_tmp = g_ptr_array_index(newfilearray, i);
-               if (!file_tmp)
-                       continue;
-               mvwprintw(center, line + j, 1, "%d", file_tmp->fd);
-               scale_unit(file_tmp->read, unit);
-               mvwprintw(center, line + j, 11, "%s", unit);
-               scale_unit(file_tmp->write, unit);
-               mvwprintw(center, line + j, 21, "%s", unit);
-               snprintf(filename_buf, COLS - 25, "%s", file_tmp->name);
-               mvwprintw(center, line + j, 31, "%s", filename_buf);
-               j++;
-       }
-       g_ptr_array_free(newfilearray, TRUE);
-}
-
-void update_perf()
-{
-       int i;
-       int nblinedisplayed = 0;
-       int current_line = 0;
-       struct processtop *tmp;
-       int header_offset = 2;
-       int perf_row = 40;
-       struct perfcounter *perfn1, *perfn2;
-       char *perf_key = NULL;
-       int value;
-       GHashTableIter iter;
-       gpointer key;
-
-       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;
-       g_hash_table_iter_init(&iter, global_perf_liszt);
-       while (g_hash_table_iter_next (&iter, &key, (gpointer) &perfn1)) {
-               if (perfn1->visible) {
-                       if (perfn1->sort) {
-                               /* pref_current_sort = i; */
-                               wattron(center, A_UNDERLINE);
-                       }
-                       /* + 5 to strip the "perf_" prefix */
-                       mvwprintw(center, 1, perf_row, "%s",
-                                       (char *) key + 5);
-                       wattroff(center, A_UNDERLINE);
-                       perf_row += 20;
-               }
-               if (perfn1->sort) {
-                       perf_key = (char *) key;
-               }
-       }
-       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++) {
-               tmp = g_ptr_array_index(data->process_table, i);
-               if (tmp->pid != tmp->tid)
-                       if (toggle_threads == -1)
-                               continue;
-
-               if (process_selected(tmp)) {
-                       wattron(center, COLOR_PAIR(6));
-                       mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
-               }
-               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);
-
-               g_hash_table_iter_init(&iter, global_perf_liszt);
-
-               perf_row = 40;
-               while (g_hash_table_iter_next (&iter, &key, (gpointer) &perfn1)) {
-                       if (perfn1->visible) {
-                               perfn2 = g_hash_table_lookup(tmp->perf, (char *) key);
-                               if (perfn2)
-                                       value = perfn2->count;
-                               else
-                                       value = 0;
-                               mvwprintw(center, current_line + header_offset,
-                                               perf_row, "%d", value);
-                               perf_row += 20;
-                       }
-               }
-
-               wattroff(center, COLOR_PAIR(6));
-               wattroff(center, COLOR_PAIR(5));
-               nblinedisplayed++;
-               current_line++;
-       }
-}
-
-void update_iostream()
-{
-       int i;
-       int header_offset = 2;
-       struct processtop *tmp;
-       int nblinedisplayed = 0;
-       int current_line = 0;
-       int total = 0;
-       char unit[4];
-       int column;
-
-       set_window_title(center, "IO Top");
-       wattron(center, A_BOLD);
-       mvwprintw(center, 1, 1, "PID");
-       mvwprintw(center, 1, 11, "TID");
-       mvwprintw(center, 1, 22, "NAME");
-       column = 40;
-       for (i = 0; i < 3; i++) {
-               if (iostreamtopview[i].sort) {
-                       pref_current_sort = i;
-                       wattron(center, A_UNDERLINE);
-               }
-               mvwprintw(center, 1, column, iostreamtopview[i].title);
-               wattroff(center, A_UNDERLINE);
-               column += 12;
-       }
-       wattroff(center, A_BOLD);
-       wattroff(center, A_UNDERLINE);
-
-       if (iostreamtopview[0].sort == 1)
-               g_ptr_array_sort(data->process_table, sort_by_process_read_desc);
-       else if (iostreamtopview[1].sort == 1)
-               g_ptr_array_sort(data->process_table, sort_by_process_write_desc);
-       else if (iostreamtopview[2].sort == 1)
-               g_ptr_array_sort(data->process_table, sort_by_process_total_desc);
-       else
-               g_ptr_array_sort(data->process_table, sort_by_process_total_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 (tmp->pid != tmp->tid)
-                       if (toggle_threads == -1)
-                               continue;
-
-               if (process_selected(tmp)) {
-                       wattron(center, COLOR_PAIR(6));
-                       mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
-               }
-               if (current_line == selected_line) {
-                       selected_process = tmp;
-                       wattron(center, COLOR_PAIR(5));
-                       mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
-               }
-               /* TGID */
-               mvwprintw(center, current_line + header_offset, 1, "%d", tmp->pid);
-               /* PID */
-               mvwprintw(center, current_line + header_offset, 11, "%d", tmp->tid);
-               /* NAME */
-               mvwprintw(center, current_line + header_offset, 22, "%s", tmp->comm);
-
-               /* READ (bytes/sec) */
-               scale_unit(tmp->fileread, unit);
-               mvwprintw(center, current_line + header_offset, 40, "%s", unit);
-
-               /* WRITE (bytes/sec) */
-               scale_unit(tmp->filewrite, unit);
-               mvwprintw(center, current_line + header_offset, 52, "%s", unit);
-
-               /* TOTAL STREAM */
-               total = tmp->totalfileread + tmp->totalfilewrite;
-
-               scale_unit(total, unit);
-               mvwprintw(center, current_line + header_offset, 64, "%s", unit);
-
-               wattroff(center, COLOR_PAIR(6));
-               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 iostream:
-               update_iostream();
-               break;
-       case tree:
-               update_cputop_display();
-               break;
-       default:
-               break;
-       }
-       update_panels();
-       doupdate();
-       sem_post(&update_display_sem);
-}
-
-void update_process_detail_sort(int *line_selected)
-{
-       int i;
-       int size;
-
-       size = 3;
-
-       if (*line_selected > (size - 1))
-               *line_selected = size - 1;
-       else if (*line_selected < 0)
-               *line_selected = 0;
-
-       if (fileview[*line_selected].sort == 1)
-               fileview[*line_selected].reverse = 1;
-       for (i = 0; i < size; i++)
-               fileview[i].sort = 0;
-       fileview[*line_selected].sort = 1;
-}
-
-void update_process_detail_pref(int *line_selected, int toggle_view, int toggle_sort)
-{
-       int i;
-       int size;
-
-       if (!data)
-               return;
-       if (pref_panel_window) {
-               del_panel(pref_panel);
-               delwin(pref_panel_window);
-       }
-       size = 3;
-
-       pref_panel_window = create_window(size + 2, 30, 10, 10);
-       pref_panel = new_panel(pref_panel_window);
-
-       werase(pref_panel_window);
-       box(pref_panel_window, 0 , 0);
-       set_window_title(pref_panel_window, "Process Detail Preferences ");
-       wattron(pref_panel_window, A_BOLD);
-       mvwprintw(pref_panel_window, size + 1, 1,
-                       " 's' : sort, space : toggle");
-       wattroff(pref_panel_window, A_BOLD);
-
-       if (*line_selected > (size - 1))
-               *line_selected = size - 1;
-       else if (*line_selected < 0)
-               *line_selected = 0;
-       if (toggle_sort == 1) {
-               update_process_detail_sort(line_selected);
-               update_current_view();
-       }
-
-       for (i = 0; i < size; i++) {
-               if (i == *line_selected) {
-                       wattron(pref_panel_window, COLOR_PAIR(5));
-                       mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
-               }
-               if (fileview[i].sort == 1)
-                       wattron(pref_panel_window, A_BOLD);
-               mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
-                               fileview[i].title);
-               wattroff(pref_panel_window, A_BOLD);
-               wattroff(pref_panel_window, COLOR_PAIR(5));
-
-       }
-       update_panels();
-       doupdate();
-}
-
-void update_iostream_sort(int *line_selected)
-{
-       int i;
-       int size;
-
-       size = 3;
-       if (*line_selected > (size - 1))
-               *line_selected = size - 1;
-       else if (*line_selected < 0)
-               *line_selected = 0;
-       if (iostreamtopview[*line_selected].sort == 1)
-               iostreamtopview[*line_selected].reverse = 1;
-       for (i = 0; i < size; i++)
-               iostreamtopview[i].sort = 0;
-       iostreamtopview[*line_selected].sort = 1;
-
-}
-
-void update_iostream_pref(int *line_selected, int toggle_view, int toggle_sort)
-{
-       int i;
-       int size;
-
-       if (!data)
-               return;
-       if (pref_panel_window) {
-               del_panel(pref_panel);
-               delwin(pref_panel_window);
-       }
-       size = 3;
-
-       pref_panel_window = create_window(size + 2, 30, 10, 10);
-       pref_panel = new_panel(pref_panel_window);
-
-       werase(pref_panel_window);
-       box(pref_panel_window, 0 , 0);
-       set_window_title(pref_panel_window, "IOTop Preferences ");
-       wattron(pref_panel_window, A_BOLD);
-       mvwprintw(pref_panel_window, size + 1, 1,
-                       " 's' : sort, space : toggle");
-       wattroff(pref_panel_window, A_BOLD);
-
-       if (*line_selected > (size - 1))
-               *line_selected = size - 1;
-       else if (*line_selected < 0)
-               *line_selected = 0;
-       if (toggle_sort == 1) {
-               update_iostream_sort(line_selected);
-               update_current_view();
-       }
-
-       for (i = 0; i < size; i++) {
-               if (i == *line_selected) {
-                       wattron(pref_panel_window, COLOR_PAIR(5));
-                       mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
-               }
-               if (iostreamtopview[i].sort == 1)
-                       wattron(pref_panel_window, A_BOLD);
-               mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
-                               iostreamtopview[i].title);
-               wattroff(pref_panel_window, A_BOLD);
-               wattroff(pref_panel_window, COLOR_PAIR(5));
-
-       }
-       update_panels();
-       doupdate();
-}
-
-void update_cpu_sort(int *line_selected)
-{
-       int i;
-       int size = 3;
-
-       if (*line_selected > (size - 1))
-               *line_selected = size - 1;
-       else if (*line_selected < 0)
-               *line_selected = 0;
-
-       /* special case, we don't support sorting by procname for now */
-       if (*line_selected != 3) {
-               if (cputopview[*line_selected].sort == 1)
-                       cputopview[*line_selected].reverse = 1;
-               for (i = 0; i < size; i++)
-                       cputopview[i].sort = 0;
-               cputopview[*line_selected].sort = 1;
-       }
-}
-
-void update_cpu_pref(int *line_selected, int toggle_view, int toggle_sort)
-{
-       int i;
-       int size;
-
-       if (!data)
-               return;
-       if (pref_panel_window) {
-               del_panel(pref_panel);
-               delwin(pref_panel_window);
-       }
-       size = 4;
-
-       pref_panel_window = create_window(size + 2, 30, 10, 10);
-       pref_panel = new_panel(pref_panel_window);
-
-       werase(pref_panel_window);
-       box(pref_panel_window, 0 , 0);
-       set_window_title(pref_panel_window, "CPUTop Preferences ");
-       wattron(pref_panel_window, A_BOLD);
-       mvwprintw(pref_panel_window, size + 1, 1,
-                       " 's' : sort, space : toggle");
-       wattroff(pref_panel_window, A_BOLD);
-
-       if (*line_selected > (size - 1))
-               *line_selected = size - 1;
-       else if (*line_selected < 0)
-               *line_selected = 0;
-       if (toggle_sort == 1) {
-               update_cpu_sort(line_selected);
-               update_current_view();
-       }
-
-       for (i = 0; i < size; i++) {
-               if (i == *line_selected) {
-                       wattron(pref_panel_window, COLOR_PAIR(5));
-                       mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
-               }
-               if (cputopview[i].sort == 1)
-                       wattron(pref_panel_window, A_BOLD);
-               mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
-                               cputopview[i].title);
-               wattroff(pref_panel_window, A_BOLD);
-               wattroff(pref_panel_window, COLOR_PAIR(5));
-
-       }
-       update_panels();
-       doupdate();
-}
-
-void update_perf_sort(int *line_selected)
-{
-       int i;
-       struct perfcounter *perf;
-       GList *perflist;
-       int size;
-
-       size = g_hash_table_size(global_perf_liszt);
-       if (*line_selected > (size - 1))
-               *line_selected = size - 1;
-       else if (*line_selected < 0)
-               *line_selected = 0;
-
-       i = 0;
-       perflist = g_list_first(g_hash_table_get_keys(global_perf_liszt));
-       while (perflist) {
-               perf = g_hash_table_lookup(global_perf_liszt, perflist->data);
-               if (i != *line_selected)
-                       perf->sort = 0;
-               else
-                       perf->sort = 1;
-               i++;
-               perflist = g_list_next(perflist);
-       }
-}
-
-void update_perf_pref(int *line_selected, int toggle_view, int toggle_sort)
-{
-       int i;
-       struct perfcounter *perf;
-       GList *perflist;
-       int size;
-
-       if (!data)
-               return;
-       if (pref_panel_window) {
-               del_panel(pref_panel);
-               delwin(pref_panel_window);
-       }
-       size = g_hash_table_size(global_perf_liszt);
-
-       pref_panel_window = create_window(size + 2, 30, 10, 10);
-       pref_panel = new_panel(pref_panel_window);
-
-       werase(pref_panel_window);
-       box(pref_panel_window, 0 , 0);
-       set_window_title(pref_panel_window, "Perf Preferences ");
-       wattron(pref_panel_window, A_BOLD);
-       mvwprintw(pref_panel_window, g_hash_table_size(global_perf_liszt) + 1, 1,
-                       " 's' : sort, space : toggle");
-       wattroff(pref_panel_window, A_BOLD);
-
-       if (*line_selected > (size - 1))
-               *line_selected = size - 1;
-       else if (*line_selected < 0)
-               *line_selected = 0;
-
-       if (toggle_sort == 1) {
-               update_perf_sort(line_selected);
-               update_current_view();
-       }
-
-       i = 0;
-       perflist = g_list_first(g_hash_table_get_keys(global_perf_liszt));
-       while (perflist) {
-               perf = g_hash_table_lookup(global_perf_liszt, perflist->data);
-               if (i == *line_selected && toggle_view == 1) {
-                       perf->visible = perf->visible == 1 ? 0:1;
-                       update_current_view();
-               }
-               if (i == *line_selected) {
-                       wattron(pref_panel_window, COLOR_PAIR(5));
-                       mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
-               }
-               if (perf->sort == 1)
-                       wattron(pref_panel_window, A_BOLD);
-               mvwprintw(pref_panel_window, i + 1, 1, "[%c] %s",
-                               perf->visible == 1 ? 'x' : ' ',
-                               (char *) perflist->data + 5);
-               wattroff(pref_panel_window, A_BOLD);
-               wattroff(pref_panel_window, COLOR_PAIR(5));
-               i++;
-               perflist = g_list_next(perflist);
-       }
-       update_panels();
-       doupdate();
-}
-
-int update_preference_panel(int *line_selected, int toggle_view, int toggle_sort)
-{
-       int ret = 0;
-
-       switch(current_view) {
-               case perf:
-                       update_perf_pref(line_selected, toggle_view, toggle_sort);
-                       break;
-               case cpu:
-                       update_cpu_pref(line_selected, toggle_view, toggle_sort);
-                       break;
-               case iostream:
-                       update_iostream_pref(line_selected, toggle_view, toggle_sort);
-                       break;
-               case process_details:
-                       update_process_detail_pref(line_selected, toggle_view, toggle_sort);
-                       break;
-               default:
-                       ret = -1;
-                       break;
-       }
-
-       return ret;
-}
-
-int update_sort(int *line_selected)
-{
-       int ret = 0;
-
-       switch(current_view) {
-               case perf:
-                       update_perf_sort(line_selected);
-                       break;
-               case cpu:
-                       update_cpu_sort(line_selected);
-                       break;
-               case iostream:
-                       update_iostream_sort(line_selected);
-                       break;
-               case process_details:
-                       update_process_detail_sort(line_selected);
-                       break;
-               default:
-                       ret = -1;
-                       break;
-       }
-
-       return ret;
-}
-
-
-void toggle_pref_panel(void)
-{
-       int ret;
-
-       if (pref_panel_visible) {
-               hide_panel(pref_panel);
-               pref_panel_visible = 0;
-       } else {
-               ret = update_preference_panel(&pref_line_selected, 0, 0);
-               if (ret < 0)
-                       return;
-               show_panel(pref_panel);
-               pref_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 'j':
-               case KEY_DOWN:
-                       if (pref_panel_visible) {
-                               pref_line_selected++;
-                               update_preference_panel(&pref_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:
-                       break;
-               case 'k':
-               case KEY_UP:
-                       if (pref_panel_visible) {
-                               if (pref_line_selected > 0)
-                                       pref_line_selected--;
-                               update_preference_panel(&pref_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:
-                       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);
-                               if (toggle_pause > 0) {
-                                       sem_post(&pause_sem);
-                                       update_current_view();
-                                       sem_wait(&pause_sem);
-                               }
-                       }
-
-                       break;
-               case ' ':
-                       if (pref_panel_visible) {
-                               update_preference_panel(&pref_line_selected, 1, 0);
-                       } else {
-                               update_selected_processes();
-                               update_current_view();
-                       }
-                       break;
-               case 's':
-                       if (pref_panel_visible)
-                               update_preference_panel(&pref_line_selected, 0, 1);
-                       break;
-               case '>':
-                       /* perf uses a hashtable, it is ordered backward */
-                       if (current_view == perf) {
-                               pref_current_sort--;
-                       } else if (!pref_panel_visible) {
-                               pref_current_sort++;
-                       }
-                       update_sort(&pref_current_sort);
-                       update_current_view();
-                       break;
-               case '<':
-                       /* perf uses a hashtable, it is ordered backward */
-                       if (current_view == perf) {
-                               pref_current_sort++;
-                       } else if (!pref_panel_visible) {
-                               pref_current_sort--;
-                       }
-                       update_sort(&pref_current_sort);
-                       update_current_view();
-                       break;
-
-               case 13: /* FIXME : KEY_ENTER ?? */
-                       if (pref_panel_visible)
-                               break;
-                       if (current_view != process_details) {
-                               previous_view = current_view;
-                               current_view = process_details;
-                       } else {
-                               current_view = previous_view;
-                               previous_view = process_details;
-                       }
-                       update_current_view();
-                       break;
-
-               case KEY_F(1):
-                       if (pref_panel_visible)
-                               toggle_pref_panel();
-                       current_view = cpu;
-                       selected_line = 0;
-                       update_current_view();
-                       break;
-               case KEY_F(2):
-                       if (pref_panel_visible)
-                               toggle_pref_panel();
-                       current_view = cpu;
-                       selected_line = 0;
-                       update_current_view();
-                       break;
-               case KEY_F(3):
-                       if (pref_panel_visible)
-                               toggle_pref_panel();
-                       current_view = perf;
-                       selected_line = 0;
-                       update_current_view();
-                       break;
-               case KEY_F(4):
-                       if (pref_panel_visible)
-                               toggle_pref_panel();
-                       current_view = iostream;
-                       selected_line = 0;
-                       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 'r':
-                       toggle_pref_panel();
-                       break;
-               /* ESCAPE, but slow to process, don't know why */
-               case 27:
-                       if (pref_panel_visible)
-                               toggle_pref_panel();
-                       else if (current_view == process_details) {
-                               current_view = previous_view;
-                               previous_view = process_details;
-                       }
-                       update_current_view();
-                       break;
-               default:
-                       if (data)
-                               update_current_view();
-                       break;
-               }
-               update_footer();
-       }
-       return NULL;
-}
-
-void init_view_headers()
-{
-       cputopview[0].title = strdup("CPU(%)");
-       cputopview[0].sort = 1;
-       cputopview[1].title = strdup("PID");
-       cputopview[2].title = strdup("TID");
-       cputopview[3].title = strdup("NAME");
-
-       iostreamtopview[0].title = strdup("R (B/sec)");
-       iostreamtopview[1].title = strdup("W (B/sec)");
-       iostreamtopview[2].title = strdup("Total (B)");
-       iostreamtopview[2].sort = 1;
-
-       fileview[0].title = strdup("FD");
-       fileview[1].title = strdup("READ");
-       fileview[1].sort = 1;
-       fileview[2].title = strdup("WRITE");
-}
-
-void init_ncurses()
-{
-       selected_processes = g_ptr_array_new();
-       sem_init(&update_display_sem, 0, 1);
-       init_view_headers();
-       init_screen();
-
-       header = create_window(5, COLS - 1, 0, 0);
-       center = create_window(LINES - 5 - 7, COLS - 1, 5, 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);
-
-       current_view = cpu;
-
-       basic_header();
-       update_footer();
-
-       pthread_create(&keyboard_thread, NULL, handle_keyboard, (void *)NULL);
-}
diff --git a/src/cursesdisplay.cpp b/src/cursesdisplay.cpp
new file mode 100644 (file)
index 0000000..3cd273f
--- /dev/null
@@ -0,0 +1,1797 @@
+/*
+ * Copyright (C) 2011-2012 Julien Desfossez
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 <state/StateSystem.hpp>
+#include <state/statevalue/StateValue.hpp>
+#include <state/statevalue/IntegerStateValue.hpp>
+#include <state/statevalue/StringStateValue.hpp>
+#include <state/statevalue/NullStateValue.hpp>
+#include <state/statevalue/QuarkStateValue.hpp>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include "cursesdisplay.h"
+#include "lttngtoptypes.h"
+#include "iostreamtop.h"
+#include "common.h"
+
+#define DEFAULT_DELAY 15
+#define MAX_LINE_LENGTH 50
+#define MAX_LOG_LINES 4
+
+using namespace State;
+
+enum view_list current_view;
+enum view_list previous_view;
+
+/* to prevent concurrent updates of the different windows */
+sem_t update_display_sem;
+
+char *termtype;
+WINDOW *footer, *header, *center, *status;
+WINDOW *pref_panel_window = NULL;
+PANEL *pref_panel, *main_panel;
+
+int pref_panel_visible = 0;
+int pref_line_selected = 0;
+int pref_current_sort = 0;
+
+Quark selected_process;
+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 max_center_lines;
+GPtrArray *selected_processes;
+
+pthread_t keyboard_thread;
+
+struct header_view cputopview[4];
+struct header_view iostreamtopview[3];
+struct header_view fileview[3];
+
+unsigned long i_start = 0;
+unsigned long i_end = 0;
+
+std::string sort_perf_key;
+
+
+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 */
+               init_pair(6, COLOR_WHITE, COLOR_GREEN); /* selected process */
+       }
+       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, const 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, "%d", value);
+       wmove(header, line, 24);
+       print_digits(header, first, second);
+       wmove(header, line, 40);
+}
+
+void set_window_title(WINDOW *win, const char title[])
+{
+       wattron(win, A_BOLD);
+       mvwprintw(win, 0, 1, title);
+       wattroff(win, A_BOLD);
+}
+
+void print_log(const char str[])
+{
+       unsigned 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);
+}
+
+int process_selected(Quark proc)
+{
+       int selected;
+       get_current_attribute_value_int(&proc, "selected", selected);
+       return selected;
+}
+
+void update_selected_processes()
+{
+       Quark selected = state_system->getQuark(selected_process, "selected");
+       if (process_selected(selected_process)) {
+               state_system->updateCurrentState(selected, 0);
+               print_log("Process removed");
+       } else {
+               state_system->updateCurrentState(selected, 1);
+               print_log("Process added");
+       }
+}
+
+void print_key(WINDOW *win, const char key[], const 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, "F4", "IOTop  ", current_view == iostream);
+       print_key(footer, "Enter", "Details  ", current_view == process_details);
+       print_key(footer, "Space", "Highlight  ", 0);
+       print_key(footer, "q", "Quit ", 0);
+       print_key(footer, "r", "Pref  ", 0);
+       print_key(footer, "t", "Threads  ", toggle_threads);
+       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, "Threads");
+       mvwprintw(header, 3, 4, "FDs");
+       wattroff(header, A_BOLD);
+       wrefresh(header);
+}
+
+struct tm format_timestamp(uint64_t timestamp)
+{
+       struct tm tm;
+       uint64_t ts_sec = 0, ts_nsec;
+       time_t time_s;
+
+       ts_nsec = timestamp;
+       ts_sec += ts_nsec / NSEC_PER_SEC;
+       ts_nsec = ts_nsec % NSEC_PER_SEC;
+
+       time_s = (time_t) ts_sec;
+
+       localtime_r(&time_s, &tm);
+
+       return tm;
+}
+
+static void scale_unit(uint64_t bytes, char *ret)
+{
+       if (bytes >= 1000000000)
+               sprintf(ret, "%" PRIu64 "G", bytes/1000000000);
+       if (bytes >= 1000000)
+               sprintf(ret, "%" PRIu64 "M", bytes/1000000);
+       else if (bytes >= 1000)
+               sprintf(ret, "%" PRIu64 "K", bytes/1000);
+       else
+               sprintf(ret, "%" PRIu64, bytes);
+}
+
+uint64_t total_io()
+{
+       uint64_t total = 0;
+       int read, write;
+       unsigned long birth;
+       unsigned long real_start;
+       Quark proc;
+
+       if (get_attribute_value_at_quark(i_end, NULL, "proc", proc)) {
+               do {
+                       get_attribute_value_at_ulong(
+                               i_end, &proc, "birth", birth);
+                       if (birth > i_start)
+                               real_start = birth;
+                       else
+                               real_start = i_start;
+                       get_interval_value_int(real_start, i_end, &proc,
+                                                "fileread", read);
+                       get_interval_value_int(real_start, i_end, &proc,
+                                                "filewrite", write);
+                       total += read + write;
+
+               } while (get_attribute_value_at_quark(
+                                i_end, &proc, "next", proc));
+       }
+
+       return total;
+}
+
+void update_header()
+{
+       struct tm start, end;
+       uint64_t ts_nsec_start, ts_nsec_end;
+       char io[16];
+       int cpu_nb;
+       int nbthreads, nbnewthreads, nbdeadthreads;
+       int nbfiles, nbnewfiles, nbdeadfiles;
+
+       ts_nsec_start = i_start % NSEC_PER_SEC;
+       start = format_timestamp(i_start);
+
+       ts_nsec_end = i_end % NSEC_PER_SEC;
+       end = format_timestamp(i_end);
+
+       werase(header);
+       box(header, 0 , 0);
+       set_window_title(header, "Statistics for interval ");
+       wattron(header, A_BOLD);
+
+       wprintw(header,
+               "[%02d:%02d:%02d.%09" PRIu64 ", %02d:%02d:%02d.%09" PRIu64 "[",
+               start.tm_hour, start.tm_min, start.tm_sec, ts_nsec_start,
+               end.tm_hour, end.tm_min, end.tm_sec, ts_nsec_end);
+       mvwprintw(header, 1, 4, "CPUs");
+       wattroff(header, A_BOLD);
+
+       cpu_nb = get_sequence_length(i_end, state_system->getQuark("cpu"));
+       get_attribute_value_at_int(i_end, NULL, "nbthreads", nbthreads);
+       get_interval_value_int(i_start, i_end, NULL, "nbnewthreads",
+                              nbnewthreads);
+       get_interval_value_int(i_start, i_end, NULL, "nbdeadthreads",
+                              nbdeadthreads);
+       get_attribute_value_at_int(i_end, NULL, "nbfiles", nbfiles);
+       get_interval_value_int(i_start, i_end, NULL, "nbnewfiles", nbnewfiles);
+       get_interval_value_int(i_start, i_end, NULL, "nbdeadfiles",
+                              nbdeadfiles);
+
+       wprintw(header, "\t%d\t(max/cpu : %0.2f%)", cpu_nb,
+                       100.0/cpu_nb);
+       print_headers(2, "Threads", nbthreads, nbnewthreads,-1*nbdeadthreads);
+       print_headers(3, "FDs", nbfiles, nbnewfiles,-1*nbdeadfiles);
+       scale_unit(total_io(), io);
+       mvwprintw(header, 3, 43, "%sB/sec", io);
+       wrefresh(header);
+}
+
+int sort_by_cpu_desc(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       unsigned long total1, total2;
+       unsigned long birth1, birth2;
+       unsigned long start1 = i_start;
+       unsigned long start2 = i_start;
+
+       get_attribute_value_at_ulong(i_end, &p1, "birth", birth1);
+       get_attribute_value_at_ulong(i_end, &p2, "birth", birth2);
+       if (birth1 > i_start)
+               start1 = birth1;
+       if (birth2 > i_start)
+               start2 = birth2;
+
+       get_interval_value_ulong(start1, i_end, &p1, "totalcpunsec", total1);
+       get_interval_value_ulong(start2, i_end, &p2, "totalcpunsec", total2);
+
+       if (total1 > total2)
+               return 1;
+       if (total1 == total2)
+               return 0;
+       return -1;
+}
+
+int sort_by_tid_desc(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       int tid1, tid2;
+
+       get_attribute_value_at_int(i_end, &p1, "tid", tid1);
+       get_attribute_value_at_int(i_end, &p2, "tid", tid2);
+
+       if (tid1 > tid2)
+               return 1;
+       if (tid1 == tid2)
+               return 0;
+       return -1;
+}
+
+int sort_by_pid_desc(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       int pid1, pid2;
+
+       get_attribute_value_at_int(i_end, &p1, "pid", pid1);
+       get_attribute_value_at_int(i_end, &p2, "pid", pid2);
+
+       if (pid1 > pid2)
+               return 1;
+       if (pid1 == pid2)
+               return 0;
+       return -1;
+}
+
+
+int sort_by_process_read_desc(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       int total1, total2;
+       unsigned long birth1, birth2;
+       unsigned long start1 = i_start;
+       unsigned long start2 = i_start;
+
+       get_attribute_value_at_ulong(i_end, &p1, "birth", birth1);
+       get_attribute_value_at_ulong(i_end, &p2, "birth", birth2);
+       if (birth1 > i_start)
+               start1 = birth1;
+       if (birth2 > i_start)
+               start2 = birth2;
+
+       get_interval_value_int(start1, i_end, &p1, "fileread", total1);
+       get_interval_value_int(start2, i_end, &p2, "fileread", total2);
+
+       if (total1 > total2)
+               return 1;
+       if (total1 == total2)
+               return 0;
+       return -1;
+}
+
+int sort_by_process_write_desc(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       int total1, total2;
+       unsigned long birth1, birth2;
+       unsigned long start1 = i_start;
+       unsigned long start2 = i_start;
+
+       get_attribute_value_at_ulong(i_end, &p1, "birth", birth1);
+       get_attribute_value_at_ulong(i_end, &p2, "birth", birth2);
+       if (birth1 > i_start)
+               start1 = birth1;
+       if (birth2 > i_start)
+               start2 = birth2;
+
+       get_interval_value_int(start1, i_end, &p1, "filewrite", total1);
+       get_interval_value_int(start2, i_end, &p2, "filewrite", total2);
+
+       if (total1 > total2)
+               return 1;
+       if (total1 == total2)
+               return 0;
+       return -1;
+}
+
+int sort_by_process_total_desc(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       int p1Read, p2Read;
+       int p1Write, p2Write;
+       int total1, total2;
+       unsigned long birth1, birth2;
+       unsigned long start1 = i_start;
+       unsigned long start2 = i_start;
+
+       get_attribute_value_at_ulong(i_end, &p1, "birth", birth1);
+       get_attribute_value_at_ulong(i_end, &p2, "birth", birth2);
+       if (birth1 > i_start)
+               start1 = birth1;
+       if (birth2 > i_start)
+               start2 = birth2;
+
+       get_interval_value_int(start1, i_end, &p1, "fileread", p1Read);
+       get_interval_value_int(start2, i_end, &p2, "fileread", p2Read);
+       get_interval_value_int(start1, i_end, &p1, "filewrite", p1Write);
+       get_interval_value_int(start2, i_end, &p2, "filewrite", p2Write);
+
+       total1 = p1Read + p1Write;
+       total2 = p2Read + p2Write;
+
+       if (total1 > total2)
+               return 1;
+       if (total1 == total2)
+               return 0;
+       return -1;
+}
+
+int sort_by_file_read_desc(const void *pf1, const void *pf2)
+{
+       Quark f1 = *(Quark *)pf1;
+       Quark f2 = *(Quark *)pf2;
+       int total1, total2;
+       unsigned long birth1, birth2;
+       unsigned long start1 = i_start;
+       unsigned long start2 = i_start;
+
+       get_attribute_value_at_ulong(i_end, &f1, "file/birth", birth1);
+       get_attribute_value_at_ulong(i_end, &f2, "file/birth", birth2);
+       if (birth1 > i_start)
+               start1 = birth1;
+       if (birth2 > i_start)
+               start2 = birth2;
+
+       get_interval_value_int(start1, i_end, &f1, "file/read", total1);
+       get_interval_value_int(start2, i_end, &f2, "file/read", total2);
+
+       if (total1 > total2)
+               return 1;
+       if (total1 == total2)
+               return 0;
+       return -1;
+}
+
+int sort_by_file_write_desc(const void *pf1, const void *pf2)
+{
+       Quark f1 = *(Quark *)pf1;
+       Quark f2 = *(Quark *)pf2;
+       int total1, total2;
+       unsigned long birth1, birth2;
+       unsigned long start1 = i_start;
+       unsigned long start2 = i_start;
+
+       get_attribute_value_at_ulong(i_end, &f1, "file/birth", birth1);
+       get_attribute_value_at_ulong(i_end, &f2, "file/birth", birth2);
+       if (birth1 > i_start)
+               start1 = birth1;
+       if (birth2 > i_start)
+               start2 = birth2;
+
+       get_interval_value_int(start1, i_end, &f1, "file/write", total1);
+       get_interval_value_int(start2, i_end, &f2, "file/write", total2);
+
+       if (total1 > total2)
+               return 1;
+       if (total1 == total2)
+               return 0;
+       return -1;
+}
+
+int sort_by_file_fd_desc(const void *pf1, const void *pf2)
+{
+       Quark f1 = *(Quark *)pf1;
+       Quark f2 = *(Quark *)pf2;
+       int fd1, fd2;
+
+       get_attribute_value_at_int(i_end, &f1, "file/fd", fd1);
+       get_attribute_value_at_int(i_end, &f2, "file/fd", fd2);
+
+       if (fd1 > fd2)
+               return 1;
+       if (fd1 == fd2)
+               return 0;
+       return -1;
+}
+
+int sort_by_cpu_group_by_threads_desc(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       unsigned long total1, total2;
+       unsigned long birth1, birth2;
+       unsigned long start1 = i_start;
+       unsigned long start2 = i_start;
+
+       get_attribute_value_at_ulong(i_end, &p1, "birth", birth1);
+       get_attribute_value_at_ulong(i_end, &p2, "birth", birth2);
+       if (birth1 > i_start)
+               start1 = birth1;
+       if (birth2 > i_start)
+               start2 = birth2;
+
+       get_interval_value_ulong(start1, i_end, &p1, "threadstotalcpunsec",
+                                total1);
+       get_interval_value_ulong(start2, i_end, &p2, "threadstotalcpunsec",
+                                total2);
+
+       if (total1 > total2)
+               return 1;
+       if (total1 == total2)
+               return 0;
+       return -1;
+}
+
+void update_cputop_display()
+{
+       unsigned int i;
+       int header_offset = 2;
+       unsigned long elapsed;
+       double maxcputime;
+       int nblinedisplayed = 0;
+       int current_line = 0;
+       int column;
+       Quark *processes;
+       int tid, pid;
+       unsigned long totalcpunsec;
+       std::string comm;
+
+       Quark cpu_root = state_system->getQuark("cpu");
+       Quark proc_root = state_system->getQuark("proc");
+       unsigned int cpu_nb = get_sequence_length(i_end, cpu_root);
+       unsigned int proc_nb = get_sequence_length(i_end, proc_root);
+
+       elapsed = i_end - i_start;
+       maxcputime = elapsed * cpu_nb / 100.0;
+
+       processes = g_new(Quark, proc_nb);
+       sequence_to_array(i_end, proc_root, processes, proc_nb);
+
+       if (cputopview[0].sort == 1)
+               qsort(processes, proc_nb, sizeof(Quark), sort_by_cpu_desc);
+       else if (cputopview[1].sort == 1)
+               qsort(processes, proc_nb, sizeof(Quark), sort_by_pid_desc);
+       else if (cputopview[2].sort == 1)
+               qsort(processes, proc_nb, sizeof(Quark), sort_by_tid_desc);
+       else if (cputopview[3].sort == 1)
+               qsort(processes, proc_nb, sizeof(Quark), sort_by_cpu_desc);
+       else
+               qsort(processes, proc_nb, sizeof(Quark), sort_by_cpu_desc);
+
+       set_window_title(center, "CPU Top");
+       wattron(center, A_BOLD);
+       column = 1;
+       for (i = 0; i < 4; i++) {
+               if (cputopview[i].sort) {
+                       wattron(center, A_UNDERLINE);
+                       pref_current_sort = i;
+               }
+               mvwprintw(center, 1, column, cputopview[i].title);
+               wattroff(center, A_UNDERLINE);
+               column += 10;
+       }
+       wattroff(center, A_BOLD);
+
+       max_center_lines = LINES - 5 - 7 - 1 - header_offset;
+
+       /* iterate the process (thread) list */
+       for (i = list_offset; i < proc_nb && nblinedisplayed < max_center_lines;
+            i++) {
+               get_attribute_value_at_int(i_end, processes + i, "tid", tid);
+               get_attribute_value_at_int(i_end, processes + i, "pid", pid);
+
+               if (pid != tid)
+                       if (toggle_threads == -1)
+                               continue;
+
+               if (process_selected(processes[i])) {
+                       wattron(center, COLOR_PAIR(6));
+                       mvwhline(center, current_line + header_offset, 1, ' ',
+                                COLS-3);
+               }
+               if (current_line == selected_line) {
+                       selected_process = processes[i];
+                       wattron(center, COLOR_PAIR(5));
+                       mvwhline(center, current_line + header_offset, 1, ' ',
+                                COLS-3);
+               }
+               /* CPU(%) */
+               get_interval_value_ulong(i_start, i_end, processes + i,
+                                        "totalcpunsec", totalcpunsec);
+               mvwprintw(center, current_line + header_offset, 1, "%1.2f",
+                               totalcpunsec / maxcputime);
+               /* PID */
+               mvwprintw(center, current_line + header_offset, 11, "%d", pid);
+               /* TID */
+               mvwprintw(center, current_line + header_offset, 21, "%d", tid);
+               /* NAME */
+               get_attribute_value_at_string(i_end, processes + i, "comm",
+                                             comm);
+               mvwprintw(center, current_line + header_offset, 31, "%s",
+                         comm.c_str());
+               wattroff(center, COLOR_PAIR(6));
+               wattroff(center, COLOR_PAIR(5));
+               nblinedisplayed++;
+               current_line++;
+       }
+
+       g_free(processes);
+}
+
+int sort_perf(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       std::string key = sort_perf_key;
+       int total1;
+       int total2;
+       int tid1;
+       int tid2;
+
+       if (!get_attribute_value_at_int(i_end, &p1, "perf/" + key + "/count",
+                                   total1))
+               total1 = 0;
+
+       if (!get_attribute_value_at_int(i_end, &p2, "perf/" + key + "/count",
+                                   total2))
+               total2 = 0;
+
+
+       if (total1 < total2)
+               return 1;
+       if (total1 == total2) {
+               get_attribute_value_at_int(i_end, &p1, "tid", tid1);
+               get_attribute_value_at_int(i_end, &p2, "tid", tid2);
+               if (tid1 < tid2)
+                       return 1;
+               return -1;
+       }
+       return -1;
+}
+
+void print_key_title(const char key[], int line)
+{
+       wattron(center, A_BOLD);
+       mvwprintw(center, line, 1, "%s", key);
+       mvwprintw(center, line, 30, " ");
+       wattroff(center, A_BOLD);
+}
+
+void update_process_details()
+{
+       unsigned long elapsed;
+       double maxcputime;
+       unsigned int i, j = 0;
+       char unit[4];
+       char filename_buf[COLS];
+       int line = 1;
+       int column;
+       unsigned int cpu_nb;
+       std::string comm;
+       int tid = -1, pid, ppid, fileread, filewrite;
+       unsigned long totalcpunsec;
+       Quark *global_perf;
+       unsigned int global_perf_nb;
+       std::string key;
+       int count;
+       Quark *files;
+       unsigned int file_nb;
+       int fd, read, write;
+       std::string name;
+
+       set_window_title(center, "Process details");
+
+       elapsed = i_end - i_start;
+       cpu_nb = get_sequence_length(i_end, state_system->getQuark("cpu"));
+       maxcputime = elapsed * cpu_nb / 100.0;
+
+       get_attribute_value_at_int(i_end, &selected_process, "tid", tid);
+       if (tid == -1) {
+               print_key_title("Does not exit at this time", 3);
+               return;
+       }
+
+       print_key_title("Name", line++);
+       get_attribute_value_at_string(i_end, &selected_process, "comm", comm);
+       wprintw(center, "%s", comm.c_str());
+       print_key_title("TID", line++);
+       wprintw(center, "%d", tid);
+
+       print_key_title("PID", line++);
+       get_attribute_value_at_int(i_end, &selected_process, "pid", pid);
+       wprintw(center, "%d", pid);
+       print_key_title("PPID", line++);
+       get_attribute_value_at_int(i_end, &selected_process, "ppid", ppid);
+       wprintw(center, "%d", ppid);
+       print_key_title("CPU", line++);
+       get_attribute_value_at_ulong(i_end, &selected_process, "totalcpunsec",
+                                  totalcpunsec);
+       wprintw(center, "%1.2f %%", totalcpunsec/maxcputime);
+
+       print_key_title("READ B/s", line++);
+       get_attribute_value_at_int(i_end, &selected_process, "fileread",
+                                  fileread);
+       scale_unit(fileread, unit);
+       wprintw(center, "%s", unit);
+
+       print_key_title("WRITE B/s", line++);
+       get_attribute_value_at_int(i_end, &selected_process, "filewrite",
+                                  filewrite);
+       scale_unit(filewrite, unit);
+       wprintw(center, "%s", unit);
+
+
+       global_perf_nb = get_global_perf_list_size(i_end);
+       global_perf = g_new(Quark, global_perf_nb);
+       get_global_perf_list(i_end, global_perf, global_perf_nb);
+       for (i = 0; i < global_perf_nb; i++) {
+               get_attribute_value_at_string(i_end, global_perf + i, "key",
+                                             key);
+               print_key_title(key.c_str(), line++);
+               if (!get_attribute_value_at_int(i_end, global_perf + i, "count",
+                                              count))
+                       count = 0;
+               wprintw(center, "%d", count);
+       }
+       line++;
+
+       wattron(center, A_BOLD);
+       column = 1;
+       for (i = 0; i < 3; i++) {
+               if (fileview[i].sort) {
+                       pref_current_sort = i;
+                       wattron(center, A_UNDERLINE);
+               }
+               mvwprintw(center, line, column, fileview[i].title);
+               wattroff(center, A_UNDERLINE);
+               column += 10;
+       }
+       mvwprintw(center, line++, column, "FILENAME");
+       wattroff(center, A_BOLD);
+
+       file_nb = get_number_of_opened_files(i_end, selected_process);
+       files = g_new(Quark, file_nb);
+       get_opened_files(i_end, selected_process, files, file_nb);
+
+       if (fileview[0].sort == 1)
+               qsort(files, file_nb, sizeof(Quark), sort_by_file_fd_desc);
+       else if (fileview[1].sort == 1)
+               qsort(files, file_nb, sizeof(Quark), sort_by_file_read_desc);
+       else if (fileview[2].sort == 1)
+               qsort(files, file_nb, sizeof(Quark), sort_by_file_write_desc);
+       else
+               qsort(files, file_nb, sizeof(Quark), sort_by_file_fd_desc);
+
+       for (i = selected_line;
+            i < file_nb && i < (selected_line + max_center_lines - line + 2);
+            i++) {
+               get_attribute_value_at_int(i_end, files + i, "fd", fd);
+               mvwprintw(center, line + j, 1, "%d", fd);
+               get_attribute_value_at_int(i_end, files + i, "read", read);
+               scale_unit(read, unit);
+               mvwprintw(center, line + j, 11, "%s", unit);
+               get_attribute_value_at_int(i_end, files + i, "write", write);
+               scale_unit(write, unit);
+               mvwprintw(center, line + j, 21, "%s", unit);
+               get_attribute_value_at_string(i_end, files + i, "name", name);
+               snprintf(filename_buf, COLS - 25, "%s", name.c_str());
+               mvwprintw(center, line + j, 31, "%s", filename_buf);
+               j++;
+       }
+       g_free(global_perf);
+       g_free(files);
+}
+
+void update_perf()
+{
+       unsigned int i, j;
+       int nblinedisplayed = 0;
+       int current_line = 0;
+       int header_offset = 2;
+       int perf_row = 40;
+       int value;
+       unsigned int global_perf_nb;
+       Quark *global_perf;
+       int sort = 0;
+       int visible = 0;
+       std::string key;
+       bool sort_exists;
+       unsigned int proc_nb;
+       Quark *procs;
+       Quark proc_beg;
+       int tid, pid;
+       std::string comm;
+
+       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;
+       global_perf_nb = get_global_perf_list_size(i_end);
+       global_perf = g_new(Quark, global_perf_nb);
+       get_global_perf_list(i_end, global_perf, global_perf_nb);
+       for (i = 0; i < global_perf_nb; i++) {
+               get_attribute_value_at_int(i_end, global_perf + i, "visible",
+                                          visible);
+               get_attribute_value_at_string(i_end, global_perf + i, "key",
+                                             key);
+               sort_exists = get_attribute_value_at_int(i_end, global_perf + i,
+                                                        "sort", sort);
+               if (visible) {
+                       if (sort_exists && sort) {
+                               wattron(center, A_UNDERLINE);
+                       }
+                       /* + 5 to strip the "perf_" prefix */
+                       mvwprintw(center, 1, perf_row, "%s",
+                                 key.c_str() + 5);
+                       wattroff(center, A_UNDERLINE);
+                       perf_row += 20;
+               }
+               if (sort_exists && sort) {
+                       sort_perf_key = key;
+               }
+       }
+       wattroff(center, A_BOLD);
+
+       proc_beg = state_system->getQuark("proc");
+       proc_nb = get_sequence_length(i_end, proc_beg);
+       procs = g_new(Quark, proc_nb);
+       sequence_to_array(i_end, proc_beg, procs, proc_nb);
+       for (i = 0; i < proc_nb && nblinedisplayed < max_center_lines; i++) {
+               get_attribute_value_at_int(i_end, procs + i, "tid", tid);
+               get_attribute_value_at_int(i_end, procs + i, "pid", pid);
+               get_attribute_value_at_string(i_end, procs + 1, "comm", comm);
+
+               if (pid != tid)
+                       if (toggle_threads == -1)
+                               continue;
+
+               if (process_selected(procs[i])) {
+                       wattron(center, COLOR_PAIR(6));
+                       mvwhline(center, current_line + header_offset, 1, ' ',
+                                COLS-3);
+               }
+               if (current_line == selected_line) {
+                       selected_process = procs[i];
+                       wattron(center, COLOR_PAIR(5));
+                       mvwhline(center, current_line + header_offset, 1, ' ',
+                                COLS-3);
+               }
+
+               mvwprintw(center, current_line + header_offset, 1, "%d", pid);
+               mvwprintw(center, current_line + header_offset, 11, "%d", tid);
+               mvwprintw(center, current_line + header_offset, 22, "%s",
+                         comm.c_str());
+
+               perf_row = 40;
+               for (j = 0; j < global_perf_nb; j++) {
+                       get_attribute_value_at_int(i_end, global_perf + j,
+                                                  "visible", visible);
+                       get_attribute_value_at_string(i_end, global_perf + j,
+                                                     "key", key);
+
+                       if (visible) {
+                               if (!get_interval_value_int(i_start, i_end,
+                                                          procs + i, "perf/" +
+                                                           key + "/count",
+                                                           value)) {
+                                       value = 0;
+                               }
+                               mvwprintw(center, current_line + header_offset,
+                                         perf_row, "%d", value);
+                               perf_row += 20;
+                       }
+               }
+
+               wattroff(center, COLOR_PAIR(6));
+               wattroff(center, COLOR_PAIR(5));
+               nblinedisplayed++;
+               current_line++;
+       }
+       g_free(global_perf);
+       g_free(procs);
+}
+
+void update_iostream()
+{
+       unsigned int i;
+       int header_offset = 2;
+       int nblinedisplayed = 0;
+       int current_line = 0;
+       char unit[4];
+       int column;
+       unsigned int proc_nb;
+       Quark *procs;
+       Quark proc_root;
+       int pid, tid, read, write, totalread, totalwrite;
+       std::string comm;
+
+       set_window_title(center, "IO Top");
+       wattron(center, A_BOLD);
+       mvwprintw(center, 1, 1, "PID");
+       mvwprintw(center, 1, 11, "TID");
+       mvwprintw(center, 1, 22, "NAME");
+       column = 40;
+       for (i = 0; i < 3; i++) {
+               if (iostreamtopview[i].sort) {
+                       pref_current_sort = i;
+                       wattron(center, A_UNDERLINE);
+               }
+               mvwprintw(center, 1, column, iostreamtopview[i].title);
+               wattroff(center, A_UNDERLINE);
+               column += 12;
+       }
+       wattroff(center, A_BOLD);
+       wattroff(center, A_UNDERLINE);
+
+       proc_root = state_system->getQuark("proc");
+       proc_nb = get_sequence_length(i_end, proc_root);
+       procs = g_new(Quark, proc_nb);
+       sequence_to_array(i_end, proc_root, procs, proc_nb);
+
+       if (iostreamtopview[0].sort == 1)
+               qsort(procs, proc_nb, sizeof(Quark), sort_by_process_read_desc);
+       else if (iostreamtopview[1].sort == 1)
+               qsort(procs, proc_nb, sizeof(Quark),
+                     sort_by_process_write_desc);
+       else if (iostreamtopview[2].sort == 1)
+               qsort(procs, proc_nb, sizeof(Quark),
+                     sort_by_process_total_desc);
+       else
+               qsort(procs, proc_nb, sizeof(Quark),
+                     sort_by_process_total_desc);
+
+       for (i = list_offset; i < proc_nb && nblinedisplayed < max_center_lines;
+            i++) {
+               get_attribute_value_at_int(i_end, procs + i, "tid", tid);
+               get_attribute_value_at_int(i_end, procs + i, "pid", pid);
+               get_attribute_value_at_string(i_end, procs + i, "comm", comm);
+               get_attribute_value_at_int(i_end, procs + i, "fileread",
+                                            read);
+               get_attribute_value_at_int(i_end, procs + i, "filewrite",
+                                            write);
+               get_attribute_value_at_int(i_end, procs + i, "totalfileread",
+                                            totalread);
+               get_attribute_value_at_int(i_end, procs + i, "totalfilewrite",
+                                            totalwrite);
+
+
+               if (pid != tid)
+                       if (toggle_threads == -1)
+                               continue;
+
+               if (process_selected(procs[i])) {
+                       wattron(center, COLOR_PAIR(6));
+                       mvwhline(center, current_line + header_offset, 1, ' ',
+                                COLS-3);
+               }
+               if (current_line == selected_line) {
+                       selected_process = procs[i];
+                       wattron(center, COLOR_PAIR(5));
+                       mvwhline(center, current_line + header_offset, 1, ' ',
+                                COLS-3);
+               }
+               /* PID */
+               mvwprintw(center, current_line + header_offset, 1, "%d", pid);
+               /* TID */
+               mvwprintw(center, current_line + header_offset, 11, "%d", tid);
+               /* NAME */
+               mvwprintw(center, current_line + header_offset, 22, "%s",
+                         comm.c_str());
+
+               /* READ (bytes/sec) */
+               scale_unit(read, unit);
+               mvwprintw(center, current_line + header_offset, 40, "%s", unit);
+
+               /* WRITE (bytes/sec) */
+               scale_unit(write, unit);
+               mvwprintw(center, current_line + header_offset, 52, "%s", unit);
+
+               /* TOTAL STREAM */
+               scale_unit(totalread + totalwrite, unit);
+               mvwprintw(center, current_line + header_offset, 64, "%s", unit);
+
+               wattroff(center, COLOR_PAIR(6));
+               wattroff(center, COLOR_PAIR(5));
+               nblinedisplayed++;
+               current_line++;
+       }
+       g_free(procs);
+}
+
+void update_current_view()
+{
+       sem_wait(&update_display_sem);
+       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 iostream:
+               update_iostream();
+               break;
+       case tree:
+               update_cputop_display();
+               break;
+       default:
+               break;
+       }
+       update_panels();
+       doupdate();
+       sem_post(&update_display_sem);
+}
+
+void update_process_detail_sort(int *line_selected)
+{
+       int i;
+       int size;
+
+       size = 3;
+
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+
+       if (fileview[*line_selected].sort == 1)
+               fileview[*line_selected].reverse = 1;
+       for (i = 0; i < size; i++)
+               fileview[i].sort = 0;
+       fileview[*line_selected].sort = 1;
+}
+
+void update_process_detail_pref(int *line_selected, int toggle_view, int toggle_sort)
+{
+       int i;
+       int size;
+
+       if (pref_panel_window) {
+               del_panel(pref_panel);
+               delwin(pref_panel_window);
+       }
+       size = 3;
+
+       pref_panel_window = create_window(size + 2, 30, 10, 10);
+       pref_panel = new_panel(pref_panel_window);
+
+       werase(pref_panel_window);
+       box(pref_panel_window, 0 , 0);
+       set_window_title(pref_panel_window, "Process Detail Preferences ");
+       wattron(pref_panel_window, A_BOLD);
+       mvwprintw(pref_panel_window, size + 1, 1,
+                       " 's' : sort, space : toggle");
+       wattroff(pref_panel_window, A_BOLD);
+
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+       if (toggle_sort == 1) {
+               update_process_detail_sort(line_selected);
+               update_current_view();
+       }
+
+       for (i = 0; i < size; i++) {
+               if (i == *line_selected) {
+                       wattron(pref_panel_window, COLOR_PAIR(5));
+                       mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
+               }
+               if (fileview[i].sort == 1)
+                       wattron(pref_panel_window, A_BOLD);
+               mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
+                               fileview[i].title);
+               wattroff(pref_panel_window, A_BOLD);
+               wattroff(pref_panel_window, COLOR_PAIR(5));
+
+       }
+       update_panels();
+       doupdate();
+}
+
+void update_iostream_sort(int *line_selected)
+{
+       int i;
+       int size;
+
+       size = 3;
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+       if (iostreamtopview[*line_selected].sort == 1)
+               iostreamtopview[*line_selected].reverse = 1;
+       for (i = 0; i < size; i++)
+               iostreamtopview[i].sort = 0;
+       iostreamtopview[*line_selected].sort = 1;
+
+}
+
+void update_iostream_pref(int *line_selected, int toggle_view, int toggle_sort)
+{
+       int i;
+       int size;
+
+       if (pref_panel_window) {
+               del_panel(pref_panel);
+               delwin(pref_panel_window);
+       }
+       size = 3;
+
+       pref_panel_window = create_window(size + 2, 30, 10, 10);
+       pref_panel = new_panel(pref_panel_window);
+
+       werase(pref_panel_window);
+       box(pref_panel_window, 0 , 0);
+       set_window_title(pref_panel_window, "IOTop Preferences ");
+       wattron(pref_panel_window, A_BOLD);
+       mvwprintw(pref_panel_window, size + 1, 1,
+                       " 's' : sort, space : toggle");
+       wattroff(pref_panel_window, A_BOLD);
+
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+       if (toggle_sort == 1) {
+               update_iostream_sort(line_selected);
+               update_current_view();
+       }
+
+       for (i = 0; i < size; i++) {
+               if (i == *line_selected) {
+                       wattron(pref_panel_window, COLOR_PAIR(5));
+                       mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
+               }
+               if (iostreamtopview[i].sort == 1)
+                       wattron(pref_panel_window, A_BOLD);
+               mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
+                               iostreamtopview[i].title);
+               wattroff(pref_panel_window, A_BOLD);
+               wattroff(pref_panel_window, COLOR_PAIR(5));
+
+       }
+       update_panels();
+       doupdate();
+}
+
+void update_cpu_sort(int *line_selected)
+{
+       int i;
+       int size = 3;
+
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+
+       /* special case, we don't support sorting by procname for now */
+       if (*line_selected != 3) {
+               if (cputopview[*line_selected].sort == 1)
+                       cputopview[*line_selected].reverse = 1;
+               for (i = 0; i < size; i++)
+                       cputopview[i].sort = 0;
+               cputopview[*line_selected].sort = 1;
+       }
+}
+
+void update_cpu_pref(int *line_selected, int toggle_view, int toggle_sort)
+{
+       int i;
+       int size;
+
+       if (pref_panel_window) {
+               del_panel(pref_panel);
+               delwin(pref_panel_window);
+       }
+       size = 4;
+
+       pref_panel_window = create_window(size + 2, 30, 10, 10);
+       pref_panel = new_panel(pref_panel_window);
+
+       werase(pref_panel_window);
+       box(pref_panel_window, 0 , 0);
+       set_window_title(pref_panel_window, "CPUTop Preferences ");
+       wattron(pref_panel_window, A_BOLD);
+       mvwprintw(pref_panel_window, size + 1, 1,
+                       " 's' : sort, space : toggle");
+       wattroff(pref_panel_window, A_BOLD);
+
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+       if (toggle_sort == 1) {
+               update_cpu_sort(line_selected);
+               update_current_view();
+       }
+
+       for (i = 0; i < size; i++) {
+               if (i == *line_selected) {
+                       wattron(pref_panel_window, COLOR_PAIR(5));
+                       mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
+               }
+               if (cputopview[i].sort == 1)
+                       wattron(pref_panel_window, A_BOLD);
+               mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
+                               cputopview[i].title);
+               wattroff(pref_panel_window, A_BOLD);
+               wattroff(pref_panel_window, COLOR_PAIR(5));
+
+       }
+       update_panels();
+       doupdate();
+}
+
+void update_perf_sort(int *line_selected)
+{
+       int i;
+       int size;
+       Quark *global_perf;
+
+       size = get_global_perf_list_size(i_end);
+       global_perf = g_new(Quark, size);
+       get_global_perf_list(i_end, global_perf, size);
+
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+
+       for (i = 0; i < size; i++) {
+               if (i != *line_selected)
+                       modify_attribute(i_end, global_perf + i, "sort", 0);
+               else
+                       modify_attribute(i_end, global_perf + i, "sort", 1);
+       }
+
+       g_free(global_perf);
+}
+
+void update_perf_pref(int *line_selected, int toggle_view, int toggle_sort)
+{
+       int i;
+       int size;
+       Quark *global_perf;
+       int visible;
+       int sort;
+       std::string key;
+
+       if (pref_panel_window) {
+               del_panel(pref_panel);
+               delwin(pref_panel_window);
+       }
+
+       size = get_global_perf_list_size(i_end);
+       global_perf = g_new(Quark, size);
+       get_global_perf_list(i_end, global_perf, size);
+
+       pref_panel_window = create_window(size + 2, 30, 10, 10);
+       pref_panel = new_panel(pref_panel_window);
+
+       werase(pref_panel_window);
+       box(pref_panel_window, 0 , 0);
+       set_window_title(pref_panel_window, "Perf Preferences ");
+       wattron(pref_panel_window, A_BOLD);
+       mvwprintw(pref_panel_window, size + 1, 1,
+                       " 's' : sort, space : toggle");
+       wattroff(pref_panel_window, A_BOLD);
+
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+
+       if (toggle_sort == 1) {
+               update_perf_sort(line_selected);
+               update_current_view();
+       }
+
+       for (i = 0; i < size; i++) {
+               get_attribute_value_at_int(i_end, global_perf + i,
+                                          "visible", visible);
+               get_attribute_value_at_string(i_end, global_perf + i, "key",
+                                             key);
+               if (i == *line_selected && toggle_view == 1) {
+                       visible = visible == 1 ? 0 : 1;
+                       modify_attribute(i_end, global_perf + i, "visible",
+                                        visible);
+                       update_current_view();
+               }
+               if (i == *line_selected) {
+                       wattron(pref_panel_window, COLOR_PAIR(5));
+                       mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
+               }
+
+               if (get_attribute_value_at_int(i_end, global_perf + 1, "sort",
+                                              sort) && sort) {
+                       wattron(pref_panel_window, A_BOLD);
+               }
+               mvwprintw(pref_panel_window, i + 1, 1, "[%c] %s",
+                         visible == 1 ? 'x' : ' ', key.c_str() + 5);
+               wattroff(pref_panel_window, A_BOLD);
+               wattroff(pref_panel_window, COLOR_PAIR(5));
+       }
+       update_panels();
+       doupdate();
+
+       g_free(global_perf);
+}
+
+int update_preference_panel(int *line_selected, int toggle_view, int toggle_sort)
+{
+       int ret = 0;
+
+       switch(current_view) {
+               case perf:
+                       update_perf_pref(line_selected, toggle_view, toggle_sort);
+                       break;
+               case cpu:
+                       update_cpu_pref(line_selected, toggle_view, toggle_sort);
+                       break;
+               case iostream:
+                       update_iostream_pref(line_selected, toggle_view, toggle_sort);
+                       break;
+               case process_details:
+                       update_process_detail_pref(line_selected, toggle_view, toggle_sort);
+                       break;
+               default:
+                       ret = -1;
+                       break;
+       }
+
+       return ret;
+}
+
+int update_sort(int *line_selected)
+{
+       int ret = 0;
+
+       switch(current_view) {
+               case perf:
+                       update_perf_sort(line_selected);
+                       break;
+               case cpu:
+                       update_cpu_sort(line_selected);
+                       break;
+               case iostream:
+                       update_iostream_sort(line_selected);
+                       break;
+               case process_details:
+                       update_process_detail_sort(line_selected);
+                       break;
+               default:
+                       ret = -1;
+                       break;
+       }
+
+       return ret;
+}
+
+
+void toggle_pref_panel(void)
+{
+       int ret;
+
+       if (pref_panel_visible) {
+               hide_panel(pref_panel);
+               pref_panel_visible = 0;
+       } else {
+               ret = update_preference_panel(&pref_line_selected, 0, 0);
+               if (ret < 0)
+                       return;
+               show_panel(pref_panel);
+               pref_panel_visible = 1;
+       }
+       update_panels();
+       doupdate();
+}
+
+void display()
+{
+       if (i_start == 0)
+               i_start = first_display_update;
+       else
+               i_start += refresh_display;
+       i_end = i_start + refresh_display;
+
+       max_elements = get_sequence_length(
+               i_end, state_system->getQuark("proc"));
+       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 'j':
+               case KEY_DOWN:
+                       if (pref_panel_visible) {
+                               pref_line_selected++;
+                               update_preference_panel(&pref_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:
+                       break;
+               case 'k':
+               case KEY_UP:
+                       if (pref_panel_visible) {
+                               if (pref_line_selected > 0)
+                                       pref_line_selected--;
+                               update_preference_panel(&pref_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:
+                       break;
+
+               /* Navigate the history with arrows */
+               case KEY_LEFT:
+                       if ((i_start - refresh_display) >=
+                           first_display_update) {
+                               i_start -= refresh_display;
+                               i_end = i_start + refresh_display;
+                               print_log("Going back in time");
+                       } else {
+                               print_log("Cannot rewind, last data is already displayed");
+                       }
+                       max_elements = get_sequence_length(
+                               i_end, state_system->getQuark("proc"));
+
+                       /* 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 ((i_end + refresh_display) <=
+                            last_display_update) {
+                                   i_end += refresh_display;
+                                   i_start = i_end - refresh_display;
+                                   print_log("Going forward in time");
+                                   max_elements = get_sequence_length(
+                                           i_end, state_system->getQuark(
+                                                   "proc"));
+                                   update_current_view();
+                                   update_footer();
+                       } else {
+                               print_log("Manually moving forward");
+                               sem_post(&timer);
+                               if (toggle_pause > 0) {
+                                       sem_post(&pause_sem);
+                                       update_current_view();
+                                       sem_wait(&pause_sem);
+                               }
+                       }
+
+                       break;
+               case ' ':
+                       if (pref_panel_visible) {
+                               update_preference_panel(&pref_line_selected, 1, 0);
+                       } else {
+                               update_selected_processes();
+                               update_current_view();
+                       }
+                       break;
+               case 's':
+                       if (pref_panel_visible)
+                               update_preference_panel(&pref_line_selected, 0, 1);
+                       break;
+               case '>':
+                       /* perf uses a hashtable, it is ordered backward */
+                       if (current_view == perf) {
+                               pref_current_sort--;
+                       } else if (!pref_panel_visible) {
+                               pref_current_sort++;
+                       }
+                       update_sort(&pref_current_sort);
+                       update_current_view();
+                       break;
+               case '<':
+                       /* perf uses a hashtable, it is ordered backward */
+                       if (current_view == perf) {
+                               pref_current_sort++;
+                       } else if (!pref_panel_visible) {
+                               pref_current_sort--;
+                       }
+                       update_sort(&pref_current_sort);
+                       update_current_view();
+                       break;
+
+               case 13: /* FIXME : KEY_ENTER ?? */
+                       if (pref_panel_visible)
+                               break;
+                       if (current_view != process_details) {
+                               previous_view = current_view;
+                               current_view = process_details;
+                       } else {
+                               current_view = previous_view;
+                               previous_view = process_details;
+                       }
+                       update_current_view();
+                       break;
+
+               case KEY_F(1):
+                       if (pref_panel_visible)
+                               toggle_pref_panel();
+                       current_view = cpu;
+                       selected_line = 0;
+                       update_current_view();
+                       break;
+               case KEY_F(2):
+                       if (pref_panel_visible)
+                               toggle_pref_panel();
+                       current_view = cpu;
+                       selected_line = 0;
+                       update_current_view();
+                       break;
+               case KEY_F(3):
+                       if (pref_panel_visible)
+                               toggle_pref_panel();
+                       current_view = perf;
+                       selected_line = 0;
+                       update_current_view();
+                       break;
+               case KEY_F(4):
+                       if (pref_panel_visible)
+                               toggle_pref_panel();
+                       current_view = iostream;
+                       selected_line = 0;
+                       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 'r':
+                       toggle_pref_panel();
+                       break;
+               /* ESCAPE, but slow to process, don't know why */
+               case 27:
+                       if (pref_panel_visible)
+                               toggle_pref_panel();
+                       else if (current_view == process_details) {
+                               current_view = previous_view;
+                               previous_view = process_details;
+                       }
+                       update_current_view();
+                       break;
+               default:
+                       update_current_view();
+                       break;
+               }
+               update_footer();
+       }
+       return NULL;
+}
+
+void init_view_headers()
+{
+       cputopview[0].title = strdup("CPU(%)");
+       cputopview[0].sort = 1;
+       cputopview[1].title = strdup("PID");
+       cputopview[2].title = strdup("TID");
+       cputopview[3].title = strdup("NAME");
+
+       iostreamtopview[0].title = strdup("R (B/sec)");
+       iostreamtopview[1].title = strdup("W (B/sec)");
+       iostreamtopview[2].title = strdup("Total (B)");
+       iostreamtopview[2].sort = 1;
+
+       fileview[0].title = strdup("FD");
+       fileview[1].title = strdup("READ");
+       fileview[1].sort = 1;
+       fileview[2].title = strdup("WRITE");
+}
+
+void init_ncurses()
+{
+       selected_processes = g_ptr_array_new();
+       sem_init(&update_display_sem, 0, 1);
+       init_view_headers();
+       init_screen();
+
+       header = create_window(5, COLS - 1, 0, 0);
+       center = create_window(LINES - 5 - 7, COLS - 1, 5, 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);
+
+       current_view = cpu;
+
+       basic_header();
+       update_footer();
+
+       pthread_create(&keyboard_thread, NULL, handle_keyboard, (void *)NULL);
+}
index fac262900b288b388c97a419b1faf6bab8a2fb30..6e21509f2292277dd5aaab25891d9155638f4c0d 100644 (file)
@@ -19,7 +19,9 @@
 #define CURSESDISPLAY_H
 
 #include <glib.h>
+extern "C" {
 #include <ncurses.h>
+}
 #include "common.h"
 
 enum view_list
@@ -31,10 +33,10 @@ enum view_list
        tree,
 };
 
-enum view_list current_view;
-enum view_list previous_view;
+extern enum view_list current_view;
+extern enum view_list previous_view;
 
-void display(unsigned int);
+void display();
 void init_ncurses();
 void reset_ncurses();
 
diff --git a/src/iostreamtop.c b/src/iostreamtop.c
deleted file mode 100644 (file)
index bda9c7c..0000000
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * Copyright (C) 2011-2012 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <babeltrace/babeltrace.h>
-
-#include "lttngtoptypes.h"
-#include "common.h"
-#include "iostreamtop.h"
-
-void add_file(struct processtop *proc, struct files *file, int fd)
-{
-       struct files *tmp_file;
-       struct processtop *parent;
-       int size;
-       int i;
-
-       size = proc->process_files_table->len;
-       parent = proc->threadparent;
-       if (parent)
-               insert_file(parent, fd);
-       if (size <= fd) {
-               /* Add NULL file structures for undefined FDs */
-               for (i = size; i < fd; i++) {
-                       g_ptr_array_add(proc->process_files_table, NULL);
-               }
-               g_ptr_array_add(proc->process_files_table, file);
-       } else {
-               tmp_file = g_ptr_array_index(proc->process_files_table, fd);
-               if (tmp_file == NULL)
-                       g_ptr_array_index(proc->process_files_table, fd) = file;
-               else {
-                       if (strcmp(tmp_file->name, file->name) != 0) {
-                               size = proc->process_files_table->len;
-                               g_ptr_array_set_size(proc->process_files_table,
-                                                               size+1);
-                               g_ptr_array_index(proc->process_files_table,
-                                                       size) = tmp_file;
-                               g_ptr_array_index(proc->process_files_table,
-                                                       fd) = file;
-                       } else
-                               tmp_file->flag = __NR_open;
-               }
-       }
-       /*
-        * The file may have be created in the parent
-        */
-       if (file->flag == -1) {
-               file->fd = fd;
-               file->flag = __NR_open;
-               lttngtop.nbfiles++;
-               lttngtop.nbnewfiles++;
-       }
-}
-
-/*
- * Edit the file
- * Called by handled_statedump_filename
- */
-void edit_file(struct processtop *proc, struct files *file, int fd)
-{
-       int size = proc->process_files_table->len;
-       struct files *tmpfile;
-
-       if (fd >= size) {
-               add_file(proc, file, fd);
-       } else {
-               tmpfile = g_ptr_array_index(proc->process_files_table, fd);
-               if (tmpfile) {
-                       tmpfile->name = strdup(file->name);
-                       free(file);
-               } else
-                       add_file(proc, file, fd);
-       }
-}
-
-void insert_file(struct processtop *proc, int fd)
-{
-       struct files *tmp;
-       struct files *tmp_parent;
-       struct processtop *parent;
-
-       if (fd < 0)
-               return;
-       if (fd >= proc->process_files_table->len) {
-               tmp = g_new0(struct files, 1);
-               tmp->name = "Unknown";
-               tmp->read = 0;
-               tmp->write = 0;
-               tmp->fd = fd;
-               tmp->flag = -1;
-               add_file(proc, tmp, fd);
-       } else {
-               tmp = g_ptr_array_index(proc->process_files_table, fd);
-               if (tmp == NULL) {
-                       tmp = g_new0(struct files, 1);
-                       tmp->name = "Unknown";
-                       tmp->read = 0;
-                       tmp->write = 0;
-                       tmp->fd = fd;
-                       tmp->flag = -1;
-                       add_file(proc, tmp, fd);
-               } else {
-                       parent = proc->threadparent;
-                       if (parent) {
-                               tmp_parent = g_ptr_array_index(
-                                       parent->process_files_table, fd);
-                               if (tmp_parent &&
-                                  (strcmp(tmp->name, tmp_parent->name)) != 0)
-                                       tmp->name = strdup(tmp_parent->name);
-                       }
-               }
-       }
-}
-
-void close_file(struct processtop *proc, int fd)
-{
-       struct files *file;
-
-       file = get_file(proc, fd);
-       if (file != NULL) {
-               file->flag = __NR_close;
-               lttngtop.nbfiles--;
-       }
-       lttngtop.nbclosedfiles++;
-}
-
-struct files *get_file(struct processtop *proc, int fd)
-{
-       int len;
-       struct files *tmp = NULL;
-
-       len = proc->process_files_table->len;
-
-       /*
-        * It is possible that a file was open before taking the trace
-        * and its fd could be greater than all of the others fd
-        * used by the process
-        */
-       if (fd < len && fd >= 0)
-               tmp = g_ptr_array_index(proc->process_files_table, fd);
-
-       return tmp;
-}
-
-void show_table(GPtrArray *tab)
-{
-       int i;
-       struct files *file;
-
-       for (i = 0 ; i < tab->len; i++) {
-               file = g_ptr_array_index(tab, i);
-               if (file == NULL)
-                       fprintf(stderr, "NULL, ");
-               else
-                       fprintf(stderr, "%s, ", file->name);
-       }
-       fprintf(stderr, "]\n\n");
-}
-
-void show_history(struct file_history *history)
-{
-       struct file_history *tmp = history;
-
-       while (tmp != NULL) {
-               fprintf(stderr, "fd = %d, name = %s\n", tmp->file->fd,
-                                       tmp->file->name);
-               tmp = tmp->next;
-       }
-
-}
-
-int update_iostream_ret(struct lttngtop *ctx, int tid, char *comm,
-               unsigned long timestamp, uint64_t cpu_id, int ret)
-{
-       struct processtop *tmp;
-       struct files *tmpfile;
-       int err = 0;
-
-       tmp = get_proc(ctx, tid, comm, timestamp);
-
-       if (tmp->syscall_info != NULL) {
-               if (tmp->syscall_info->type == __NR_read
-                       && ret > 0) {
-                       tmp->totalfileread += ret;
-                       tmp->fileread += ret;
-                       tmpfile = get_file(tmp, tmp->syscall_info->fd);
-                       if (tmpfile)
-                               tmpfile->read += ret;
-               } else if (tmp->syscall_info->type == __NR_write
-                       && ret > 0) {
-                       tmp->totalfilewrite += ret;
-                       tmp->filewrite += ret;
-                       tmpfile = get_file(tmp, tmp->syscall_info->fd);
-                       if (tmpfile)
-                               tmpfile->write += ret;
-               } else if (tmp->syscall_info->type == __NR_open
-                       && ret > 0) {
-                       tmpfile = tmp->files_history->file;
-                       add_file(tmp, tmpfile, ret);
-                       tmpfile->fd = ret;
-               } else {
-                       err = -1;
-               }
-               g_free(tmp->syscall_info);
-               tmp->syscall_info = NULL;
-       }
-       return err;
-}
-
-struct syscalls *create_syscall_info(unsigned int type, uint64_t cpu_id,
-               unsigned int tid, int fd)
-{
-       struct syscalls *syscall_info;
-       
-       syscall_info = g_new0(struct syscalls, 1);
-       syscall_info->type = type;
-       syscall_info->cpu_id = cpu_id;
-       syscall_info->tid = tid;
-       syscall_info->fd = fd;
-
-       return syscall_info;
-}
-
-struct file_history *create_file(struct file_history *history, char *file_name)
-{
-       struct files *new_file;
-       struct file_history *new_history;
-
-       new_file = g_new0(struct files, 1);
-       new_history = g_new0(struct file_history, 1);
-       new_file->name = strdup(file_name);
-       new_file->read = 0;
-       new_file->write = 0;
-       new_file->flag = -1;
-       new_history->file = new_file;
-       new_history->next = history;
-
-       return new_history;
-}
-
-enum bt_cb_ret handle_exit_syscall(struct bt_ctf_event *call_data,
-               void *private_data)
-{
-       const struct definition *scope;
-       unsigned long timestamp;
-       char *comm;
-       uint64_t ret, tid;
-       uint64_t cpu_id;
-
-       timestamp = bt_ctf_get_timestamp(call_data);
-       if (timestamp == -1ULL)
-               goto error;
-
-       comm = get_context_comm(call_data);
-       tid = get_context_tid(call_data);
-
-       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;
-       }
-
-       cpu_id = get_cpu_id(call_data);
-
-       /*
-        * 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)
-{
-       const struct definition *scope;
-       struct processtop *tmp;
-       unsigned long timestamp;
-       uint64_t cpu_id;
-       int64_t tid;
-       char *procname;
-       int fd;
-
-       timestamp = bt_ctf_get_timestamp(call_data);
-       if (timestamp == -1ULL)
-               goto error;
-
-       tid = get_context_tid(call_data);
-       cpu_id = get_cpu_id(call_data);
-
-       procname = get_context_comm(call_data);
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_EVENT_FIELDS);
-       fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
-                               scope, "_fd"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing fd context info\n");
-               goto error;
-       }
-
-       tmp = get_proc(&lttngtop, tid, procname, timestamp);
-       tmp->syscall_info = create_syscall_info(__NR_write, cpu_id, tid, fd);
-
-       insert_file(tmp, fd);
-
-       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;
-       const struct definition *scope;
-       unsigned long timestamp;
-       uint64_t cpu_id;
-       int64_t tid;
-       char *procname;
-       int fd;
-
-       timestamp = bt_ctf_get_timestamp(call_data);
-       if (timestamp == -1ULL)
-               goto error;
-
-       tid = get_context_tid(call_data);
-       cpu_id = get_cpu_id(call_data);
-
-       procname = get_context_comm(call_data);
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_EVENT_FIELDS);
-       fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
-                               scope, "_fd"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing fd context info\n");
-               goto error;
-       }
-
-       tmp = get_proc(&lttngtop, tid, procname, timestamp);
-       tmp->syscall_info = create_syscall_info(__NR_read, cpu_id, tid, fd);
-
-       insert_file(tmp, fd);
-
-       return BT_CB_OK;
-
-error:
-       return BT_CB_ERROR_STOP;
-}
-
-
-enum bt_cb_ret handle_sys_open(struct bt_ctf_event *call_data,
-               void *private_data)
-{
-
-       struct processtop *tmp;
-       const struct definition *scope;
-       unsigned long timestamp;
-       uint64_t cpu_id;
-       int64_t tid;
-       char *procname;
-       char *file;
-
-       timestamp = bt_ctf_get_timestamp(call_data);
-       if (timestamp == -1ULL)
-               goto error;
-
-       tid = get_context_tid(call_data);
-       cpu_id = get_cpu_id(call_data);
-
-       procname = get_context_comm(call_data);
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_EVENT_FIELDS);
-       file = bt_ctf_get_string(bt_ctf_get_field(call_data,
-                               scope, "_filename"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing file name context info\n");
-               goto error;
-       }
-
-       tmp = get_proc(&lttngtop, tid, procname, timestamp);
-       tmp->syscall_info = create_syscall_info(__NR_open, cpu_id, tid, -1);
-
-       tmp->files_history = create_file(tmp->files_history, file);
-
-       return BT_CB_OK;
-
-error:
-       return BT_CB_ERROR_STOP;
-}
-
-
-enum bt_cb_ret handle_sys_close(struct bt_ctf_event *call_data,
-               void *private_data)
-{
-       const struct definition *scope;
-       struct processtop *tmp;
-       unsigned long timestamp;
-       int64_t tid;
-       char *procname;
-       int fd;
-
-       timestamp = bt_ctf_get_timestamp(call_data);
-       if (timestamp == -1ULL)
-               goto error;
-
-       tid = get_context_tid(call_data);
-
-       procname = get_context_comm(call_data);
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_EVENT_FIELDS);
-       fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
-                               scope, "_fd"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing fd context info\n");
-               goto error;
-       }
-
-       tmp = get_proc(&lttngtop, tid, procname, timestamp);
-
-       close_file(tmp, fd);
-
-       return BT_CB_OK;
-
-error:
-       return BT_CB_ERROR_STOP;
-}
-
-enum bt_cb_ret handle_statedump_file_descriptor(struct bt_ctf_event *call_data,
-               void *private_data)
-{
-       const struct definition *scope;
-       struct processtop *parent;
-       struct files *file;
-       unsigned long timestamp;
-       int64_t pid;
-       char *file_name;
-       int fd;
-
-       timestamp = bt_ctf_get_timestamp(call_data);
-       if (timestamp == -1ULL)
-               goto error;
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                        BT_EVENT_FIELDS);
-       pid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
-                            scope, "_pid"));
-       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);
-       fd = bt_ctf_get_int64(bt_ctf_get_field(call_data,
-                               scope, "_fd"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing fd context info\n");
-               goto error;
-       }
-
-       scope = bt_ctf_get_top_level_scope(call_data,
-                       BT_EVENT_FIELDS);
-       file_name = bt_ctf_get_string(bt_ctf_get_field(call_data,
-                               scope, "_filename"));
-       if (bt_ctf_field_get_error()) {
-               fprintf(stderr, "Missing file name context info\n");
-               goto error;
-       }
-
-       parent = get_proc_pid(&lttngtop, pid, pid, timestamp);
-       parent->files_history = create_file(parent->files_history, file_name);
-       file = parent->files_history->file;
-       edit_file(parent, file, fd);
-
-       return BT_CB_OK;
-
-error:
-       return BT_CB_ERROR_STOP;
-}
diff --git a/src/iostreamtop.cpp b/src/iostreamtop.cpp
new file mode 100644 (file)
index 0000000..3e96c60
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2011-2012 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+extern "C"
+{
+#include <babeltrace/babeltrace.h>
+}
+
+#include "lttngtoptypes.h"
+#include "common.h"
+#include "iostreamtop.h"
+
+void add_file(Quark proc_quark, Quark file, int fd,
+                       unsigned long timestamp)
+{
+       Quark parent;
+       Quark file_pointer;
+       Quark old_file;
+       std::string filename;
+       std::string old_filename;
+       std::string path;
+       int flag;
+
+       if (state_system->attributeExists(proc_quark, "threadparent")) {
+               parent = state_system->getQuark(proc_quark, "threadparent");
+               insert_file(parent, fd, timestamp);
+       }
+
+       path = path_name_from_fd(fd);
+       if (state_system->attributeExists(proc_quark, path + "/file")) {
+               file_pointer = state_system->getQuark(proc_quark, path);
+               get_current_attribute_value_quark(&file_pointer, "file",
+                                                 old_file);
+               get_current_attribute_value_string(&old_file, "name",
+                                                  old_filename);
+               get_current_attribute_value_string(&file, "name", filename);
+               if (old_filename != filename) {
+                       /* Different file with same fd, we overwrite the
+                          file pointer */
+                       modify_attribute(timestamp, &file_pointer, "file",
+                                        file);
+               } else {
+                       modify_attribute(timestamp, &old_file, "flag",
+                                        __NR_open);
+               }
+       } else {
+               file_pointer = state_system->getQuark(proc_quark, path);
+               modify_attribute(timestamp, &file_pointer, "file", file);
+
+       }
+        /* To easily retrieve file pointer from files_history */
+       modify_attribute(timestamp, &file, "fd", fd);
+
+       /* The file may have been created in the parent */
+       get_current_attribute_value_int(&file, "flag", flag);
+       if (flag == -1) {
+               modify_attribute(timestamp, &file, "fd", fd);
+               modify_attribute(timestamp, &file, "flag", __NR_open);
+               increment_attribute(timestamp, NULL, "nbfiles");
+               increment_attribute(timestamp, NULL, "nbnewfiles");
+       }
+}
+
+/*
+ * Edit the file
+ * Called by handled_statedump_filename
+ */
+void edit_file(unsigned long timestamp, Quark proc, Quark file, int fd)
+{
+       std::string path;
+
+       path = path_name_from_fd(fd);
+       if (!state_system->attributeExists(proc, path)) {
+               add_file(proc, file, fd, timestamp);
+       }
+}
+
+Quark create_file(Quark proc, std::string file_name, unsigned long timestamp)
+{
+       Quark file_history;
+       Quark old_newest;
+       bool has_old;
+       std::string current_path;
+       int index;
+       std::stringstream ss;
+
+       if (!get_current_attribute_value_quark(&proc, "files_history/current",
+                                             file_history)) {
+               /* First file for process */
+               file_history = state_system->getQuark(
+                       proc, "files_history/file_0");
+       } else {
+
+               current_path = state_system->getFullAttributeName(file_history);
+               index = atoi(current_path.substr(current_path.find_last_of('_')
+                       + 1).c_str());
+               ss << "files_history/file_" << index + 1;
+               current_path = ss.str();
+               file_history = state_system->getQuark(
+                       proc, current_path);
+       }
+
+       has_old = get_current_attribute_value_quark(
+               &proc,"files_history/current", old_newest);
+       modify_attribute(timestamp, &proc, "files_history/current",
+               file_history);
+       modify_attribute(timestamp, &file_history, "file/name", file_name);
+       modify_attribute(timestamp, &file_history, "file/read", 0);
+       modify_attribute(timestamp, &file_history, "file/write", 0);
+       modify_attribute(timestamp, &file_history, "file/flag", -1);
+       modify_attribute(timestamp, &file_history, "file/fd", -1);
+       modify_attribute(timestamp, &file_history, "file/birth", timestamp);
+       if (has_old)
+               modify_attribute(timestamp, &file_history, "next", old_newest);
+       else
+              nullify_attribute(timestamp, &file_history, "next");
+
+       return state_system->getQuark(file_history, "file");
+}
+
+void insert_file(Quark proc, int fd, unsigned long timestamp)
+{
+       Quark file;
+       Quark parent;
+       Quark parent_file;
+       bool parent_has_file;
+       std::string name;
+
+       if (fd < 0)
+               return;
+
+       if (get_file(proc, fd, file)) {
+               if (state_system->attributeExists(proc, "threadparent")) {
+                       parent = state_system->getQuark(proc, "threadparent");
+                       parent_has_file = get_file(parent, fd,
+                                                  parent_file);
+                       if (parent_has_file) {
+                               get_current_attribute_value_string(&parent_file,
+                                                                  "name",
+                                                                  name);
+                               modify_attribute(timestamp, &file, "name",
+                                                name);
+                       }
+               }
+       } else {
+               file = create_file(proc, "Unknown", timestamp);
+               add_file(proc, file, fd, timestamp);
+       }
+}
+
+void close_file(unsigned long timestamp, Quark proc, int fd)
+{
+       Quark file;
+       bool file_found;
+
+       file_found = get_current_attribute_value_quark(&proc,
+                                                      path_name_from_fd(fd),
+                                                      file);
+       if (file_found) {
+               modify_attribute(timestamp, &file, "flag", __NR_close);
+               decrement_attribute(timestamp, NULL, "nbfiles");
+       }
+       increment_attribute(timestamp, NULL, "nbdeadfiles");
+}
+
+bool get_file(Quark proc_quark, int fd, Quark &file_quark)
+{
+       std::string path = path_name_from_fd(fd);
+       Quark file_pointer;
+       if (state_system->attributeExists(proc_quark, path)) {
+               file_pointer = state_system->getQuark(proc_quark, path);
+               return get_current_attribute_value_quark(&file_pointer, "file",
+                                                        file_quark);
+       } else {
+               return false;
+       }
+}
+
+void show_history(Quark proc)
+{
+       Quark file;
+       int fd;
+       std::string name;
+
+       if (get_current_attribute_value_quark(&proc, "files_history", file)) {
+               do {
+                       fd = -1;
+                       name = "";
+                       get_current_attribute_value_int(&file, "file/fd", fd);
+                       get_current_attribute_value_string(
+                               &file, "file/name", name);
+                       fprintf(stderr, "fd = %d, name = %s\n", fd,
+                               name.c_str());
+               } while (get_current_attribute_value_quark(
+                                &file, "next", file));
+       }
+
+}
+
+int update_iostream_ret(int tid, char *comm, unsigned long timestamp,
+                                 uint64_t cpu_id, int ret)
+{
+       Quark proc_quark;
+       Quark syscall_info_quark;
+       Quark file_quark;
+       Quark file_history_quark;
+       bool file_found;
+       int syscall_type;
+       int fd;
+       int err = 0;
+
+       proc_quark = get_proc(tid, comm, timestamp);
+
+       if (state_system->attributeExists(proc_quark, "syscall_info")) {
+               syscall_info_quark = state_system->getQuark(proc_quark,
+                                                           "syscall_info");
+               get_current_attribute_value_int(&syscall_info_quark, "type",
+                                               syscall_type);
+               if (syscall_type == __NR_read && ret > 0) {
+                       increase_attribute(timestamp, &proc_quark,
+                                          "totalfileread", ret);
+                       increase_attribute(timestamp, &proc_quark,
+                                          "fileread", ret);
+                       get_current_attribute_value_int(&syscall_info_quark,
+                                                       "fd", fd);
+                       file_found = get_file(proc_quark, fd,
+                                                       file_quark);
+                       if (file_found)
+                               increase_attribute(timestamp, &file_quark,
+                                                  "read", ret);
+               } else if (syscall_type == __NR_write && ret > 0) {
+
+                       increase_attribute(timestamp, &proc_quark,
+                                          "totalfilewrite", ret);
+                       increase_attribute(timestamp, &proc_quark,
+                                          "filewrite", ret);
+                       get_current_attribute_value_int(&syscall_info_quark,
+                                                       "fd", fd);
+                       file_found = get_file(proc_quark, fd,
+                                                       file_quark);
+                       if (file_found)
+                               increase_attribute(timestamp, &file_quark,
+                                                  "write", ret);
+               } else if (syscall_type == __NR_open && ret > 0) {
+                       file_history_quark = state_system->getQuark(proc_quark,
+                                                                   "files_history");
+                       file_quark = state_system->getQuark(file_history_quark,
+                                                           "current/file");
+                       add_file(proc_quark, file_quark, ret,
+                                          timestamp);
+                       modify_attribute(timestamp, &file_quark, "fd", fd);
+               } else {
+                       err = -1;
+               }
+       }
+       return err;
+}
+
+void update_syscall_info(unsigned long timestamp, int type, int cpu_id,
+       Quark proc, int fd)
+{
+       int tid;
+
+       get_current_attribute_value_int(&proc, "tid", tid);
+       modify_attribute(timestamp, &proc, "syscall_info/type", type);
+       modify_attribute(timestamp, &proc, "syscall_info/cpu_id", cpu_id);
+       modify_attribute(timestamp, &proc, "syscall_info/tid", tid);
+       modify_attribute(timestamp, &proc, "syscall_info/fd", fd);
+}
+
+enum bt_cb_ret handle_exit_syscall(struct bt_ctf_event *call_data,
+                                            void *private_data)
+{
+       const struct definition *scope;
+       unsigned long timestamp;
+       char *comm;
+       uint64_t ret, tid;
+       uint64_t cpu_id;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       comm = get_context_comm(call_data);
+       tid = get_context_tid(call_data);
+
+       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;
+       }
+
+       cpu_id = get_cpu_id(call_data);
+
+       /*
+        * 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(
+                   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)
+{
+       const struct definition *scope;
+       Quark proc;
+       unsigned long timestamp;
+       int cpu_id;
+       int tid;
+       char *procname;
+       int fd;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       tid = get_context_tid(call_data);
+       cpu_id = get_cpu_id(call_data);
+
+       procname = get_context_comm(call_data);
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
+                                               scope, "_fd"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing fd context info\n");
+               goto error;
+       }
+
+       proc = get_proc(tid, procname, timestamp);
+       update_syscall_info(timestamp, __NR_write, cpu_id, proc, fd);
+
+       insert_file(proc, fd, timestamp);
+
+       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)
+{
+       const struct definition *scope;
+       Quark proc;
+       unsigned long timestamp;
+       uint64_t cpu_id;
+       int64_t tid;
+       char *procname;
+       int fd;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       tid = get_context_tid(call_data);
+       cpu_id = get_cpu_id(call_data);
+
+       procname = get_context_comm(call_data);
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
+                                               scope, "_fd"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing fd context info\n");
+               goto error;
+       }
+
+       proc = get_proc(tid, procname, timestamp);
+       update_syscall_info(timestamp, __NR_read, cpu_id, proc, fd);
+
+       insert_file(proc, fd, timestamp);
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
+
+enum bt_cb_ret handle_sys_open(struct bt_ctf_event *call_data,
+                                        void *private_data)
+{
+       Quark proc;
+       const struct definition *scope;
+       unsigned long timestamp;
+       uint64_t cpu_id;
+       int64_t tid;
+       char *procname;
+       char *file;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       tid = get_context_tid(call_data);
+       cpu_id = get_cpu_id(call_data);
+
+       procname = get_context_comm(call_data);
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       file = bt_ctf_get_string(bt_ctf_get_field(call_data,
+                                                 scope, "_filename"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing file name context info\n");
+               goto error;
+       }
+
+       proc = get_proc(tid, procname, timestamp);
+       update_syscall_info(timestamp, __NR_open, cpu_id, proc, -1);
+
+       create_file(proc, file, timestamp);
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
+
+enum bt_cb_ret handle_sys_close(struct bt_ctf_event *call_data,
+                                         void *private_data)
+{
+       const struct definition *scope;
+       Quark proc;
+       unsigned long timestamp;
+       int64_t tid;
+       char *procname;
+       int fd;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       tid = get_context_tid(call_data);
+
+       procname = get_context_comm(call_data);
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
+                                               scope, "_fd"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing fd context info\n");
+               goto error;
+       }
+
+       proc = get_proc(tid, procname, timestamp);
+
+       close_file(timestamp, proc, fd);
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
+
+enum bt_cb_ret handle_statedump_file_descriptor(
+       struct bt_ctf_event *call_data, void *private_data)
+{
+       const struct definition *scope;
+       Quark parent;
+       Quark file;
+       unsigned long timestamp;
+       int64_t pid;
+       char *file_name;
+       int fd;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       pid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
+                                               scope, "_pid"));
+       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);
+       fd = bt_ctf_get_int64(bt_ctf_get_field(call_data,
+                                              scope, "_fd"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing fd context info\n");
+               goto error;
+       }
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       file_name = bt_ctf_get_string(bt_ctf_get_field(call_data,
+                                                      scope, "_filename"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing file name context info\n");
+               goto error;
+       }
+
+       parent = get_proc_pid(pid, pid, timestamp);
+       create_file(parent, file_name, timestamp);
+       file = state_system->getQuark(parent, "files_history/current/file");
+       edit_file(timestamp, parent, file, fd);
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
index 0124ac6455a780bd6f4ce668100ca8162989cec5..077650737a3ce710342e0d5520d05926d241f484 100644 (file)
 #ifndef _IOSTREANTOP_H
 #define _IOSTREAMTOP_H
 
+extern "C" {
 #include <babeltrace/babeltrace.h>
 #include <babeltrace/ctf/events.h>
+}
 #include <inttypes.h>
 #include <glib.h>
 #include <asm/unistd.h>
 
-struct files *get_file(struct processtop *proc, int fd);
-void show_table(GPtrArray *tab);
-void insert_file(struct processtop *proc, int fd);
+#include "common.h"
+
+bool get_file(Quark proc_quark, int fd, Quark &file_quark);
+void insert_file(Quark proc, int fd, unsigned long timestamp);
+
+void show_history(Quark proc);
 
 enum bt_cb_ret handle_exit_syscall(struct bt_ctf_event *call_data,
-               void *private_data);
+                                  void *private_data);
 enum bt_cb_ret handle_sys_write(struct bt_ctf_event *call_data,
-               void *private_data);
+                               void *private_data);
 enum bt_cb_ret handle_sys_read(struct bt_ctf_event *call_data,
-               void *private_data);
+                              void *private_data);
 enum bt_cb_ret handle_sys_open(struct bt_ctf_event *call_data,
-               void *private_data);
+                              void *private_data);
 enum bt_cb_ret handle_sys_close(struct bt_ctf_event *call_data,
-               void *private_data);
-enum bt_cb_ret handle_statedump_file_descriptor(struct bt_ctf_event *call_data,
-               void *private_data);
+                               void *private_data);
+enum bt_cb_ret handle_statedump_file_descriptor(
+       struct bt_ctf_event *call_data, void *private_data);
 
 #endif /* _IOSTREAMTOP_H */
diff --git a/src/libStateIntegrationPrototype.cpp b/src/libStateIntegrationPrototype.cpp
new file mode 100644 (file)
index 0000000..c8ae1a6
--- /dev/null
@@ -0,0 +1,3 @@
+#include "libStateIntegrationPrototype.h"
+
+
diff --git a/src/libStateIntegrationPrototype.h b/src/libStateIntegrationPrototype.h
new file mode 100644 (file)
index 0000000..64e58ac
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _LIB_STATE_INTEGRATION_PROTOTYPE_H_
+#define _LIB_STATE_INTEGRATION_PROTOTYPE_H_
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/callbacks.h>
+#include <babeltrace/ctf/events.h>
+#include <asm/unistd.h>
+#include "common.h"
+#ifdef __cplusplus
+}
+#endif
+
+
+
+const unsigned long p_refresh_display = 1 * NSEC_PER_SEC;
+
+
+
+
+/* #ifdef __cplusplus */
+/* } */
+/* #endif */
+
+#endif
+
diff --git a/src/lttngtop.c b/src/lttngtop.c
deleted file mode 100644 (file)
index 2ee303a..0000000
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * Copyright (C) 2011-2012 Julien Desfossez
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 <babeltrace/ctf/iterator.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 <assert.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) {
-               if (quit)
-                       return NULL;
-               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);
-       /*
-        * Prevent the 1 second delay when we hit ESC
-        */
-       ESCDELAY = 0;
-       init_ncurses();
-
-       while (1) {
-               sem_wait(&timer);
-               sem_wait(&goodtodisplay);
-               sem_wait(&pause_sem);
-
-               copy = g_ptr_array_index(copies, current_display_index);
-               assert(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;
-       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 = g_new0(struct perfcounter, 1);
-       /* by default, make it visible in the UI */
-       ret->visible = 1;
-       g_hash_table_insert(table, (gpointer) strdup(name), ret);
-
-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(const struct bt_ctf_event *event,
-               const struct definition *scope,
-               struct processtop *proc,
-               struct cputime *cpu)
-{
-       struct definition const * const *list = NULL;
-       const struct definition *field;
-       unsigned int count;
-       struct perfcounter *perfcounter;
-       GHashTableIter iter;
-       gpointer key;
-       int ret;
-
-       if (!scope)
-               goto end;
-
-       ret = bt_ctf_get_field_list(event, scope, &list, &count);
-       if (ret < 0)
-               goto end;
-
-       if (count == 0)
-               goto end;
-
-       g_hash_table_iter_init(&iter, global_perf_liszt);
-       while (g_hash_table_iter_next (&iter, &key, (gpointer) &perfcounter)) {
-               field = bt_ctf_get_field(event, scope, (char *) key);
-               if (field) {
-                       int value = bt_ctf_get_uint64(field);
-                       if (bt_ctf_field_get_error())
-                               continue;
-                       update_perf_value(proc, cpu, (char *) key, value);
-               }
-       }
-
-end:
-       return;
-}
-
-void update_perf_counter(struct processtop *proc, const struct bt_ctf_event *event)
-{
-       struct cputime *cpu;
-       const struct definition *scope;
-
-       cpu = get_cpu(get_cpu_id(event));
-
-       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);
-}
-
-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;
-       unsigned long timestamp;
-
-       timestamp = bt_ctf_get_timestamp(call_data);
-       if (timestamp == -1ULL)
-               goto error;
-
-       pid = get_context_pid(call_data);
-       if (pid == -1ULL) {
-               goto error;
-       }
-       tid = get_context_tid(call_data);
-       if (tid == -1ULL) {
-               goto error;
-       }
-       ppid = get_context_ppid(call_data);
-       if (ppid == -1ULL) {
-               goto error;
-       }
-       comm = get_context_comm(call_data);
-       if (!comm) {
-               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();
-       global_perf_liszt = g_hash_table_new(g_str_hash, g_str_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);
-
-       reset_global_counters();
-       lttngtop.nbproc = 0;
-       lttngtop.nbthreads = 0;
-       lttngtop.nbfiles = 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 *fp)
-{
-       fprintf(fp, "LTTngTop %s\n\n", VERSION);
-       fprintf(fp, "Usage : lttngtop /path/to/trace\n");
-}
-
-/*
- * 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;
-                       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;
-       const 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);
-       /* to get all the process from the statedumps */
-       bt_ctf_iter_add_callback(iter,
-                       g_quark_from_static_string(
-                               "lttng_statedump_process_state"),
-                       NULL, 0, handle_statedump_process_state,
-                       NULL, NULL, NULL);
-
-       /* for IO top */
-       bt_ctf_iter_add_callback(iter,
-                       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);
-       bt_ctf_iter_add_callback(iter,
-                       g_quark_from_static_string("sys_open"),
-                       NULL, 0, handle_sys_open, NULL, NULL, NULL);
-       bt_ctf_iter_add_callback(iter,
-                       g_quark_from_static_string("sys_close"),
-                       NULL, 0, handle_sys_close, NULL, NULL, NULL);
-       bt_ctf_iter_add_callback(iter,
-                       g_quark_from_static_string(
-                                       "lttng_statedump_file_descriptor"),
-                       NULL, 0, handle_statedump_file_descriptor,
-                       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_ctf_iter_destroy(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 = -1;
-
-       /*
-        * 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) {
-                       close(dirfd);
-                       ret = -1;
-                       continue;
-               } 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, "[warning] [Context] opening trace \"%s\" from %s "
-                                       "for reading.\n", node->fts_accpath, path);
-                               /* Allow to skip erroneous traces. */
-                               continue;
-                       }
-                       g_array_append_val(trace_ids, trace_id);
-               }
-       }
-
-       g_array_free(trace_ids, TRUE);
-       return ret;
-
-error:
-       return ret;
-}
-
-static int check_field_requirements(const struct bt_ctf_field_decl *const * field_list,
-               int field_cnt, int *tid_check, int *pid_check,
-               int *procname_check, int *ppid_check)
-{
-       int j;
-       struct perfcounter *global;
-       const char *name;
-
-       for (j = 0; j < field_cnt; j++) {
-               name = bt_ctf_get_decl_field_name(field_list[j]);
-               if (*tid_check == 0) {
-                       if (strncmp(name, "tid", 3) == 0)
-                               (*tid_check)++;
-               }
-               if (*pid_check == 0) {
-                       if (strncmp(name, "tid", 3) == 0)
-                               (*pid_check)++;
-               }
-               if (*ppid_check == 0) {
-                       if (strncmp(name, "ppid", 4) == 0)
-                               (*ppid_check)++;
-               }
-               if (*procname_check == 0) {
-                       if (strncmp(name, "procname", 8) == 0)
-                               (*procname_check)++;
-               }
-               if (strncmp(name, "perf_", 5) == 0) {
-                       global = g_hash_table_lookup(global_perf_liszt, (gpointer) name);
-                       if (!global) {
-                               global = g_new0(struct perfcounter, 1);
-                               /* by default, sort on the first perf context */
-                               if (g_hash_table_size(global_perf_liszt) == 0)
-                                       global->sort = 1;
-                               global->visible = 1;
-                               g_hash_table_insert(global_perf_liszt, (gpointer) strdup(name), global);
-                       }
-               }
-       }
-
-       if (*tid_check == 1 && *pid_check == 1 && *ppid_check == 1 &&
-                       *procname_check == 1)
-               return 0;
-
-       return -1;
-}
-
-/*
- * check_requirements: check if the required context informations are available
- *
- * If each mandatory context information is available for at least in one
- * event, return 0 otherwise return -1.
- */
-int check_requirements(struct bt_context *ctx)
-{
-       unsigned int i, evt_cnt, field_cnt;
-       struct bt_ctf_event_decl *const * evt_list;
-       const struct bt_ctf_field_decl *const * field_list;
-       int tid_check = 0;
-       int pid_check = 0;
-       int procname_check = 0;
-       int ppid_check = 0;
-       int ret = 0;
-
-       bt_ctf_get_event_decl_list(0, ctx, &evt_list, &evt_cnt);
-       for (i = 0; i < evt_cnt; i++) {
-               bt_ctf_get_decl_fields(evt_list[i], BT_STREAM_EVENT_CONTEXT,
-                               &field_list, &field_cnt);
-               ret = check_field_requirements(field_list, field_cnt,
-                               &tid_check, &pid_check, &procname_check,
-                               &ppid_check);
-
-               bt_ctf_get_decl_fields(evt_list[i], BT_EVENT_CONTEXT,
-                               &field_list, &field_cnt);
-               ret = check_field_requirements(field_list, field_cnt,
-                               &tid_check, &pid_check, &procname_check,
-                               &ppid_check);
-
-               bt_ctf_get_decl_fields(evt_list[i], BT_STREAM_PACKET_CONTEXT,
-                               &field_list, &field_cnt);
-               ret = check_field_requirements(field_list, field_cnt,
-                               &tid_check, &pid_check, &procname_check,
-                               &ppid_check);
-       }
-
-       if (tid_check == 0) {
-               ret = -1;
-               fprintf(stderr, "[error] missing tid context information\n");
-       }
-       if (pid_check == 0) {
-               ret = -1;
-               fprintf(stderr, "[error] missing pid context information\n");
-       }
-       if (ppid_check == 0) {
-               ret = -1;
-               fprintf(stderr, "[error] missing ppid context information\n");
-       }
-       if (procname_check == 0) {
-               ret = -1;
-               fprintf(stderr, "[error] missing procname context information\n");
-       }
-
-       return ret;
-}
-
-int main(int argc, char **argv)
-{
-       int ret;
-       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) {
-               fprintf(stderr, "[error] Opening the trace\n");
-               goto end;
-       }
-
-       ret = check_requirements(bt_ctx);
-       if (ret < 0) {
-               fprintf(stderr, "[error] some mandatory contexts were missing, exiting.\n");
-               goto end;
-       }
-
-       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);
-       pthread_join(timer_thread, NULL);
-
-end:
-       bt_context_put(bt_ctx);
-       return 0;
-}
diff --git a/src/lttngtop.cpp b/src/lttngtop.cpp
new file mode 100644 (file)
index 0000000..43afe48
--- /dev/null
@@ -0,0 +1,717 @@
+/*
+ * Copyright (C) 2011-2012 Julien Desfossez
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdint.h>
+extern "C" {
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/callbacks.h>
+#include <babeltrace/ctf/iterator.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 <assert.h>
+
+#include "lttngtoptypes.h"
+#include "cputop.h"
+#include "iostreamtop.h"
+#include "common.h"
+#include "cursesdisplay.h"
+
+#define DEFAULT_FILE_ARRAY_SIZE 1
+
+const char *opt_input_path;
+
+pthread_t display_thread;
+pthread_t timer_thread;
+
+int quit = 0;
+std::string history_file;
+
+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) {
+               if (quit)
+                       return NULL;
+               sem_wait(&pause_sem);
+               sem_post(&pause_sem);
+               sem_post(&timer);
+               sleep(refresh_display/NSEC_PER_SEC);
+       }
+}
+
+void *ncurses_display(void *p)
+{
+       sem_wait(&bootstrap);
+       /*
+        * Prevent the 1 second delay when we hit ESC
+        */
+       ESCDELAY = 0;
+       init_ncurses();
+
+       while (1) {
+               sem_wait(&timer);
+               sem_wait(&goodtodisplay);
+               sem_wait(&pause_sem);
+
+               display();
+
+               sem_post(&goodtoupdate);
+               sem_post(&pause_sem);
+
+               if (quit) {
+                       reset_ncurses();
+                       pthread_exit(0);
+               }
+       }
+}
+
+/*
+ * We soft update each attribute during the execution for perfromance reasons.
+ * Here we write the actual intervals to disk, which are needed to query history.
+ */
+void create_intervals(unsigned long timestamp)
+{
+       StateValue::SharedPtr value;
+
+       for (std::set<Quark>::iterator i = modified_quarks.begin();
+            i != modified_quarks.end();
+            i++) {
+               value = state_system->getCurrentStateValue(*i);
+               /* To force the creation of an interval (which is what we want)
+                  we need to pass a different value than the current value.
+                  We reapply the correct value afterwards */
+               if (std::tr1::dynamic_pointer_cast<NullStateValue>(value)) {
+                       state_system->modifyAttribute(timestamp, *i, 0);
+               } else {
+                       state_system->modifyAttribute(timestamp, *i,
+                                                     StateValue::getNullValue());
+               }
+               state_system->updateCurrentState(*i, value);
+       }
+       modified_quarks.clear();
+}
+
+/*
+ * 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 (first_display_update == 0)
+               first_display_update = timestamp;
+
+       if (timestamp - last_display_update >= refresh_display) {
+               sem_wait(&goodtoupdate);
+               create_intervals(timestamp);
+               update_state_on_refresh(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 (specified by root)
+ */
+Quark get_perf_counter(unsigned long timestamp, Quark root, std::string name)
+{
+       Quark perf_counter;
+
+       if (state_system->attributeExists(root, "perf/" + name)) {
+               return state_system->getQuark(root, "perf/" + name);
+       } else {
+               perf_counter = state_system->getQuark(root, "perf/" + name);
+               modify_attribute(timestamp, &perf_counter, "count", 0);
+               modify_attribute(timestamp, &perf_counter, "visible", 1);
+               add_in_sequence(timestamp, perf_counter,
+                               state_system->getQuark(root, "perf"));
+               return perf_counter;
+       }
+}
+
+void update_perf_value(unsigned long timestamp, Quark proc, Quark cpu,
+                      std::string name, int value)
+{
+       Quark cpu_perf, process_perf;
+       int count;
+
+       cpu_perf = get_perf_counter(timestamp, cpu, name);
+       get_current_attribute_value_int(&cpu_perf, "count", count);
+       if (count < value) {
+               process_perf = get_perf_counter(timestamp, proc, name);
+               increase_attribute(
+                       timestamp, &process_perf, "count", value - count);
+               modify_attribute(timestamp, &cpu_perf, "count", value);
+       }
+}
+
+void extract_perf_counter_scope(unsigned long timestamp,
+                               const struct bt_ctf_event *event,
+                               const struct definition *scope,
+                               Quark proc, Quark cpu)
+{
+       struct definition const * const *list = NULL;
+       const struct definition *field;
+       unsigned int count;
+       int ret;
+       std::string key;
+       Quark perf_quark;
+
+       if (!scope)
+               goto end;
+
+       ret = bt_ctf_get_field_list(event, scope, &list, &count);
+       if (ret < 0)
+               goto end;
+
+       if (count == 0)
+               goto end;
+
+       if (get_current_attribute_value_quark(
+                   NULL, "perf", perf_quark)) {
+               do {
+                       get_current_attribute_value_string(
+                               &perf_quark, "key", key);
+                       field = bt_ctf_get_field(event, scope, key.c_str());
+                       if (field) {
+                               int value = bt_ctf_get_uint64(field);
+                               if (bt_ctf_field_get_error())
+                                       continue;
+                               update_perf_value(
+                                       timestamp, proc, cpu, key, value);
+                       }
+               } while (get_current_attribute_value_quark(
+                                &perf_quark, "next", perf_quark));
+       }
+
+
+end:
+       return;
+}
+
+void update_perf_counter(unsigned long timestamp, Quark proc,
+                        const struct bt_ctf_event *event)
+{
+       Quark cpu;
+       const struct definition *scope;
+
+       cpu = get_cpu(get_cpu_id(event), timestamp);
+
+       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT);
+       extract_perf_counter_scope(timestamp, event, scope, proc, cpu);
+
+       scope = bt_ctf_get_top_level_scope(event, BT_STREAM_PACKET_CONTEXT);
+       extract_perf_counter_scope(timestamp, event, scope, proc, cpu);
+
+       scope = bt_ctf_get_top_level_scope(event, BT_EVENT_CONTEXT);
+       extract_perf_counter_scope(timestamp, event, scope, proc, cpu);
+}
+
+enum bt_cb_ret fix_process_table(struct bt_ctf_event *call_data,
+                                          void *private_data)
+{      int pid, tid, ppid;
+       char *comm;
+       Quark parent, child;
+       unsigned long timestamp;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       pid = get_context_pid(call_data);
+       if ((unsigned long)pid == -1ULL) {
+               goto error;
+       }
+       tid = get_context_tid(call_data);
+       if ((unsigned long)tid == -1ULL) {
+               goto error;
+       }
+       ppid = get_context_ppid(call_data);
+       if ((unsigned long)ppid == -1ULL) {
+               goto error;
+       }
+       comm = get_context_comm(call_data);
+       if (!comm) {
+               goto error;
+       }
+
+       /* find or create the current process */
+       if (!find_process_tid(tid, child))
+               child = add_proc(tid, comm, timestamp);
+       update_proc(timestamp, child, pid, tid, ppid, comm);
+
+       if (pid != tid) {
+               /* find or create the parent */
+               if (!find_process_tid(pid, parent)) {
+                       parent = add_proc(pid, comm, timestamp);
+                       modify_attribute(timestamp, &parent, "pid", pid);
+               }
+
+               /* attach the parent to the current process */
+               modify_attribute(timestamp, &parent, "threadparent", parent);
+               add_thread(timestamp, parent, child);
+       }
+
+       update_perf_counter(timestamp, child, call_data);
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
+
+void init_lttngtop()
+{
+       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);
+
+       // TODO: real file name
+       std::stringstream ss;
+       ss << "history" << time(NULL) << ".hst";
+       history_file = ss.str();
+       IntervalHistoryProvider *ihp = g_new(IntervalHistoryProvider, 1);
+       new (ihp) IntervalHistoryProvider(history_file);
+       state_system = g_new(StateSystem, 1);
+       new (state_system) StateSystem(ihp);
+
+       /* Create global attributes */
+       state_system->updateCurrentState(
+               state_system->getQuark("nbproc"), 0);
+       state_system->updateCurrentState(
+               state_system->getQuark("nbnewproc"), 0);
+       state_system->updateCurrentState(
+               state_system->getQuark("nbdeadproc"), 0);
+       state_system->updateCurrentState(
+               state_system->getQuark("nbthreads"), 0);
+       state_system->updateCurrentState(
+               state_system->getQuark("nbnewthreads"), 0);
+       state_system->updateCurrentState(
+               state_system->getQuark("nbdeadthreads"), 0);
+       state_system->updateCurrentState(
+               state_system->getQuark("nbfiles"), 0);
+       state_system->updateCurrentState(
+               state_system->getQuark("nbnewfiles"), 0);
+       state_system->updateCurrentState(
+               state_system->getQuark("nbdeadfiles"), 0);
+}
+
+void usage(FILE *fp)
+{
+       fprintf(fp, "LTTngTop %s\n\n", VERSION);
+       fprintf(fp, "Usage : lttngtop /path/to/trace\n");
+}
+
+/*
+ * 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;
+                       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;
+       const struct bt_ctf_event *event;
+       int ret = 0;
+
+       begin_pos.type = bt_iter_pos::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);
+       /* to get all the process from the statedumps */
+       bt_ctf_iter_add_callback(iter,
+                       g_quark_from_static_string(
+                               "lttng_statedump_process_state"),
+                       NULL, 0, handle_statedump_process_state,
+                       NULL, NULL, NULL);
+
+       /* for IO top */
+       bt_ctf_iter_add_callback(iter,
+                       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);
+       bt_ctf_iter_add_callback(iter,
+                       g_quark_from_static_string("sys_open"),
+                       NULL, 0, handle_sys_open, NULL, NULL, NULL);
+       bt_ctf_iter_add_callback(iter,
+                       g_quark_from_static_string("sys_close"),
+                       NULL, 0, handle_sys_close, NULL, NULL, NULL);
+       bt_ctf_iter_add_callback(iter,
+                       g_quark_from_static_string(
+                                       "lttng_statedump_file_descriptor"),
+                       NULL, 0, handle_statedump_file_descriptor,
+                       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_ctf_iter_destroy(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 = -1;
+
+       /*
+        * 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) {
+                       close(dirfd);
+                       ret = -1;
+                       continue;
+               } 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, "[warning] [Context] opening trace \"%s\" from %s "
+                                       "for reading.\n", node->fts_accpath, path);
+                               /* Allow to skip erroneous traces. */
+                               continue;
+                       }
+                       g_array_append_val(trace_ids, trace_id);
+               }
+       }
+
+       g_array_free(trace_ids, TRUE);
+       return ret;
+
+error:
+       return ret;
+}
+
+static int check_field_requirements(const struct bt_ctf_field_decl *const * field_list,
+               int field_cnt, int *tid_check, int *pid_check,
+               int *procname_check, int *ppid_check)
+{
+       int j;
+       const char *name;
+       Quark perf;
+       Quark perf_root = state_system->getQuark("perf");
+       static bool first_perf_counter = true;
+
+       for (j = 0; j < field_cnt; j++) {
+               name = bt_ctf_get_decl_field_name(field_list[j]);
+               if (*tid_check == 0) {
+                       if (strncmp(name, "tid", 3) == 0)
+                               (*tid_check)++;
+               }
+               if (*pid_check == 0) {
+                       if (strncmp(name, "tid", 3) == 0)
+                               (*pid_check)++;
+               }
+               if (*ppid_check == 0) {
+                       if (strncmp(name, "ppid", 4) == 0)
+                               (*ppid_check)++;
+               }
+               if (*procname_check == 0) {
+                       if (strncmp(name, "procname", 8) == 0)
+                               (*procname_check)++;
+               }
+               if (strncmp(name, "perf_", 5) == 0) {
+                       if (!state_system->attributeExists(
+                                   perf_root, name+5)) {
+                               perf = state_system->getQuark(perf_root, name+5);
+                               /* by default, sort on the first perf context */
+                               if (first_perf_counter) {
+                                       modify_attribute(0, &perf, "sort", 1);
+                                       first_perf_counter = false;
+                               }
+                               modify_attribute(0, &perf, "visible", 1);
+                               add_in_sequence(0, perf, perf_root);
+                       }
+               }
+       }
+
+       if (*tid_check == 1 && *pid_check == 1 && *ppid_check == 1 &&
+                       *procname_check == 1)
+               return 0;
+
+       return -1;
+}
+
+/*
+ * check_requirements: check if the required context informations are available
+ *
+ * If each mandatory context information is available for at least in one
+ * event, return 0 otherwise return -1.
+ */
+int check_requirements(struct bt_context *ctx)
+{
+       unsigned int i, evt_cnt, field_cnt;
+       struct bt_ctf_event_decl *const * evt_list;
+       const struct bt_ctf_field_decl *const * field_list;
+       int tid_check = 0;
+       int pid_check = 0;
+       int procname_check = 0;
+       int ppid_check = 0;
+       int ret = 0;
+
+       bt_ctf_get_event_decl_list(0, ctx, &evt_list, &evt_cnt);
+       for (i = 0; i < evt_cnt; i++) {
+               bt_ctf_get_decl_fields(evt_list[i], BT_STREAM_EVENT_CONTEXT,
+                               &field_list, &field_cnt);
+               ret = check_field_requirements(field_list, field_cnt,
+                               &tid_check, &pid_check, &procname_check,
+                               &ppid_check);
+
+               bt_ctf_get_decl_fields(evt_list[i], BT_EVENT_CONTEXT,
+                               &field_list, &field_cnt);
+               ret = check_field_requirements(field_list, field_cnt,
+                               &tid_check, &pid_check, &procname_check,
+                               &ppid_check);
+
+               bt_ctf_get_decl_fields(evt_list[i], BT_STREAM_PACKET_CONTEXT,
+                               &field_list, &field_cnt);
+               ret = check_field_requirements(field_list, field_cnt,
+                               &tid_check, &pid_check, &procname_check,
+                               &ppid_check);
+       }
+
+       if (tid_check == 0) {
+               ret = -1;
+               fprintf(stderr, "[error] missing tid context information\n");
+       }
+       if (pid_check == 0) {
+               ret = -1;
+               fprintf(stderr, "[error] missing pid context information\n");
+       }
+       if (ppid_check == 0) {
+               ret = -1;
+               fprintf(stderr, "[error] missing ppid context information\n");
+       }
+       if (procname_check == 0) {
+               ret = -1;
+               fprintf(stderr, "[error] missing procname context information\n");
+       }
+
+       return ret;
+}
+
+int main(int argc, char **argv)
+{
+       int ret;
+       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) {
+               fprintf(stderr, "[error] Opening the trace\n");
+               goto end;
+       }
+
+       ret = check_requirements(bt_ctx);
+       if (ret < 0) {
+               fprintf(stderr, "[error] some mandatory contexts were missing, exiting.\n");
+               goto end;
+       }
+
+       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);
+       pthread_join(timer_thread, NULL);
+
+end:
+       bt_context_put(bt_ctx);
+       return 0;
+}
index c69ea0192c56657b1eb99ab850f7324fec5c1dd8..3a75c9deffe17b645ea5979db14d082b81c053e8 100644 (file)
 
 #include <glib.h>
 
-struct lttngtop {
-       GPtrArray *process_table;       /* struct processtop */
-       GPtrArray *files_table;         /* struct files */
-       GPtrArray *cpu_table;           /* struct cputime */
-       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;
-       /* Files managing */
-       GPtrArray *process_files_table;
-       struct file_history *files_history;
-       GPtrArray *threads;
-       GHashTable *perf;
-       struct processtop *threadparent;
-       /* IO calculting */
-       unsigned long totalfileread;
-       unsigned long totalfilewrite;
-       unsigned long fileread;
-       unsigned long filewrite;
-       struct syscalls *syscall_info;
-       unsigned long totalcpunsec;
-       unsigned long threadstotalcpunsec;
-};
-
-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;
-       int flag;
-       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 file_history {
-       struct files *file;
-       struct file_history *next;
-};
-
-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;
-       uint64_t cpu_id;
-       unsigned int type;
-       unsigned int tid;
-       unsigned int fd;
-};
-
-struct signals {
-       int dest_pid;
-       int id;
-       unsigned long count;
-};
-
-struct file_info {
-       struct file_info *next;
-       char *name;
-       int fd;
-       int status;
-};
-
 /* header for cputop display */
 struct header_view {
        char *title;
This page took 0.140388 seconds and 4 git commands to generate.