From 590ce7311c1b03636a26c6d59f0b006451cf39a1 Mon Sep 17 00:00:00 2001 From: Dawid Kuczma Date: Fri, 15 Sep 2017 12:39:40 +0200 Subject: [PATCH] Add 6 tools tracking dbus. - 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 --- packaging/bcc-tools.spec | 12 ++ tools/dbus-connection-message-size.c | 130 +++++++++++++++++ tools/dbus-connection-message-size.py | 41 ++++++ tools/dbus-glib-tok.py | 191 ++++++++++++++++++++++++ tools/dbus-latency.c | 267 ++++++++++++++++++++++++++++++++++ tools/dbus-latency.py | 45 ++++++ tools/dbus-message-size.c | 45 ++++++ tools/dbus-message-size.py | 54 +++++++ tools/dbus-message-type.c | 157 ++++++++++++++++++++ tools/dbus-message-type.py | 25 ++++ tools/dbus-messages-sent.py | 55 +++++++ tools/dbus-tok.c | 61 ++++++++ tools/dbus-tok.py | 42 ++++++ 13 files changed, 1125 insertions(+) create mode 100644 tools/dbus-connection-message-size.c create mode 100755 tools/dbus-connection-message-size.py create mode 100755 tools/dbus-glib-tok.py create mode 100644 tools/dbus-latency.c create mode 100755 tools/dbus-latency.py create mode 100644 tools/dbus-message-size.c create mode 100755 tools/dbus-message-size.py create mode 100644 tools/dbus-message-type.c create mode 100755 tools/dbus-message-type.py create mode 100755 tools/dbus-messages-sent.py create mode 100644 tools/dbus-tok.c create mode 100755 tools/dbus-tok.py diff --git a/packaging/bcc-tools.spec b/packaging/bcc-tools.spec index dbb2691..134af99 100644 --- a/packaging/bcc-tools.spec +++ b/packaging/bcc-tools.spec @@ -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 index 0000000..8d1a7f2 --- /dev/null +++ b/tools/dbus-connection-message-size.c @@ -0,0 +1,130 @@ +#include +#include + +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 index 0000000..64451cf --- /dev/null +++ b/tools/dbus-connection-message-size.py @@ -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 index 0000000..3be925b --- /dev/null +++ b/tools/dbus-glib-tok.py @@ -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 +#include + +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 index 0000000..eabd22c --- /dev/null +++ b/tools/dbus-latency.c @@ -0,0 +1,267 @@ +#include +#include + +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 index 0000000..ea1aae3 --- /dev/null +++ b/tools/dbus-latency.py @@ -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 index 0000000..80e2adc --- /dev/null +++ b/tools/dbus-message-size.c @@ -0,0 +1,45 @@ +#include +#include + +#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 index 0000000..e194ed9 --- /dev/null +++ b/tools/dbus-message-size.py @@ -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 index 0000000..7b1345e --- /dev/null +++ b/tools/dbus-message-type.c @@ -0,0 +1,157 @@ +#include +#include + +#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 index 0000000..51a1555 --- /dev/null +++ b/tools/dbus-message-type.py @@ -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 index 0000000..2e91593 --- /dev/null +++ b/tools/dbus-messages-sent.py @@ -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 +#include + +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 index 0000000..76fe5da --- /dev/null +++ b/tools/dbus-tok.c @@ -0,0 +1,61 @@ +#include +#include + +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 index 0000000..28384ab --- /dev/null +++ b/tools/dbus-tok.py @@ -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))) -- 2.7.4