newproc->tid = tid;
newproc->birth = timestamp;
newproc->process_files_table = g_ptr_array_new();
+ newproc->files_history = g_new0(struct file_history, 1);
+ newproc->files_history->next = NULL;
+ newproc->totalfileread = 0;
+ newproc->totalfilewrite = 0;
+ newproc->fileread = 0;
+ newproc->filewrite = 0;
+ newproc->syscall_info = NULL;
newproc->threads = g_ptr_array_new();
newproc->perf = g_hash_table_new(g_str_hash, g_str_equal);
- newproc->iostream = g_new0(struct iostream, 1);
- newproc->iostream->ret_read = 0;
- newproc->iostream->ret_write = 0;
- newproc->iostream->ret_total = 0;
- newproc->iostream->syscall_info = NULL;
g_ptr_array_add(ctx->process_table, newproc);
}
newproc->comm = strdup(comm);
void cleanup_processtop()
{
- gint i;
+ 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->iostream->ret_read = 0;
- tmp->iostream->ret_write = 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;
+ }
+ }
}
}
new->perf = g_hash_table_new(g_str_hash, g_str_equal);
g_hash_table_foreach(tmp->perf, copy_perf_counter, new->perf);
- new->iostream = g_new0(struct iostream, 1);
- memcpy(new->iostream, tmp->iostream, sizeof(struct iostream));
/* compute the stream speed */
if (end - start != 0) {
time = (end - start) / NSEC_PER_SEC;
- new->iostream->ret_read = new->iostream->ret_read / time;
- new->iostream->ret_write = new->iostream->ret_write / time;
+ 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 = g_new0(struct files, 1);
-
- 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);
+ 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
#include "cursesdisplay.h"
#include "lttngtoptypes.h"
+#include "iostreamtop.h"
#include "common.h"
#define DEFAULT_DELAY 15
wmove(status, ++current_line, 1);
current_char = 1;
} else {
- mvwprintw(status, current_line, current_char++, "%c", log_lines[i]);
+ mvwprintw(status, current_line, current_char++, "%c",
+ log_lines[i]);
}
}
wrefresh(status);
unsigned long elapsed;
double maxcputime;
struct processtop *tmp = find_process_tid(data, selected_tid, selected_comm);
+ struct files *file_tmp;
+ int i, j = 0;
set_window_title(center, "Process details");
wprintw(center, "%d", tmp->ppid);
print_key_title("CPU", 5);
wprintw(center, "%1.2f %%", tmp->totalcpunsec/maxcputime);
+
+ print_key_title("READ B/s", 6);
+ wprintw(center, "%d", tmp->fileread);
+
+ print_key_title("WRITE B/s", 7);
+ wprintw(center, "%d", tmp->filewrite);
+
+ for (i = 0; i < tmp->process_files_table->len; i++) {
+ file_tmp = get_file(tmp, i);
+ if (file_tmp != NULL) {
+ print_key_title("file", 8+j);
+ wprintw(center, "%s fd = %d", file_tmp->name, i);
+ wprintw(center, " read = %d", file_tmp->read);
+ wprintw(center, " write = %d", file_tmp->write);
+ j++;
+ }
+ }
}
void update_perf()
value = perfn2->count;
else
value = 0;
- mvwprintw(center, current_line + header_offset, perf_row, "%d", value);
+ mvwprintw(center, current_line + header_offset,
+ perf_row, "%d", value);
perf_row += 20;
}
}
{
struct processtop *n1 = *(struct processtop **)p1;
struct processtop *n2 = *(struct processtop **)p2;
- unsigned long totaln1 = n1->iostream->ret_total;
- unsigned long totaln2 = n2->iostream->ret_total;
+
+ unsigned long totaln1 = n1->totalfileread + n1->totalfilewrite;
+ unsigned long totaln2 = n2->totalfileread + n2->totalfilewrite;
if (totaln1 < totaln2)
return 1;
struct processtop *tmp;
int nblinedisplayed = 0;
int current_line = 0;
+ int total = 0;
set_window_title(center, "IO Top");
wattron(center, A_BOLD);
wattron(center, COLOR_PAIR(5));
mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
}
+
/* READ (bytes/sec) */
mvwprintw(center, current_line + header_offset, 1, "%lu",
- tmp->iostream->ret_read);
+ tmp->fileread);
/* WRITE (bytes/sec) */
mvwprintw(center, current_line + header_offset, 20, "%lu",
- tmp->iostream->ret_write);
+ tmp->filewrite);
/* TOTAL STREAM */
- if(tmp->iostream->ret_total >= 1000000)
+ total = tmp->totalfileread + tmp->totalfilewrite;
+
+ if (total >= 1000000)
mvwprintw(center, current_line + header_offset, 40, "%lu MB",
- tmp->iostream->ret_total/1000000);
- else if(tmp->iostream->ret_total >=1000)
+ total/1000000);
+ else if (total >= 1000)
mvwprintw(center, current_line + header_offset, 40, "%lu KB",
- tmp->iostream->ret_total/1000);
+ total/1000);
else
mvwprintw(center, current_line + header_offset, 40, "%lu B",
- tmp->iostream->ret_total);
+ total);
+
/* TGID */
mvwprintw(center, current_line + header_offset, 60, "%d", tmp->pid);
/* PID */
box(perf_panel_window, 0 , 0);
set_window_title(perf_panel_window, "Perf Preferences ");
wattron(perf_panel_window, A_BOLD);
- mvwprintw(perf_panel_window, g_hash_table_size(data->perf_list) + 1, 1, " 's' to sort");
+ mvwprintw(perf_panel_window, g_hash_table_size(data->perf_list) + 1, 1,
+ " 's' to sort");
wattroff(perf_panel_window, A_BOLD);
if (toggle_sort == 1) {
toggle_perf_panel();
break;
default:
- /*
- * commented because it makes the list refresh in different order
- * if we sort and there are equal values
- if (data)
- update_current_view();
- */
+ if (data)
+ update_current_view();
break;
}
update_footer();
* MA 02111-1307, 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"
-#include <stdlib.h>
+void add_file(struct processtop *proc, struct files *file, int fd)
+{
+ if (proc->process_files_table->len <= fd) {
+ g_ptr_array_set_size(proc->process_files_table, fd);
+ g_ptr_array_add(proc->process_files_table, file);
+ } else {
+ g_ptr_array_index(proc->process_files_table, fd) = file;
+ }
+ file->fd = fd;
+}
+
+
+void insert_file(struct processtop *proc, int fd)
+{
+ struct files *tmp;
+
+ if (fd >= proc->process_files_table->len) {
+ tmp = g_new0(struct files, 1);
+ tmp->name = "Unknown";
+ 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;
+ add_file(proc, tmp, fd);
+ }
+ }
+}
+
+void close_file(struct processtop *proc, int fd)
+{
+ int len;
+
+ 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) {
+ g_ptr_array_remove_index_fast(proc->process_files_table, fd);
+ g_ptr_array_set_size(proc->process_files_table, len + 1);
+ }
+}
+
+struct files *get_file(struct processtop *proc, int fd)
+{
+ struct files *tmp;
+ 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");
+}
int update_iostream_ret(struct lttngtop *ctx, int tid, char *comm,
unsigned long timestamp, int cpu_id, int ret)
{
struct processtop *tmp;
+ struct files *tmpfile;
int err = 0;
tmp = get_proc(ctx, tid, comm, timestamp);
- if ((tmp->iostream->syscall_info != NULL) && (tmp->iostream->syscall_info->cpu_id == cpu_id)) {
- if (tmp->iostream->syscall_info->type == __NR_read && ret > 0) {
- tmp->iostream->ret_read += ret;
- tmp->iostream->ret_total += ret;
- } else if(tmp->iostream->syscall_info->type == __NR_write && ret > 0) {
- tmp->iostream->ret_write += ret;
- tmp->iostream->ret_total += ret;
- } else{
+
+ 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);
+ 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);
+ tmpfile->write += ret;
+ } else if (tmp->syscall_info->type == __NR_open
+ && ret > 0) {
+ add_file(tmp, tmp->files_history->file, ret);
+ } else {
err = -1;
}
- free(tmp->iostream->syscall_info);
- tmp->iostream->syscall_info = NULL;
- }
-
+ g_free(tmp->syscall_info);
+ tmp->syscall_info = NULL;
+ }
return err;
}
+struct syscalls *create_syscall_info(unsigned int type, unsigned int 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_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)
{
}
/*
- * if we encounter an exit_syscall and it is not for a syscall read or write
+ * 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(<tngtop, tid, comm, timestamp, cpu_id, ret)) < 0)
{
struct definition *scope;
struct processtop *tmp;
- struct syscalls *syscall_info;
unsigned long timestamp;
uint64_t cpu_id;
char *comm;
int64_t tid;
+ int fd;
timestamp = bt_ctf_get_timestamp(call_data);
if (timestamp == -1ULL)
goto error;
}
- syscall_info = malloc(sizeof(struct syscalls));
- syscall_info->cpu_id = cpu_id;
- syscall_info->type = __NR_write;
- syscall_info->tid = tid;
+ 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(<tngtop, tid, comm, timestamp);
- tmp->iostream->syscall_info = syscall_info;
+ tmp->syscall_info = create_syscall_info(__NR_write, cpu_id, tid, fd);
+
+ insert_file(tmp, fd);
return BT_CB_OK;
{
struct processtop *tmp;
struct definition *scope;
- struct syscalls * syscall_info;
unsigned long timestamp;
uint64_t cpu_id;
char *comm;
int64_t tid;
+ int fd;
timestamp = bt_ctf_get_timestamp(call_data);
if (timestamp == -1ULL)
goto error;
}
- syscall_info = malloc(sizeof(struct syscalls));
- syscall_info->cpu_id = cpu_id;
- syscall_info->type = __NR_read;
- syscall_info->tid = tid;
+ 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(<tngtop, tid, comm, 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;
+ struct definition *scope;
+ unsigned long timestamp;
+ uint64_t cpu_id;
+ char *comm;
+ int64_t tid;
+ char *file;
+
+ timestamp = bt_ctf_get_timestamp(call_data);
+ if (timestamp == -1ULL)
+ goto error;
+
+ scope = bt_ctf_get_top_level_scope(call_data,
+ BT_STREAM_EVENT_CONTEXT);
+ comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
+ scope, "_procname"));
+ if (bt_ctf_field_get_error()) {
+ fprintf(stderr, "Missing procname context info\n");
+ goto error;
+ }
+
+ tid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
+ scope, "_tid"));
+ if (bt_ctf_field_get_error()) {
+ fprintf(stderr, "Missing tid context info\n");
+ goto error;
+ }
+
+ scope = bt_ctf_get_top_level_scope(call_data,
+ BT_STREAM_PACKET_CONTEXT);
+ cpu_id = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
+ scope, "cpu_id"));
+ if (bt_ctf_field_get_error()) {
+ fprintf(stderr, "Missing cpu_id context info\n");
+ goto error;
+ }
+
+ 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 fd context info\n");
+ goto error;
+ }
+
tmp = get_proc(<tngtop, tid, comm, timestamp);
- tmp->iostream->syscall_info = syscall_info;
+ 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;
return BT_CB_ERROR_STOP;
}
+
+enum bt_cb_ret handle_sys_close(struct bt_ctf_event *call_data,
+ void *private_data)
+{
+ struct definition *scope;
+ unsigned long timestamp;
+ int64_t tid;
+ struct processtop *tmp;
+ char *comm;
+ int fd;
+
+ timestamp = bt_ctf_get_timestamp(call_data);
+ if (timestamp == -1ULL)
+ goto error;
+
+ scope = bt_ctf_get_top_level_scope(call_data,
+ BT_STREAM_EVENT_CONTEXT);
+ comm = bt_ctf_get_char_array(bt_ctf_get_field(call_data,
+ scope, "_procname"));
+ if (bt_ctf_field_get_error()) {
+ fprintf(stderr, "Missing procname context info\n");
+ goto error;
+ }
+
+ tid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
+ scope, "_tid"));
+ if (bt_ctf_field_get_error()) {
+ fprintf(stderr, "Missing tid context info\n");
+ goto error;
+ }
+
+ scope = bt_ctf_get_top_level_scope(call_data,
+ BT_EVENT_FIELDS);
+ 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(<tngtop, tid, comm, timestamp);
+ close_file(tmp, fd);
+
+ return BT_CB_OK;
+
+error:
+ return BT_CB_ERROR_STOP;
+}
#define _IOSTREAMTOP_H
#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
#include <inttypes.h>
#include <glib.h>
#include <asm/unistd.h>
-/*
-#define SYS_READ 1
-#define SYS_WRITE 2
-*/
+struct files *get_file(struct processtop *proc, int fd);
+void show_table(GPtrArray *tab);
enum bt_cb_ret handle_exit_syscall(struct bt_ctf_event *call_data,
void *private_data);
-
enum bt_cb_ret handle_sys_write(struct bt_ctf_event *call_data,
void *private_data);
-
enum bt_cb_ret handle_sys_read(struct bt_ctf_event *call_data,
void *private_data);
+enum bt_cb_ret handle_sys_open(struct bt_ctf_event *call_data,
+ void *private_data);
+enum bt_cb_ret handle_sys_close(struct bt_ctf_event *call_data,
+ void *private_data);
#endif /* _IOSTREAMTOP_H */
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);
while ((event = bt_ctf_iter_read_event(iter)) != NULL) {
ret = bt_iter_next(bt_ctf_get_iter(iter));
if (ret < 0)
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;
- /* IO speed for this process */
- struct iostream *iostream;
};
struct perfcounter
/* 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 */
struct syscalls {
unsigned int id;
unsigned long count;
- unsigned int cpu_id;
- unsigned int type;
- unsigned int tid;
+ unsigned int cpu_id;
+ unsigned int type;
+ unsigned int tid;
+ unsigned int fd;
};
struct signals {
unsigned long count;
};
-struct iostream {
- struct syscalls *syscall_info; /* NULL if there is no waiting for an exit_syscall */
- unsigned long ret_read; /* value returned by an I/O syscall_exit for a sys_read*/
- unsigned long ret_write; /* value returned by an I/O syscall_exit for a sys_write*/
- unsigned long ret_total;
+struct file_info {
+ struct file_info *next;
+ char *name;
+ int fd;
+ int status;
};
#endif /* LTTNGTOPTYPES_H */