temporary workaround for derefs on arm32
[platform/upstream/bcc.git] / tools / dbus-latency.c
1 #include <uapi/linux/ptrace.h>
2 #include <linux/sched.h>
3
4 typedef enum {
5   G_DBUS_MESSAGE_TYPE_INVALID,
6   G_DBUS_MESSAGE_TYPE_METHOD_CALL,
7   G_DBUS_MESSAGE_TYPE_METHOD_RETURN,
8   G_DBUS_MESSAGE_TYPE_ERROR,
9   G_DBUS_MESSAGE_TYPE_SIGNAL
10 } GDBusMessageType;
11
12 typedef enum {
13   G_DBUS_MESSAGE_FLAGS_NONE = 0,
14   G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED = (1<<0),
15   G_DBUS_MESSAGE_FLAGS_NO_AUTO_START = (1<<1)
16 } GDBusMessageFlags;
17
18 typedef enum
19 {
20   G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN    = 'B',
21   G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN = 'l'
22 } GDBusMessageByteOrder;
23
24 typedef enum
25 {
26         G_DBUS_SEND_MESSAGE_FLAGS_NONE = 0,
27         G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL = (1<<0)
28 } GDBusSendMessageFlags;
29
30 struct GTypeInstance {
31         void *g_class;
32 };
33
34 struct GObject {
35         struct GTypeInstance g_type_instance;
36
37         volatile unsigned int ref_count;
38         void *qdata;
39 };
40
41 struct GDBusMessage {
42         struct GObject parent_instance;
43         GDBusMessageType type;
44         GDBusMessageFlags flags;
45         bool locked;
46         GDBusMessageByteOrder byte_order;
47         unsigned char major_protocol_version;
48         unsigned int serial;
49         void *headers;
50         void *body;
51 };
52
53 struct DBusString {
54         void *str;
55         int len;
56         unsigned int allocated;
57         unsigned int constant : 1;
58         unsigned int locked : 1;
59         unsigned int invalid : 1;
60         unsigned int align_offset : 3;
61 };
62
63 struct DBusLink {
64         struct DBusLink *prev;
65         struct DBusLink *next;
66         void *data;
67 };
68
69 struct DBusHeaderFields {
70         int value_pos;
71 };
72
73 struct DBusHeader {
74         struct DBusString data;
75
76         struct DBusHeaderFields fields[9];
77
78         u32 padding;
79         u32 byte_order;
80         unsigned char protocol_version;
81 };
82
83 struct DBusDataSlot {
84         void *data;
85         void *dummy1;
86 };
87
88 struct DBusDataSlotList {
89         struct DBusDataSlot *slots;
90         int n_slots;
91 };
92
93 struct DBusList {
94         struct DBusList *prev;
95         struct DbusList *next;
96         void *data;
97 };
98
99 struct DBusMessage {
100         int refcount;
101         struct DBusHeader header;
102         struct DBusString body;
103
104         unsigned int locked : 1;
105         unsigned int in_cache : 1;
106
107         void *counters;
108         long size_counter_delta;
109         int timeout_ms;
110
111         u32 changed_stamp : 21;
112         struct DBusDataSlotList *slot_list;
113
114         int generation;
115
116         int *unix_fds;
117
118         unsigned n_unix_fds;
119         unsigned n_unix_fds_allocated;
120
121         long unix_fd_counter_delta;
122
123         struct DBusString *signature;
124         struct DBusString *unique_sender;
125         size_t gvariant_body_last_offset;
126         size_t gvariant_body_last_pos;
127 };
128
129 struct DBusConnection {
130         int refcount;
131
132         void *mutex;
133
134         void *dispatch_mutex;
135         void *dispatch_cond;
136         void *io_path_mutex;
137         void *io_path_cond;
138
139         struct DBusList *outgoing_messages;
140         struct DBusList *incoming_messages;
141         struct DBusList *expired_messages;
142
143         struct DBusMessage *message_borrowed;
144
145         int n_outgoing;
146         int n_incoming;
147 };
148
149 struct data_t {
150         int pid;
151         char comm[TASK_COMM_LEN];
152         u64 ts;
153 };
154
155 struct header_data {
156         char flag;
157         char type;
158         char bitewise;
159         char protocol;
160         u32 len;
161         u32 serial;
162 };
163
164 struct stats_t {
165         int min;
166         u32 avg;
167         int count;
168         int max;
169 };
170
171 BPF_HASH(msg_sent_addr, u32 , struct data_t);
172 BPF_HASH(msg_latency, struct data_t , struct stats_t);
173 BPF_HASH(g_serial_addr, struct data_t, struct GDBusMessage *);
174 BPF_HISTOGRAM(latency_histo);
175
176 static void get_process_data(struct data_t *data) {
177         data->pid = bpf_get_current_pid_tgid();
178         bpf_get_current_comm(&data->comm, sizeof(data->comm));
179         data->ts = bpf_ktime_get_ns() / 1000;
180 }
181
182 static int get_delay(int serial, struct data_t receiver_data) {
183         int delta;
184         struct stats_t *stat;
185         struct data_t *sender_data = msg_sent_addr.lookup(&serial);
186         if (sender_data != 0 && sender_data->pid != receiver_data.pid) {
187                 msg_sent_addr.delete(&serial);
188                 delta  = receiver_data.ts - sender_data->ts;
189                 if (delta > 5000 || delta <= 0) {
190                         return 0;
191                 }
192                 latency_histo.increment(bpf_log2l(delta));
193                 receiver_data.pid = sender_data->pid;
194                 receiver_data.ts  = 0;
195                 bpf_probe_read(&receiver_data.comm, sizeof(receiver_data.comm), sender_data->comm);
196                 stat = msg_latency.lookup(&receiver_data);
197                 if (stat == 0) {
198                         struct stats_t stats = {delta, delta, 1, delta};
199                         msg_latency.insert(&receiver_data, &stats);
200                         return 0;
201                 }
202                 struct stats_t stats = {stat->min, stat->avg, stat->count, stat->max};
203                 if (stats.min > delta) {
204                         stats.min = delta;
205                 }
206                 else if (stats.max < delta) {
207                         stats.max = delta;
208                 }
209                 u32 avg = stats.avg;
210                 if (stats.count > 1000) {
211                         avg *= 1000;
212                 }
213                 else {
214                         avg *= stats.count;
215                         stats.count++;
216                 }
217                 avg += delta;
218                 stats.avg  = (avg / stats.count);
219                 msg_latency.update(&receiver_data, &stats);
220         }
221         return 0;
222 }
223
224 int get_msg_addr(struct pt_regs *ctx, struct DBusConnection *conn, struct DBusMessage *msg){
225         struct data_t data = {};
226         get_process_data(&data);
227         struct header_data *header = 0;
228         bpf_probe_read(&header, sizeof(header), (char*)msg + offsetof(struct DBusMessage, header.data.str));
229         u32 serial = 0;
230         bpf_probe_read(&serial, sizeof(serial), (char*)header + offsetof(struct header_data, serial));
231         msg_sent_addr.update(&serial,&data);
232         return 0;
233 }
234
235 int get_msg_latency(struct pt_regs *ctx, struct DBusConnection *conn) {
236         struct data_t receiver_data = {};
237         struct DBusMessage *msg = 0;
238         struct header_data *header = 0;
239         int serial = 0;
240         struct DBusList *link = 0;
241
242         bpf_probe_read(&link, sizeof(link), (char *)conn + offsetof(struct DBusConnection, incoming_messages));
243
244         if (link == 0) {
245                 return 0;
246         }
247
248         get_process_data(&receiver_data);
249         bpf_probe_read(&msg, sizeof(msg), (char *)link + offsetof(struct DBusList, data));
250         bpf_probe_read(&header, sizeof(header), (char*)msg + offsetof(struct DBusMessage, header.data.str));
251         bpf_probe_read(&serial, sizeof(serial), (char*)header + offsetof(struct header_data, serial));
252         get_delay(serial, receiver_data);
253         return 0;
254 }
255
256 int g_get_latency(struct pt_regs *ctx, struct GDBusMessage *msg) {
257         struct data_t *receiver_data;
258         u32 serial = msg->serial;
259         receiver_data = msg_sent_addr.lookup(&serial);
260         struct data_t data = {};
261         get_process_data(&data);
262         data.ts = 0;
263         if ((receiver_data == 0) || (receiver_data->pid == data.pid)){
264                 msg_sent_addr.delete(&serial);
265                 get_delay(serial, data);
266                 return 0;
267         }
268         msg_sent_addr.update(&serial, &data);
269         bpf_trace_printk("sender: %d\n", serial);
270         return 0;
271 }