Convert LTTngTop to C++ and state system
[lttngtop.git] / src / common.cpp
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;
+}
This page took 0.034802 seconds and 4 git commands to generate.