Add 6 tools tracking dbus. 26/150426/5
authorDawid Kuczma <d.kuczma@partner.samsung.com>
Fri, 15 Sep 2017 10:39:40 +0000 (12:39 +0200)
committerDawid Kuczma <d.kuczma@partner.samsung.com>
Fri, 29 Sep 2017 09:11:48 +0000 (11:11 +0200)
- messages size (dbus and gdbus)
- number of messages sent
- dbus procesor time usage
- glib procesor time usage
- message type
- message latency (dbus and gdbus)

Change-Id: Ie283b427581f12ea76dc342c4e3c4eb71ef72486

13 files changed:
packaging/bcc-tools.spec
tools/dbus-connection-message-size.c [new file with mode: 0644]
tools/dbus-connection-message-size.py [new file with mode: 0755]
tools/dbus-glib-tok.py [new file with mode: 0755]
tools/dbus-latency.c [new file with mode: 0644]
tools/dbus-latency.py [new file with mode: 0755]
tools/dbus-message-size.c [new file with mode: 0644]
tools/dbus-message-size.py [new file with mode: 0755]
tools/dbus-message-type.c [new file with mode: 0644]
tools/dbus-message-type.py [new file with mode: 0755]
tools/dbus-messages-sent.py [new file with mode: 0755]
tools/dbus-tok.c [new file with mode: 0644]
tools/dbus-tok.py [new file with mode: 0755]

index dbb2691..134af99 100644 (file)
@@ -28,6 +28,15 @@ License: Apache-2.0
 bcc tools - devel
 This package provides development libraries.
 
+%package dbus
+Summary: Tools for monitoring dbus
+License: Apache-2.0
+
+%description dbus
+bcc tools - dbus
+This package provides tools for tracking dbus.
+
+
 %prep
 %setup -q -n bcc-tools-%{version}
 
@@ -53,6 +62,9 @@ rm -rf %{buildroot}
 %{_prefix}/lib/python2.7/site-packages/bcc*
 %{_datadir}/bcc/*
 
+%files dbus
+%{_datadir}/bcc/tools/dbus-*
+
 %files devel
 %{_includedir}/*
 %{_libdir}/libbcc.so
diff --git a/tools/dbus-connection-message-size.c b/tools/dbus-connection-message-size.c
new file mode 100644 (file)
index 0000000..8d1a7f2
--- /dev/null
@@ -0,0 +1,130 @@
+#include <uapi/linux/ptrace.h>
+#include <linux/sched.h>
+
+struct DBusString {
+       void *str;
+       int len;
+       unsigned int allocated;
+       unsigned int constant : 1;
+       unsigned int locked : 1;
+       unsigned int invalid : 1;
+       unsigned int align_offset : 3;
+};
+
+struct DBusHeaderFields {
+       int value_pos;
+};
+
+struct DBusHeader {
+       struct DBusString data;
+
+       struct DBusHeaderFields fields[9];
+
+       u32 padding;
+       u32 byte_order;
+       unsigned char protocol_version;
+};
+
+struct DBusMessage {
+       int refcount;
+       struct DBusHeader header;
+       struct DBusString body;
+
+       unsigned int locked : 1;
+
+       void * list;
+       long size_counter_delta;
+       int timeout_ms;
+
+       u32 changed_stamp : 21;
+       void *slot_list;
+
+       int generation;
+
+       int *unix_fds;
+
+       unsigned n_unix_fds;
+       unsigned n_unix_fds_allocated;
+
+       long unix_fd_counter_delta;
+
+       struct DBusString *signature;
+       struct DBusString *unique_sender;
+       size_t gvariant_body_last_offset;
+       size_t gvariant_body_last_pos;
+};
+
+struct data_t {
+       u32 pid;
+       char comm[TASK_COMM_LEN];
+};
+
+struct bytes_t {
+       int bytes;
+};
+
+BPF_HASH(g_message, struct data_t, unsigned long *)
+BPF_HASH(msg_size, struct data_t, struct bytes_t)
+BPF_HISTOGRAM(msg_size_hist)
+
+static int get_process_data(struct data_t *data) {
+       data->pid = bpf_get_current_pid_tgid();
+       bpf_get_current_comm(&data->comm, sizeof(data->comm));
+       return 0;
+}
+
+static int message_size(unsigned long size) {
+       struct data_t data = {};
+       get_process_data(&data);
+       if (size != 0) {
+               msg_size_hist.increment(bpf_log2l(size));
+               struct bytes_t bytes_sent = {size};
+               struct bytes_t *bytes_prev = msg_size.lookup(&data);
+               if (bytes_prev != 0) {
+                       bytes_sent.bytes += bytes_prev->bytes;
+                       msg_size.update(&data, &bytes_sent);
+               }
+               else {
+                       msg_size.insert(&data, &bytes_sent);
+               }
+       }
+       return 0;
+}
+
+int g_get_size_pointer (struct pt_regs *ctx, void *dummy, unsigned long *size) {
+       struct data_t data = {};
+       get_process_data(&data);
+       g_message.insert(&data, &size);
+       return 0;
+}
+
+int g_get_message_size(struct pt_regs *ctx) {
+       struct data_t data = {};
+       get_process_data(&data);
+       unsigned long **ptr_gsize;
+       ptr_gsize = g_message.lookup(&data);
+       if (ptr_gsize == 0) {
+               return 0;
+       }
+       unsigned long *gsize = *ptr_gsize;
+       unsigned long size  = 0;
+       bpf_probe_read(&size, sizeof(size), gsize);
+       if(size > 0 && size < 1000000) {
+               message_size(size);
+       }
+       return 0;
+}
+
+int dbus_message_size(struct pt_regs *ctx, void *conn, struct DBusMessage *message) {
+       unsigned long size = 0;
+        if (message->header.data.len > 0) {
+                size += message->header.data.len;
+        }
+        if (message->body.len > 0) {
+                size += message->body.len;
+        }
+       if (size != 0) {
+               message_size(size);
+       }
+       return 0;
+}
diff --git a/tools/dbus-connection-message-size.py b/tools/dbus-connection-message-size.py
new file mode 100755 (executable)
index 0000000..64451cf
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+
+from bcc import BPF
+from time import sleep
+from ctypes import c_ushort, c_int
+from sys import argv
+
+def usage():
+       print("USAGE: %s [--process|histogram]" % argv[0])
+       exit()
+
+display_mode = 0
+if len(argv) != 2:
+       usage()
+if argv[1] == "--histogram":
+       display_mode = 1
+elif argv[1] != "--process":
+       usage()
+
+
+b=BPF(src_file="dbus-connection-message-size.c", debug=0)
+b.attach_uprobe(name="dbus-1", sym="_dbus_connection_message_sent_unlocked", fn_name="dbus_message_size")
+b.attach_uprobe(name="gio-2.0", sym="g_dbus_message_to_blob", fn_name="g_get_size_pointer")
+b.attach_uretprobe(name="gio-2.0", sym="g_dbus_message_to_blob", fn_name="g_get_message_size")
+
+interval = 5
+loops = 100
+count = 0
+
+while (1):
+       count += 1
+       if count == loops:
+               exit()
+       sleep(interval)
+       print ("\n%d:\n" % count)
+       if display_mode == 0:
+               stats = b["msg_size"]
+               for v, p in sorted(stats.items(), key=lambda stats: stats[1].bytes, reverse=True):
+                       print("%10d %20s %20ld" %(v.pid, v.comm.encode('string-escape'), int(p.bytes)))
+       else:
+               b["msg_size_hist"].print_log2_hist("bytes")
diff --git a/tools/dbus-glib-tok.py b/tools/dbus-glib-tok.py
new file mode 100755 (executable)
index 0000000..3be925b
--- /dev/null
@@ -0,0 +1,191 @@
+#!/usr/bin/python
+
+from bcc import BPF
+from time import sleep
+from ctypes import c_ushort, c_int, c_ulonglong
+from sys import argv
+
+
+print("Hit Ctrl-C to end.")
+count = 100
+interval = 5
+loop = 0
+# load BPF program
+bpf_text="""#include <uapi/linux/ptrace.h>
+#include <linux/sched.h>
+
+typedef struct pdata_T {
+       u32 pid;
+       char buf[TASK_COMM_LEN];
+       u64 drun;
+       u64 dwait;
+       u64 grun;
+       u64 gwait;
+       u64 usage;
+}pdata_t;
+
+BPF_HASH(timestamp_b, u64);
+BPF_HASH(timestamp_e, u64);
+BPF_HASH(stats, u32, pdata_t, sizeof(pdata_t));
+BPF_HASH(run_start, u32);
+BPF_HASH(wait_start, u32);
+
+BPF_HISTOGRAM(dist);
+
+int do_entry_dbus(struct pt_regs *ctx) {
+       u64 time = 0;
+       pdata_t pdata;
+       pdata_t new_pdata = {0, ' ', 0, 0, 0, 0, 0};
+       u64 ts, *tsp, delta;
+       u32 pid;
+
+       ts = bpf_ktime_get_ns() / 1000;
+       if(timestamp_b.lookup(&time) == 0){
+               timestamp_b.update(&time, &ts);
+       }
+       timestamp_e.update(&time, &ts);
+
+       pid = bpf_get_current_pid_tgid();
+       tsp = run_start.lookup(&pid);
+       run_start.delete(&pid);
+       wait_start.update(&pid, &ts);
+       if(tsp != 0) {
+               delta = ts -*tsp;
+       }
+       else {
+               return 0;
+       }
+       new_pdata.pid = pid;
+       pdata = *(stats.lookup_or_init(&pid, &new_pdata));
+       pdata.drun += delta;
+       pdata.usage += delta;
+       bpf_get_current_comm(&(pdata.buf), sizeof(pdata.buf));
+       stats.update(&pid, &pdata);
+       return 0;
+}
+
+int do_return_dbus(struct pt_regs *ctx) {
+       u64 time = 0;
+       pdata_t pdata;
+       pdata_t new_pdata = {0, ' ', 0, 0, 0, 0, 0};
+       u64 ts, *tsp, delta;
+       u32 pid;
+
+       ts = bpf_ktime_get_ns() / 1000;
+       if(timestamp_b.lookup(&time) == 0){
+               timestamp_b.update(&time, &ts);
+       }
+       timestamp_e.update(&time, &ts);
+
+       pid = bpf_get_current_pid_tgid();
+       tsp = wait_start.lookup(&pid);
+       wait_start.delete(&pid);
+       run_start.update(&pid, &ts);
+       if(tsp != 0) {
+               delta = ts - *tsp;
+       }
+       else {
+               return 0;
+       }
+       new_pdata.pid = pid;
+       pdata = *(stats.lookup_or_init(&pid, &new_pdata));
+       pdata.dwait += delta;
+       bpf_get_current_comm(&(pdata.buf), sizeof(pdata.buf));
+       stats.update(&pid, &pdata);
+       return 0;
+}
+
+int do_entry_glib(struct pt_regs *ctx) {
+       u64 time = 0;
+       pdata_t pdata;
+       pdata_t new_pdata = {0, ' ', 0, 0, 0, 0, 0};
+       u64 ts, *tsp, delta;
+       u32 pid;
+
+       ts = bpf_ktime_get_ns() / 1000;
+       if(timestamp_b.lookup(&time) == 0){
+               timestamp_b.update(&time, &ts);
+       }
+       timestamp_e.update(&time, &ts);
+
+       pid = bpf_get_current_pid_tgid();
+       tsp = run_start.lookup(&pid);
+       run_start.delete(&pid);
+       wait_start.update(&pid, &ts);
+       if(tsp != 0) {
+               delta = ts -*tsp;
+       }
+       else {
+               return 0;
+       }
+       new_pdata.pid = pid;
+       pdata = *(stats.lookup_or_init(&pid, &new_pdata));
+       pdata.grun += delta;
+       pdata.usage += delta;
+       bpf_get_current_comm(&(pdata.buf), sizeof(pdata.buf));
+       stats.update(&pid, &pdata);
+       return 0;
+}
+
+int do_return_glib(struct pt_regs *ctx) {
+       u64 time = 0;
+       pdata_t pdata;
+       pdata_t new_pdata = {0, ' ', 0, 0, 0, 0, 0};
+       u64 ts, *tsp, delta;
+       u32 pid;
+
+       ts = bpf_ktime_get_ns() / 1000;
+       if(timestamp_b.lookup(&time) == 0){
+               timestamp_b.update(&time, &ts);
+       }
+       timestamp_e.update(&time, &ts);
+
+       pid = bpf_get_current_pid_tgid();
+       tsp = wait_start.lookup(&pid);
+       wait_start.delete(&pid);
+       run_start.update(&pid, &ts);
+       if(tsp != 0) {
+               delta = ts - *tsp;
+       }
+       else {
+               return 0;
+       }
+       new_pdata.pid = pid;
+       pdata = *(stats.lookup_or_init(&pid, &new_pdata));
+       pdata.gwait += delta;
+       bpf_get_current_comm(&(pdata.buf), sizeof(pdata.buf));
+       stats.update(&pid, &pdata);
+       return 0;
+}
+"""
+
+b = BPF(text=bpf_text)
+
+b.attach_uprobe(name="glib-2.0", sym="g_poll", fn_name="do_entry_glib")
+b.attach_uprobe(name="dbus-1", sym="_dbus_poll", fn_name="do_entry_dbus")
+
+b.attach_uretprobe(name="dbus-1", sym="_dbus_poll", fn_name="do_return_dbus")
+b.attach_uretprobe(name="glib-2.0", sym="g_poll", fn_name="do_return_glib")
+
+while (1):
+       if count > 0:
+
+               loop += 1
+               if loop > count:
+                       exit()
+       sleep(interval)
+       print ("%d : \n" % loop)
+       b["dist"].print_log2_hist("usecs")
+       b["dist"].clear()
+       stats_t = b["stats"]
+       timestamp = b["timestamp_e"]
+       timeframe = 0
+       for v in timestamp.values():
+               timeframe = v.value
+       timestamp = b["timestamp_b"]
+       for v in timestamp.values():
+               timeframe -= v.value
+       #print("%d\n" % stats_t[0].pid)
+       print ("%10s %20s %10s %10s" % ("PID", "NAME", "DBUS", "GLIB"))
+       for v in sorted(stats_t.values(), key=lambda stats_t: stats_t.usage, reverse=True):
+               print("%10d %20s %10.6f %10.6f" % (v.pid, v.buf.encode('string-escape'), float(v.drun) / float(timeframe), float(v.grun) / float(timeframe)))
diff --git a/tools/dbus-latency.c b/tools/dbus-latency.c
new file mode 100644 (file)
index 0000000..eabd22c
--- /dev/null
@@ -0,0 +1,267 @@
+#include <uapi/linux/ptrace.h>
+#include <linux/sched.h>
+
+typedef enum {
+  G_DBUS_MESSAGE_TYPE_INVALID,
+  G_DBUS_MESSAGE_TYPE_METHOD_CALL,
+  G_DBUS_MESSAGE_TYPE_METHOD_RETURN,
+  G_DBUS_MESSAGE_TYPE_ERROR,
+  G_DBUS_MESSAGE_TYPE_SIGNAL
+} GDBusMessageType;
+
+typedef enum {
+  G_DBUS_MESSAGE_FLAGS_NONE = 0,
+  G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED = (1<<0),
+  G_DBUS_MESSAGE_FLAGS_NO_AUTO_START = (1<<1)
+} GDBusMessageFlags;
+
+typedef enum
+{
+  G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN    = 'B',
+  G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN = 'l'
+} GDBusMessageByteOrder;
+
+typedef enum
+{
+       G_DBUS_SEND_MESSAGE_FLAGS_NONE = 0,
+       G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL = (1<<0)
+} GDBusSendMessageFlags;
+
+struct GTypeInstance {
+       void *g_class;
+};
+
+struct GObject {
+       struct GTypeInstance g_type_instance;
+
+       volatile unsigned int ref_count;
+       void *qdata;
+};
+
+struct GDBusMessage {
+       struct GObject parent_instance;
+       GDBusMessageType type;
+       GDBusMessageFlags flags;
+       bool locked;
+       GDBusMessageByteOrder byte_order;
+       unsigned char major_protocol_version;
+       unsigned int serial;
+       void *headers;
+       void *body;
+};
+
+struct DBusString {
+       void *str;
+       int len;
+       unsigned int allocated;
+       unsigned int constant : 1;
+       unsigned int locked : 1;
+       unsigned int invalid : 1;
+       unsigned int align_offset : 3;
+};
+
+struct DBusLink {
+       struct DBusLink *prev;
+       struct DBusLink *next;
+       void *data;
+};
+
+struct DBusHeaderFields {
+       int value_pos;
+};
+
+struct DBusHeader {
+       struct DBusString data;
+
+       struct DBusHeaderFields fields[9];
+
+       u32 padding;
+       u32 byte_order;
+       unsigned char protocol_version;
+};
+
+struct DBusDataSlot {
+       void *data;
+       void *dummy1;
+};
+
+struct DBusDataSlotList {
+       struct DBusDataSlot *slots;
+       int n_slots;
+};
+
+struct DBusList {
+       struct DBusList *prev;
+       struct DbusList *next;
+       void *data;
+};
+
+struct DBusMessage {
+       int refcount;
+       struct DBusHeader header;
+       struct DBusString body;
+
+       unsigned int locked : 1;
+       unsigned int in_cache : 1;
+
+       void *counters;
+       long size_counter_delta;
+       int timeout_ms;
+
+       u32 changed_stamp : 21;
+       struct DBusDataSlotList *slot_list;
+
+       int generation;
+
+       int *unix_fds;
+
+       unsigned n_unix_fds;
+       unsigned n_unix_fds_allocated;
+
+       long unix_fd_counter_delta;
+
+       struct DBusString *signature;
+       struct DBusString *unique_sender;
+       size_t gvariant_body_last_offset;
+       size_t gvariant_body_last_pos;
+};
+
+struct DBusConnection {
+       int refcount;
+
+       void *mutex;
+
+       void *dispatch_mutex;
+       void *dispatch_cond;
+       void *io_path_mutex;
+       void *io_path_cond;
+
+       struct DBusList *outgoing_messages;
+       struct DBusList *incoming_messages;
+       struct DBusList *expired_messages;
+
+       struct DBusMessage *message_borrowed;
+
+       int n_outgoing;
+       int n_incoming;
+};
+
+struct data_t {
+       int pid;
+       char comm[TASK_COMM_LEN];
+       u32 ts;
+};
+
+struct header_data {
+       char flag;
+       char type;
+       char bitewise;
+       char protocol;
+       u32 len;
+       u32 serial;
+};
+
+struct stats_t {
+       int min;
+       u32 avg;
+       int count;
+       int max;
+};
+
+BPF_HASH(msg_sent_addr, u32 , struct data_t)
+BPF_HASH(msg_latency, struct data_t , struct stats_t)
+BPF_HASH(g_serial_addr, struct data_t, struct GDBusMessage *)
+BPF_HISTOGRAM(latency_histo)
+
+static void get_process_data(struct data_t *data) {
+       data->pid = bpf_get_current_pid_tgid();
+       bpf_get_current_comm(&data->comm, sizeof(data->comm));
+       data->ts = bpf_ktime_get_ns() / 1000;
+}
+
+static int get_delay(int serial, struct data_t receiver_data) {
+       int delta;
+       struct stats_t *stat;
+       struct data_t *sender_data = msg_sent_addr.lookup(&serial);
+       if (sender_data != 0 && sender_data->pid != receiver_data.pid) {
+               msg_sent_addr.delete(&serial);
+               delta  = receiver_data.ts - sender_data->ts;
+               if (delta > 5000 || delta <= 0) {
+                       return 0;
+               }
+               latency_histo.increment(bpf_log2l(delta));
+               receiver_data.pid = sender_data->pid;
+               receiver_data.ts  = 0;
+               bpf_probe_read(&receiver_data.comm, sizeof(receiver_data.comm), sender_data->comm);
+               stat = msg_latency.lookup(&receiver_data);
+               if (stat == 0) {
+                       struct stats_t stats = {delta, delta, 1, delta};
+                       msg_latency.insert(&receiver_data, &stats);
+                       return 0;
+               }
+               struct stats_t stats = {stat->min, stat->avg, stat->count, stat->max};
+               if (stats.min > delta) {
+                       stats.min = delta;
+               }
+               else if (stats.max < delta) {
+                       stats.max = delta;
+               }
+               u32 avg = stats.avg;
+               if (stats.count > 1000) {
+                       avg *= 1000;
+               }
+               else {
+                       avg *= stats.count;
+                       stats.count++;
+               }
+               avg += delta;
+               stats.avg  = (avg / stats.count);
+               msg_latency.update(&receiver_data, &stats);
+       }
+       return 0;
+}
+
+int get_msg_addr(struct pt_regs *ctx, struct DBusConnection *conn, struct DBusMessage *msg){
+       struct data_t data = {};
+       get_process_data(&data);
+       struct header_data *header = msg->header.data.str;
+       u32 serial = header->serial;
+       msg_sent_addr.update(&serial,&data);
+       return 0;
+}
+
+int get_msg_latency(struct pt_regs *ctx, struct DBusConnection *conn) {
+       struct data_t receiver_data = {};
+       struct DBusMessage *msg;
+       struct header_data *header;
+       int serial;
+       struct DBusList *link = conn->incoming_messages;
+
+       if (link == 0) {
+               return 0;
+       }
+
+       get_process_data(&receiver_data);
+       msg = conn->incoming_messages->data;
+       header = msg->header.data.str;
+       serial =  header->serial;
+       get_delay(serial, receiver_data);
+       return 0;
+}
+
+int g_get_latency(struct pt_regs *ctx, struct GDBusMessage *msg) {
+       struct data_t *receiver_data;
+       u32 serial = msg->serial;
+       receiver_data = msg_sent_addr.lookup(&serial);
+       struct data_t data = {};
+       get_process_data(&data);
+       data.ts = 0;
+       if ((receiver_data == 0) || (receiver_data->pid == data.pid)){
+               msg_sent_addr.delete(&serial);
+               get_delay(serial, data);
+               return 0;
+       }
+       msg_sent_addr.update(&serial, &data);
+       bpf_trace_printk("sender: %d\n", serial);
+       return 0;
+}
diff --git a/tools/dbus-latency.py b/tools/dbus-latency.py
new file mode 100755 (executable)
index 0000000..ea1aae3
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/python
+
+from bcc import BPF
+from time import sleep
+from ctypes import c_ushort, c_int, c_ulonglong
+from sys import argv
+
+def usage():
+       print("USAGE: %s [--process|histogram]" % argv[0])
+       exit()
+
+print("Hit Ctrl-C to end.")
+count = 100
+interval = 5
+loop = 0
+
+mode = "histogram"
+if len(argv) != 2:
+       usage()
+if argv[1] == "--histogram":
+       mode = "histogram"
+elif argv[1] == "--process":
+       mode = "process"
+else:
+       usage()
+
+b = BPF(src_file="dbus-latency.c")
+
+b.attach_uprobe(name="dbus-1", sym="_dbus_connection_message_sent_unlocked", fn_name="get_msg_addr")
+b.attach_uprobe(name="dbus-1", sym="dbus_connection_dispatch", fn_name="get_msg_latency")
+b.attach_uprobe(name="gio-2.0", sym="g_dbus_message_lock", fn_name="g_get_latency")
+
+
+while (1):
+       sleep(interval)
+       loop = loop + 1
+       print("\n%d:" % loop)
+       if mode =="histogram":
+               b["latency_histo"].print_log2_hist("ms")
+       else:
+               print ("%10s %20s %10s %10s %10s" % ("PID", "COMM", "MIN", "AVG", "MAX"))
+               latency = b["msg_latency"]
+               for v, p in sorted(latency.items(), key=lambda latency: latency[1].avg, reverse=True):
+                       print("%10d %20s %10d %10d %10d" % (v.pid, v.comm.encode('string-escape'), int(p.min), int(p.avg), int(p.max)))
+
diff --git a/tools/dbus-message-size.c b/tools/dbus-message-size.c
new file mode 100644 (file)
index 0000000..80e2adc
--- /dev/null
@@ -0,0 +1,45 @@
+#include <uapi/linux/ptrace.h>
+#include <linux/sched.h>
+
+#define COUNTS COUNTS_T
+
+struct data_t {
+       int pid;
+       char comm[TASK_COMM_LEN];
+};
+
+struct bytes_t {
+       u32 bytes;
+};
+
+BPF_HASH(size_sent, struct data_t, struct bytes_t)
+
+BPF_HISTOGRAM(sizes);
+
+int do_write_exit(struct pt_regs *ctx) {
+       struct data_t data = {};
+       data.pid = bpf_get_current_pid_tgid();
+       bpf_get_current_comm(&data.comm, sizeof(data.comm));
+       struct bytes_t *bytes;
+       bytes = size_sent.lookup(&data);
+       if (bytes != 0 & bytes->bytes > 0) {
+               sizes.increment(bpf_log2l(bytes->bytes));
+       }
+       size_sent.delete(&data);
+       return 0;
+}
+
+int do_return(struct pt_regs *ctx){
+       struct bytes_t size = {};
+       size.bytes = PT_REGS_RC(ctx);
+       struct bytes_t zero = {0}, *val;
+       if (size.bytes > 0) {
+               struct data_t data = {};
+               bpf_get_current_comm(&data.comm, sizeof(data.comm));
+               data.pid = bpf_get_current_pid_tgid();
+               val = size_sent.lookup_or_init(&data, &zero);
+               size.bytes += val->bytes;
+               size_sent.update(&data, &size);
+       }
+       return 0;
+}
diff --git a/tools/dbus-message-size.py b/tools/dbus-message-size.py
new file mode 100755 (executable)
index 0000000..e194ed9
--- /dev/null
@@ -0,0 +1,54 @@
+#works only on sockets
+#!/usr/bin/python
+
+#old version
+
+from bcc import BPF
+from time import sleep
+from ctypes import c_ushort, c_int, c_ulonglong
+from sys import argv
+
+
+def usage():
+       print("USAGE: %s [--histogram]" % argv[0])
+       exit()
+
+mode = 0
+
+if len(argv) > 2:
+       usage()
+       exit(1)
+if len(argv) == 2:
+       if argv[1] == "--histogram":
+               mode = 1
+       else:
+               usage()
+
+print("Hit Ctrl-C to end.")
+count = 100
+interval = 5
+loop = 0
+
+# load BPF program
+
+b = BPF(src_file="dbus-message-size.c")
+if mode == 1:
+       b.attach_uretprobe(name="dbus-1", sym="do_writing", fn_name="do_write_exit")
+       b.attach_uretprobe(name="dbus-1", sym="do_authentication", fn_name="do_write_exit")
+b.attach_uretprobe(name="dbus-1", sym="_dbus_write_socket_with_unix_fds_two", fn_name="do_return")
+b.attach_uretprobe(name="dbus-1", sym="_dbus_write_socket_two", fn_name="do_return")
+b.attach_uretprobe(name="dbus-1", sym="_dbus_write_socket", fn_name="do_return")
+
+while (1):
+       if count > 0:
+               loop += 1
+               if loop > count:
+                       exit()
+       sleep(interval)
+       print ("%d : \n" % loop)
+       stats_t = b["size_sent"]
+       if mode == 0:
+               print ("%10s %20s %20s" % ("PID", "NAME", "BYTES SENT"))
+               for v, p in sorted(stats_t.items(), key=lambda stats_t: stats_t[1].bytes, reverse=True):
+                       print("%10d %20s %20d \n" % (v.pid, v.comm.encode('string-escape'), p.bytes))
+       b["sizes"].print_log2_hist("bytes");
diff --git a/tools/dbus-message-type.c b/tools/dbus-message-type.c
new file mode 100644 (file)
index 0000000..7b1345e
--- /dev/null
@@ -0,0 +1,157 @@
+#include <uapi/linux/ptrace.h>
+#include <linux/sched.h>
+
+#define DBUS_TYPE_OFFSET 1
+
+typedef enum {
+  G_DBUS_MESSAGE_TYPE_INVALID,
+  G_DBUS_MESSAGE_TYPE_METHOD_CALL,
+  G_DBUS_MESSAGE_TYPE_METHOD_RETURN,
+  G_DBUS_MESSAGE_TYPE_ERROR,
+  G_DBUS_MESSAGE_TYPE_SIGNAL
+} GDBusMessageType;
+
+typedef enum {
+  G_DBUS_MESSAGE_FLAGS_NONE = 0,
+  G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED = (1<<0),
+  G_DBUS_MESSAGE_FLAGS_NO_AUTO_START = (1<<1)
+} GDBusMessageFlags;
+
+typedef enum
+{
+  G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN    = 'B',
+  G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN = 'l'
+} GDBusMessageByteOrder;
+
+struct GTypeInstance {
+       void *g_class;
+};
+
+struct GObject {
+       struct GTypeInstance g_type_instance;
+
+       volatile unsigned int ref_count;
+       void *qdata;
+};
+
+struct GHashTable {
+       int size;
+       int mod;
+       unsigned int mask;
+       int nnodes;
+       int noccupied;
+
+       void *keys;
+       void *hashes;
+       void *values;
+};
+
+struct GVariant {
+       void *type_info;
+       unsigned long size;
+
+       union {
+               struct {
+                       void *bytes;
+                       const char *gconstpointer;
+               } serialised;
+
+               struct {
+                       struct GVariant **children;
+                       unsigned long n_children;
+               } tree;
+       } content;
+
+       int state;
+       int ref_count;
+};
+
+struct GDBusMessage {
+       struct GObject parent_instance;
+       GDBusMessageType type;
+       GDBusMessageFlags flags;
+       bool locked;
+       GDBusMessageByteOrder byte_order;
+       unsigned char major_protocol_version;
+       unsigned int serial;
+       struct GHashTable *headers;
+       struct GVariant *body;
+};
+
+struct DBusString {
+       void *str;
+       int len;
+       unsigned int allocated;
+       unsigned int constant : 1;
+       unsigned int locked : 1;
+       unsigned int invalid : 1;
+       unsigned int align_offset : 3;
+};
+
+struct DBusHeaderFields {
+       int value_pos;
+};
+
+struct DBusHeader {
+       struct DBusString data;
+
+       struct DBusHeaderFields fields[9];
+
+       u32 padding;
+       u32 byte_order;
+       unsigned char protocol_version;
+};
+
+struct DBusMessage {
+       int refcount;
+       struct DBusHeader header;
+       struct DBusString body;
+
+       unsigned int locked : 1;
+
+       void * list;
+       long size_counter_delta;
+       int timeout_ms;
+
+       u32 changed_stamp : 21;
+       void *slot_list;
+
+       int generation;
+
+       int *unix_fds;
+
+       unsigned n_unix_fds;
+       unsigned n_unix_fds_allocated;
+
+       long unix_fd_counter_delta;
+
+       struct DBusString *signature;
+       struct DBusString *unique_sender;
+       size_t gvariant_body_last_offset;
+       size_t gvariant_body_last_pos;
+};
+
+struct data_t {
+       u32 pid;
+       char comm[TASK_COMM_LEN];
+};
+
+BPF_HASH(message, struct data_t, int)
+BPF_HISTOGRAM(msg_type, int)
+
+int g_get_message_type(struct pt_regs *ctx, void *conn, struct GDBusMessage *message) {
+       msg_type.increment(message->type);
+       return 0;
+}
+
+int dbus_get_message_type(struct pt_regs *ctx, void *conn, struct DBusMessage *message) {
+       bpf_trace_printk("dbus: %d\n", PT_REGS_RC(ctx));
+       return 0;
+}
+
+int message_type(struct pt_regs *ctx, void *conn, struct DBusMessage *message) {
+       const char *c = message->header.data.str;
+       c++;
+       msg_type.increment(*c);
+       return 0;
+}
diff --git a/tools/dbus-message-type.py b/tools/dbus-message-type.py
new file mode 100755 (executable)
index 0000000..51a1555
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+
+from bcc import BPF
+from time import sleep
+from ctypes import c_ushort, c_int, c_ulonglong
+from sys import argv
+
+b = BPF(src_file="dbus-message-type.c")
+
+b.attach_uprobe(name="gio-2.0", sym="g_dbus_connection_send_message", fn_name="g_get_message_type")
+#b.attach_uretprobe(name="dbus-1", sym="_dbus_header_get_message_type", fn_name="dbus_get_message_type")
+b.attach_uprobe(name="dbus-1", sym="_dbus_connection_message_sent_unlocked", fn_name="message_type")
+
+#b.trace_print()
+count = 0
+while(1):
+       count += 1
+       sleep(5)
+       print("%d:" % count)
+       print("%20s %20s" % ("MESSAGE_TYPE", "NUMBER\n"))
+       print("%20s %20d" % ("INVALID", b["msg_type"][0].value))
+       print("%20s %20d" % ("METHOD_CALL", b["msg_type"][1].value))
+       print("%20s %20d" % ("METHOD_RETURN", b["msg_type"][2].value))
+       print("%20s %20d" % ("ERROR", b["msg_type"][3].value))
+       print("%20s %20d" % ("SIGNAL", b["msg_type"][4].value))
diff --git a/tools/dbus-messages-sent.py b/tools/dbus-messages-sent.py
new file mode 100755 (executable)
index 0000000..2e91593
--- /dev/null
@@ -0,0 +1,55 @@
+#!/usr/bin/python
+
+from bcc import BPF
+from time import sleep
+from ctypes import c_ushort, c_int, c_ulonglong
+from sys import argv
+
+
+print("Hit Ctrl-C to end.")
+count = 100
+interval = 5
+loop = 0
+# load BPF program
+bpf_text="""#include <uapi/linux/ptrace.h>
+#include <linux/sched.h>
+
+struct p_name{
+       char buf[80];
+       u32 pid;
+};
+
+BPF_HASH(counter, struct p_name);
+BPF_HASH(licznik);
+
+int sending_message(struct pt_regs *ctx, void *ptri, void *message){
+       struct p_name process = {' ', 0};
+       u64 zero = 0;
+       u32 ret = PT_REGS_RC(ctx);
+       process.pid = bpf_get_current_pid_tgid();
+       bpf_get_current_comm(&(process.buf), sizeof(process.buf));
+       counter.increment(process);
+       return 0;
+}
+
+"""
+bpf_text = bpf_text.replace('INTERVAL', '%d' % interval)
+b = BPF(text=bpf_text)
+
+b.attach_uprobe(name="dbus-1", sym="dbus_connection_send", fn_name="sending_message")
+b.attach_uprobe(name="dbus-1", sym="dbus_connection_send_preallocated", fn_name="sending_message")
+b.attach_uprobe(name="dbus-1", sym="dbus_connection_send_with_reply", fn_name="sending_message")
+b.attach_uprobe(name="dbus-1", sym="dbus_connection_send_with_reply_and_block", fn_name="sending_message")
+
+
+while (1):
+       if count > 0:
+               loop += 1
+               if loop > count:
+                       exit()
+       sleep(interval)
+       print ("%d:" % loop)
+       stats = b["counter"]
+       print("%10s %20s %20s" % ("PID", "NAME", "MESSAGES SENT"))
+       for k, v in stats.items():
+               print("%10d %20s %20d\n" % (k.pid, k.buf.encode('string-escape'), v.value ))
diff --git a/tools/dbus-tok.c b/tools/dbus-tok.c
new file mode 100644 (file)
index 0000000..76fe5da
--- /dev/null
@@ -0,0 +1,61 @@
+#include <uapi/linux/ptrace.h>
+#include <linux/sched.h>
+
+typedef struct pdata_T {
+       u32 pid;
+       char buf[TASK_COMM_LEN];
+       u64 run;
+       u64 wait;
+       u64 usage;
+}pdata_t;
+
+BPF_HASH(timestamp_b, u64);
+BPF_HASH(timestamp_e, u64);
+BPF_HASH(stats, u32, pdata_t, sizeof(pdata_t));
+BPF_HASH(run_start, u32);
+BPF_HASH(wait_start, u32);
+
+
+#define TAKE_PROCESS_DATA u64 time = 0; pdata_t pdata;\
+       pdata_t new_pdata = {0, ' ', 0, 0, 0};\
+       u64 ts, *tsp, delta;\
+       u32 pid = bpf_get_current_pid_tgid();\
+       ts = bpf_ktime_get_ns() / 1000;\
+       new_pdata.pid = pid;\
+
+int do_entry(struct pt_regs *ctx) {
+       TAKE_PROCESS_DATA
+       timestamp_b.insert(&time, &ts);
+       timestamp_e.update(&time, &ts);
+       tsp = run_start.lookup(&pid);
+       run_start.delete(&pid);
+       wait_start.update(&pid, &ts);
+       if(tsp == 0) {
+               return 0;
+       }
+       delta = ts - *tsp;
+       pdata = *(stats.lookup_or_init(&pid, &new_pdata));
+       pdata.run += delta;
+       bpf_get_current_comm(&(pdata.buf), sizeof(pdata.buf));
+       stats.update(&pid, &pdata);
+       return 0;
+}
+
+int do_return(struct pt_regs *ctx) {
+       TAKE_PROCESS_DATA
+       timestamp_b.insert(&time, &ts);
+       timestamp_e.update(&time, &ts);
+       tsp = wait_start.lookup(&pid);
+       wait_start.delete(&pid);
+       run_start.update(&pid, &ts);
+       if(tsp == 0) {
+               return 0;
+       }
+       delta = ts - *tsp;
+       pdata = *(stats.lookup_or_init(&pid, &new_pdata));
+       pdata.wait += delta;
+       bpf_get_current_comm(&(pdata.buf), sizeof(pdata.buf));
+       stats.update(&pid, &pdata);
+       return 0;
+}
+
diff --git a/tools/dbus-tok.py b/tools/dbus-tok.py
new file mode 100755 (executable)
index 0000000..28384ab
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/python
+
+from bcc import BPF
+from time import sleep
+from ctypes import c_ushort, c_int, c_ulonglong
+from sys import argv
+
+def usage():
+       print("[interval] [count]")
+       exit(0)
+
+print("Hit Ctrl-C to end.")
+count = 100
+interval = 5
+loop = 0
+# load BPF program
+b = BPF(src_file="dbus-tok.c")
+
+b.attach_uprobe(name="dbus-1", sym="_dbus_poll", fn_name="do_entry")
+
+b.attach_uretprobe(name="dbus-1", sym="_dbus_poll", fn_name="do_return")
+
+while (1):
+       if count > 0:
+
+               loop += 1
+               if loop > count:
+                       exit()
+       sleep(interval)
+       print ("%d : \n" % loop)
+       stats_t = b["stats"]
+       timestamp = b["timestamp_e"]
+       timeframe = 0
+       for v in timestamp.values():
+               timeframe = v.value
+       timestamp = b["timestamp_b"]
+       for v in timestamp.values():
+               timeframe -= v.value
+       for v in stats_t.values():
+               v.usage = (v.run * 100 / timeframe)
+       for v in sorted(stats_t.values(), key=lambda stats_t: stats_t.run, reverse=True):
+               print("%10d %20s %10.6f" % (v.pid, v.buf.encode('string-escape'), float(v.run) / float(timeframe)))