X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Fiostreamtop.cpp;fp=src%2Fiostreamtop.cpp;h=3e96c60c137171a46d990e072300e81dc9f6cab6;hb=715cf83c121d2aeac7ae030d49ff5a31bd6b9ac5;hp=0000000000000000000000000000000000000000;hpb=62895477c7e60525e63e9e5117f92b34d467d0e6;p=lttngtop.git diff --git a/src/iostreamtop.cpp b/src/iostreamtop.cpp new file mode 100644 index 0000000..3e96c60 --- /dev/null +++ b/src/iostreamtop.cpp @@ -0,0 +1,540 @@ +/* + * Copyright (C) 2011-2012 Mathieu Bain + * + * 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 +#include +#include +#include +#include +extern "C" +{ +#include +} + +#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; +}