Commit | Line | Data |
---|---|---|
1fc22eb4 | 1 | /* |
aa15ac1c | 2 | * Copyright (C) 2011-2012 Julien Desfossez |
1fc22eb4 JD |
3 | * |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License Version 2 as | |
6 | * published by the Free Software Foundation; | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | * | |
71bd7ce1 AM |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., | |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
1fc22eb4 JD |
16 | */ |
17 | ||
1dec520a | 18 | #include <babeltrace/ctf/events.h> |
1fc22eb4 | 19 | #include <stdlib.h> |
ceb3a221 | 20 | #include <linux/unistd.h> |
1fc22eb4 JD |
21 | #include <string.h> |
22 | #include "common.h" | |
23 | ||
4adc8274 | 24 | uint64_t get_cpu_id(const struct bt_ctf_event *event) |
d67167cd | 25 | { |
2e0a1190 | 26 | const struct bt_definition *scope; |
d67167cd JD |
27 | uint64_t cpu_id; |
28 | ||
29 | scope = bt_ctf_get_top_level_scope(event, BT_STREAM_PACKET_CONTEXT); | |
30 | cpu_id = bt_ctf_get_uint64(bt_ctf_get_field(event, scope, "cpu_id")); | |
31 | if (bt_ctf_field_get_error()) { | |
32 | fprintf(stderr, "[error] get cpu_id\n"); | |
33 | return -1ULL; | |
34 | } | |
35 | ||
36 | return cpu_id; | |
37 | } | |
38 | ||
4adc8274 | 39 | uint64_t get_context_tid(const struct bt_ctf_event *event) |
1dec520a | 40 | { |
2e0a1190 | 41 | const struct bt_definition *scope; |
1dec520a JD |
42 | uint64_t tid; |
43 | ||
44 | scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT); | |
45 | tid = bt_ctf_get_int64(bt_ctf_get_field(event, | |
46 | scope, "_tid")); | |
47 | if (bt_ctf_field_get_error()) { | |
8fe4d0cf JD |
48 | tid = bt_ctf_get_int64(bt_ctf_get_field(event, |
49 | scope, "_vtid")); | |
50 | if (bt_ctf_field_get_error()) { | |
51 | fprintf(stderr, "Missing tid context info\n"); | |
52 | return -1ULL; | |
53 | } | |
1dec520a JD |
54 | } |
55 | ||
56 | return tid; | |
57 | } | |
58 | ||
4adc8274 | 59 | uint64_t get_context_pid(const struct bt_ctf_event *event) |
1dec520a | 60 | { |
2e0a1190 | 61 | const struct bt_definition *scope; |
1dec520a JD |
62 | uint64_t pid; |
63 | ||
64 | scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT); | |
65 | pid = bt_ctf_get_int64(bt_ctf_get_field(event, | |
66 | scope, "_pid")); | |
67 | if (bt_ctf_field_get_error()) { | |
8fe4d0cf JD |
68 | /* Try UST pid */ |
69 | pid = bt_ctf_get_int64(bt_ctf_get_field(event, | |
70 | scope, "_vpid")); | |
71 | if (bt_ctf_field_get_error()) { | |
72 | fprintf(stderr, "Missing pid context info\n"); | |
73 | return -1ULL; | |
74 | } | |
1dec520a JD |
75 | } |
76 | ||
77 | return pid; | |
78 | } | |
79 | ||
4adc8274 | 80 | uint64_t get_context_ppid(const struct bt_ctf_event *event) |
1dec520a | 81 | { |
2e0a1190 | 82 | const struct bt_definition *scope; |
1dec520a JD |
83 | uint64_t ppid; |
84 | ||
85 | scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT); | |
86 | ppid = bt_ctf_get_int64(bt_ctf_get_field(event, | |
87 | scope, "_ppid")); | |
88 | if (bt_ctf_field_get_error()) { | |
1dec520a JD |
89 | return -1ULL; |
90 | } | |
91 | ||
92 | return ppid; | |
93 | } | |
94 | ||
1402044a JD |
95 | uint64_t get_context_vtid(const struct bt_ctf_event *event) |
96 | { | |
3160c7a9 | 97 | const struct bt_definition *scope; |
1402044a JD |
98 | uint64_t vtid; |
99 | ||
100 | scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT); | |
101 | vtid = bt_ctf_get_int64(bt_ctf_get_field(event, | |
102 | scope, "_vtid")); | |
103 | if (bt_ctf_field_get_error()) { | |
104 | return -1ULL; | |
105 | } | |
106 | ||
107 | return vtid; | |
108 | } | |
109 | ||
110 | uint64_t get_context_vpid(const struct bt_ctf_event *event) | |
111 | { | |
3160c7a9 | 112 | const struct bt_definition *scope; |
1402044a JD |
113 | uint64_t vpid; |
114 | ||
115 | scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT); | |
116 | vpid = bt_ctf_get_int64(bt_ctf_get_field(event, | |
117 | scope, "_vpid")); | |
118 | if (bt_ctf_field_get_error()) { | |
119 | return -1ULL; | |
120 | } | |
121 | ||
122 | return vpid; | |
123 | } | |
124 | ||
125 | uint64_t get_context_vppid(const struct bt_ctf_event *event) | |
126 | { | |
3160c7a9 | 127 | const struct bt_definition *scope; |
1402044a JD |
128 | uint64_t vppid; |
129 | ||
130 | scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT); | |
131 | vppid = bt_ctf_get_int64(bt_ctf_get_field(event, | |
132 | scope, "_vppid")); | |
133 | if (bt_ctf_field_get_error()) { | |
134 | return -1ULL; | |
135 | } | |
136 | ||
137 | return vppid; | |
138 | } | |
139 | ||
4adc8274 | 140 | char *get_context_comm(const struct bt_ctf_event *event) |
1dec520a | 141 | { |
2e0a1190 | 142 | const struct bt_definition *scope; |
1dec520a JD |
143 | char *comm; |
144 | ||
145 | scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT); | |
146 | comm = bt_ctf_get_char_array(bt_ctf_get_field(event, | |
147 | scope, "_procname")); | |
148 | if (bt_ctf_field_get_error()) { | |
149 | fprintf(stderr, "Missing comm context info\n"); | |
150 | return NULL; | |
151 | } | |
152 | ||
153 | return comm; | |
154 | } | |
155 | ||
c8d75a13 JD |
156 | char *get_context_hostname(const struct bt_ctf_event *event) |
157 | { | |
3160c7a9 | 158 | const struct bt_definition *scope; |
c8d75a13 JD |
159 | char *hostname; |
160 | ||
161 | scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT); | |
162 | hostname = bt_ctf_get_char_array(bt_ctf_get_field(event, | |
163 | scope, "_hostname")); | |
164 | if (bt_ctf_field_get_error()) { | |
165 | return NULL; | |
166 | } | |
167 | ||
168 | return hostname; | |
169 | } | |
170 | ||
59288610 MB |
171 | /* |
172 | * To get the parent process, put the pid in the tid field | |
173 | * because the parent process gets pid = tid | |
59288610 | 174 | */ |
08d1cfbe | 175 | struct processtop *find_process_tid(struct lttngtop *ctx, int tid, const char *comm) |
1fc22eb4 | 176 | { |
1fc22eb4 JD |
177 | struct processtop *tmp; |
178 | ||
30b646c4 JD |
179 | tmp = g_hash_table_lookup(ctx->process_hash_table, |
180 | (gconstpointer) (unsigned long) tid); | |
181 | ||
182 | return tmp; | |
1fc22eb4 JD |
183 | } |
184 | ||
185 | struct processtop* add_proc(struct lttngtop *ctx, int tid, char *comm, | |
906c08f6 | 186 | unsigned long timestamp, char *hostname) |
1fc22eb4 JD |
187 | { |
188 | struct processtop *newproc; | |
b99227ca | 189 | struct host *host; |
1fc22eb4 JD |
190 | |
191 | /* if the PID already exists, we just rename the process */ | |
192 | /* FIXME : need to integrate with clone/fork/exit to be accurate */ | |
193 | newproc = find_process_tid(ctx, tid, comm); | |
96aa77de | 194 | |
1fc22eb4 | 195 | if (!newproc) { |
559c9f86 | 196 | newproc = g_new0(struct processtop, 1); |
1fc22eb4 JD |
197 | newproc->tid = tid; |
198 | newproc->birth = timestamp; | |
199 | newproc->process_files_table = g_ptr_array_new(); | |
ceb3a221 | 200 | newproc->files_history = NULL; |
b093de8a MB |
201 | newproc->totalfileread = 0; |
202 | newproc->totalfilewrite = 0; | |
203 | newproc->fileread = 0; | |
204 | newproc->filewrite = 0; | |
205 | newproc->syscall_info = NULL; | |
59288610 | 206 | newproc->threadparent = NULL; |
1fc22eb4 | 207 | newproc->threads = g_ptr_array_new(); |
85db4618 | 208 | newproc->perf = g_hash_table_new(g_str_hash, g_str_equal); |
1fc22eb4 | 209 | g_ptr_array_add(ctx->process_table, newproc); |
30b646c4 JD |
210 | g_hash_table_insert(ctx->process_hash_table, |
211 | (gpointer) (unsigned long) tid, newproc); | |
da4353bb | 212 | if (lookup_tid_list(tid)) { |
b99227ca | 213 | add_filter_tid_list(newproc); |
da4353bb | 214 | } |
e05a35a6 JD |
215 | ctx->nbnewthreads++; |
216 | ctx->nbthreads++; | |
1fc22eb4 JD |
217 | } |
218 | newproc->comm = strdup(comm); | |
906c08f6 | 219 | if (hostname) { |
b99227ca JD |
220 | host = lookup_hostname_list(hostname); |
221 | if (!host) | |
222 | host = add_hostname_list(hostname, 0); | |
223 | if (!newproc->host || (newproc->host != host)) | |
224 | newproc->host = host; | |
114cae59 | 225 | if (is_hostname_filtered(hostname)) { |
b99227ca | 226 | add_filter_tid_list(newproc); |
906c08f6 JD |
227 | } |
228 | } | |
1fc22eb4 JD |
229 | |
230 | return newproc; | |
231 | } | |
232 | ||
233 | struct processtop* update_proc(struct processtop* proc, int pid, int tid, | |
c8d75a13 | 234 | int ppid, int vpid, int vtid, int vppid, char *comm, char *hostname) |
1fc22eb4 | 235 | { |
b99227ca JD |
236 | struct host *host; |
237 | ||
1fc22eb4 JD |
238 | if (proc) { |
239 | proc->pid = pid; | |
240 | proc->tid = tid; | |
241 | proc->ppid = ppid; | |
1402044a JD |
242 | proc->vpid = vpid; |
243 | proc->vtid = vtid; | |
244 | proc->vppid = vppid; | |
1fc22eb4 JD |
245 | if (strcmp(proc->comm, comm) != 0) { |
246 | free(proc->comm); | |
247 | proc->comm = strdup(comm); | |
248 | } | |
b99227ca JD |
249 | if (hostname && !proc->host) { |
250 | host = lookup_hostname_list(hostname); | |
251 | if (!host) | |
252 | host = add_hostname_list(hostname, 0); | |
253 | if (!proc->host || (proc->host != host)) | |
254 | proc->host = host; | |
114cae59 | 255 | if (is_hostname_filtered(hostname)) { |
b99227ca | 256 | add_filter_tid_list(proc); |
1d2391b4 JD |
257 | } |
258 | } | |
1fc22eb4 JD |
259 | } |
260 | return proc; | |
261 | } | |
262 | ||
263 | /* | |
264 | * This function just sets the time of death of a process. | |
265 | * When we rotate the cputime we remove it from the process list. | |
266 | */ | |
267 | void death_proc(struct lttngtop *ctx, int tid, char *comm, | |
268 | unsigned long timestamp) | |
269 | { | |
270 | struct processtop *tmp; | |
271 | tmp = find_process_tid(ctx, tid, comm); | |
30b646c4 JD |
272 | |
273 | g_hash_table_remove(ctx->process_hash_table, | |
274 | (gpointer) (unsigned long) tid); | |
e05a35a6 | 275 | if (tmp && strcmp(tmp->comm, comm) == 0) { |
1fc22eb4 | 276 | tmp->death = timestamp; |
e05a35a6 JD |
277 | ctx->nbdeadthreads++; |
278 | ctx->nbthreads--; | |
279 | } | |
1fc22eb4 JD |
280 | } |
281 | ||
282 | struct processtop* get_proc(struct lttngtop *ctx, int tid, char *comm, | |
906c08f6 | 283 | unsigned long timestamp, char *hostname) |
1fc22eb4 JD |
284 | { |
285 | struct processtop *tmp; | |
1d2391b4 | 286 | |
1fc22eb4 | 287 | tmp = find_process_tid(ctx, tid, comm); |
1d2391b4 | 288 | if (tmp && strcmp(tmp->comm, comm) == 0) { |
1fc22eb4 | 289 | return tmp; |
1d2391b4 | 290 | } |
906c08f6 | 291 | return add_proc(ctx, tid, comm, timestamp, hostname); |
1fc22eb4 JD |
292 | } |
293 | ||
59288610 | 294 | struct processtop *get_proc_pid(struct lttngtop *ctx, int tid, int pid, |
906c08f6 | 295 | unsigned long timestamp, char *hostname) |
59288610 MB |
296 | { |
297 | struct processtop *tmp; | |
298 | tmp = find_process_tid(ctx, tid, NULL); | |
299 | if (tmp && tmp->pid == pid) | |
300 | return tmp; | |
906c08f6 | 301 | return add_proc(ctx, tid, "Unknown", timestamp, hostname); |
59288610 MB |
302 | } |
303 | ||
1fc22eb4 JD |
304 | void add_thread(struct processtop *parent, struct processtop *thread) |
305 | { | |
306 | gint i; | |
307 | struct processtop *tmp; | |
308 | ||
96aa77de JD |
309 | if (!parent) |
310 | return; | |
311 | ||
1fc22eb4 JD |
312 | for (i = 0; i < parent->threads->len; i++) { |
313 | tmp = g_ptr_array_index(parent->threads, i); | |
314 | if (tmp == thread) | |
315 | return; | |
316 | } | |
317 | g_ptr_array_add(parent->threads, thread); | |
318 | } | |
319 | ||
320 | struct cputime* add_cpu(int cpu) | |
321 | { | |
322 | struct cputime *newcpu; | |
323 | ||
559c9f86 | 324 | newcpu = g_new0(struct cputime, 1); |
1fc22eb4 JD |
325 | newcpu->id = cpu; |
326 | newcpu->current_task = NULL; | |
85db4618 | 327 | newcpu->perf = g_hash_table_new(g_str_hash, g_str_equal); |
1fc22eb4 JD |
328 | |
329 | g_ptr_array_add(lttngtop.cpu_table, newcpu); | |
330 | ||
331 | return newcpu; | |
332 | } | |
333 | struct cputime* get_cpu(int cpu) | |
334 | { | |
335 | gint i; | |
336 | struct cputime *tmp; | |
337 | ||
338 | for (i = 0; i < lttngtop.cpu_table->len; i++) { | |
339 | tmp = g_ptr_array_index(lttngtop.cpu_table, i); | |
340 | if (tmp->id == cpu) | |
341 | return tmp; | |
342 | } | |
343 | ||
344 | return add_cpu(cpu); | |
345 | } | |
346 | ||
347 | /* | |
348 | * At the end of a sampling period, we need to display the cpu time for each | |
349 | * process and to reset it to zero for the next period | |
350 | */ | |
351 | void rotate_cputime(unsigned long end) | |
352 | { | |
353 | gint i; | |
354 | struct cputime *tmp; | |
355 | unsigned long elapsed; | |
356 | ||
357 | for (i = 0; i < lttngtop.cpu_table->len; i++) { | |
358 | tmp = g_ptr_array_index(lttngtop.cpu_table, i); | |
359 | elapsed = end - tmp->task_start; | |
360 | if (tmp->current_task) { | |
361 | tmp->current_task->totalcpunsec += elapsed; | |
362 | tmp->current_task->threadstotalcpunsec += elapsed; | |
363 | if (tmp->current_task->pid != tmp->current_task->tid && | |
364 | tmp->current_task->threadparent) { | |
365 | tmp->current_task->threadparent->threadstotalcpunsec += elapsed; | |
366 | } | |
367 | } | |
368 | tmp->task_start = end; | |
369 | } | |
370 | } | |
371 | ||
372 | void reset_perf_counter(gpointer key, gpointer value, gpointer user_data) | |
373 | { | |
374 | ((struct perfcounter*) value)->count = 0; | |
375 | } | |
376 | ||
377 | void copy_perf_counter(gpointer key, gpointer value, gpointer new_table) | |
378 | { | |
379 | struct perfcounter *newperf; | |
59288610 | 380 | |
559c9f86 | 381 | newperf = g_new0(struct perfcounter, 1); |
1fc22eb4 JD |
382 | newperf->count = ((struct perfcounter *) value)->count; |
383 | newperf->visible = ((struct perfcounter *) value)->visible; | |
384 | newperf->sort = ((struct perfcounter *) value)->sort; | |
85db4618 | 385 | g_hash_table_insert((GHashTable *) new_table, strdup(key), newperf); |
1fc22eb4 JD |
386 | } |
387 | ||
30b646c4 JD |
388 | void copy_process_table(gpointer key, gpointer value, gpointer new_table) |
389 | { | |
390 | g_hash_table_insert((GHashTable *) new_table, key, value); | |
391 | } | |
392 | ||
1fc22eb4 JD |
393 | void rotate_perfcounter() { |
394 | int i; | |
395 | struct processtop *tmp; | |
b99227ca | 396 | |
1fc22eb4 JD |
397 | for (i = 0; i < lttngtop.process_table->len; i++) { |
398 | tmp = g_ptr_array_index(lttngtop.process_table, i); | |
399 | g_hash_table_foreach(tmp->perf, reset_perf_counter, NULL); | |
400 | } | |
401 | } | |
402 | ||
403 | void cleanup_processtop() | |
404 | { | |
b093de8a | 405 | gint i, j; |
1fc22eb4 | 406 | struct processtop *tmp; |
b093de8a | 407 | struct files *tmpf; /* a temporary file */ |
1fc22eb4 JD |
408 | |
409 | for (i = 0; i < lttngtop.process_table->len; i++) { | |
410 | tmp = g_ptr_array_index(lttngtop.process_table, i); | |
411 | tmp->totalcpunsec = 0; | |
412 | tmp->threadstotalcpunsec = 0; | |
b093de8a MB |
413 | tmp->fileread = 0; |
414 | tmp->filewrite = 0; | |
415 | ||
416 | for (j = 0; j < tmp->process_files_table->len; j++) { | |
417 | tmpf = g_ptr_array_index(tmp->process_files_table, j); | |
418 | if (tmpf != NULL) { | |
419 | tmpf->read = 0; | |
420 | tmpf->write = 0; | |
ceb3a221 MB |
421 | |
422 | if (tmpf->flag == __NR_close) | |
423 | g_ptr_array_index( | |
424 | tmp->process_files_table, j | |
425 | ) = NULL; | |
b093de8a MB |
426 | } |
427 | } | |
1fc22eb4 JD |
428 | } |
429 | } | |
430 | ||
e05a35a6 JD |
431 | void reset_global_counters() |
432 | { | |
433 | lttngtop.nbnewproc = 0; | |
434 | lttngtop.nbdeadproc = 0; | |
435 | lttngtop.nbnewthreads = 0; | |
436 | lttngtop.nbdeadthreads = 0; | |
437 | lttngtop.nbnewfiles = 0; | |
438 | lttngtop.nbclosedfiles = 0; | |
439 | } | |
440 | ||
441 | void copy_global_counters(struct lttngtop *dst) | |
442 | { | |
443 | dst->nbproc = lttngtop.nbproc; | |
444 | dst->nbnewproc = lttngtop.nbnewproc; | |
445 | dst->nbdeadproc = lttngtop.nbdeadproc; | |
446 | dst->nbthreads = lttngtop.nbthreads; | |
447 | dst->nbnewthreads = lttngtop.nbnewthreads; | |
448 | dst->nbdeadthreads = lttngtop.nbdeadthreads; | |
449 | dst->nbfiles = lttngtop.nbfiles; | |
450 | dst->nbnewfiles = lttngtop.nbnewfiles; | |
451 | dst->nbclosedfiles = lttngtop.nbclosedfiles; | |
452 | reset_global_counters(); | |
453 | } | |
454 | ||
1fc22eb4 JD |
455 | struct lttngtop* get_copy_lttngtop(unsigned long start, unsigned long end) |
456 | { | |
457 | gint i, j; | |
458 | unsigned long time; | |
459 | struct lttngtop *dst; | |
460 | struct processtop *tmp, *tmp2, *new; | |
461 | struct cputime *tmpcpu, *newcpu; | |
462 | struct files *tmpfile, *newfile; | |
246d5992 | 463 | struct kprobes *tmpprobe, *newprobe; |
1fc22eb4 | 464 | |
559c9f86 | 465 | dst = g_new0(struct lttngtop, 1); |
1fc22eb4 JD |
466 | dst->start = start; |
467 | dst->end = end; | |
e05a35a6 | 468 | copy_global_counters(dst); |
1fc22eb4 JD |
469 | dst->process_table = g_ptr_array_new(); |
470 | dst->files_table = g_ptr_array_new(); | |
471 | dst->cpu_table = g_ptr_array_new(); | |
246d5992 | 472 | dst->kprobes_table = g_ptr_array_new(); |
30b646c4 JD |
473 | dst->process_hash_table = g_hash_table_new(g_direct_hash, g_direct_equal); |
474 | g_hash_table_foreach(lttngtop.process_hash_table, copy_process_table, | |
475 | dst->process_hash_table); | |
1fc22eb4 JD |
476 | |
477 | rotate_cputime(end); | |
478 | ||
1fc22eb4 JD |
479 | for (i = 0; i < lttngtop.process_table->len; i++) { |
480 | tmp = g_ptr_array_index(lttngtop.process_table, i); | |
559c9f86 | 481 | new = g_new0(struct processtop, 1); |
1fc22eb4 JD |
482 | |
483 | memcpy(new, tmp, sizeof(struct processtop)); | |
484 | new->threads = g_ptr_array_new(); | |
485 | new->comm = strdup(tmp->comm); | |
486 | new->process_files_table = g_ptr_array_new(); | |
ceb3a221 | 487 | new->files_history = tmp->files_history; |
85db4618 | 488 | new->perf = g_hash_table_new(g_str_hash, g_str_equal); |
1fc22eb4 JD |
489 | g_hash_table_foreach(tmp->perf, copy_perf_counter, new->perf); |
490 | ||
1fc22eb4 | 491 | /* compute the stream speed */ |
85db4618 JD |
492 | if (end - start != 0) { |
493 | time = (end - start) / NSEC_PER_SEC; | |
b093de8a MB |
494 | new->fileread = new->fileread/(time); |
495 | new->filewrite = new->filewrite/(time); | |
1fc22eb4 JD |
496 | } |
497 | ||
498 | for (j = 0; j < tmp->process_files_table->len; j++) { | |
499 | tmpfile = g_ptr_array_index(tmp->process_files_table, j); | |
1fc22eb4 | 500 | |
b093de8a MB |
501 | newfile = malloc(sizeof(struct files)); |
502 | ||
503 | if (tmpfile != NULL) { | |
504 | memcpy(newfile, tmpfile, sizeof(struct files)); | |
505 | newfile->name = strdup(tmpfile->name); | |
506 | newfile->ref = new; | |
507 | g_ptr_array_add(new->process_files_table, | |
508 | newfile); | |
509 | g_ptr_array_add(dst->files_table, newfile); | |
510 | } else { | |
511 | g_ptr_array_add(new->process_files_table, NULL); | |
512 | g_ptr_array_add(dst->files_table, NULL); | |
513 | } | |
1fc22eb4 JD |
514 | /* |
515 | * if the process died during the last period, we remove all | |
516 | * files associated with if after the copy | |
517 | */ | |
518 | if (tmp->death > 0 && tmp->death < end) { | |
e05a35a6 | 519 | /* FIXME : close the files before */ |
1fc22eb4 | 520 | g_ptr_array_remove(tmp->process_files_table, tmpfile); |
559c9f86 | 521 | g_free(tmpfile); |
1fc22eb4 JD |
522 | } |
523 | } | |
524 | g_ptr_array_add(dst->process_table, new); | |
525 | ||
526 | /* | |
527 | * if the process died during the last period, we remove it from | |
528 | * the current process list after the copy | |
529 | */ | |
530 | if (tmp->death > 0 && tmp->death < end) { | |
531 | g_ptr_array_remove(lttngtop.process_table, tmp); | |
85db4618 | 532 | /* FIXME : TRUE does not mean clears the object in it */ |
1fc22eb4 JD |
533 | g_ptr_array_free(tmp->threads, TRUE); |
534 | free(tmp->comm); | |
535 | g_ptr_array_free(tmp->process_files_table, TRUE); | |
85db4618 | 536 | /* FIXME : clear elements */ |
1fc22eb4 | 537 | g_hash_table_destroy(tmp->perf); |
559c9f86 | 538 | g_free(tmp); |
1fc22eb4 JD |
539 | } |
540 | } | |
541 | rotate_perfcounter(); | |
542 | ||
543 | for (i = 0; i < lttngtop.cpu_table->len; i++) { | |
544 | tmpcpu = g_ptr_array_index(lttngtop.cpu_table, i); | |
559c9f86 | 545 | newcpu = g_new0(struct cputime, 1); |
1fc22eb4 | 546 | memcpy(newcpu, tmpcpu, sizeof(struct cputime)); |
85db4618 | 547 | newcpu->perf = g_hash_table_new(g_str_hash, g_str_equal); |
1fc22eb4 JD |
548 | g_hash_table_foreach(tmpcpu->perf, copy_perf_counter, newcpu->perf); |
549 | /* | |
550 | * note : we don't care about the current process pointer in the copy | |
551 | * so the reference is invalid after the memcpy | |
552 | */ | |
553 | g_ptr_array_add(dst->cpu_table, newcpu); | |
554 | } | |
da4353bb JD |
555 | if (lttngtop.kprobes_table) { |
556 | for (i = 0; i < lttngtop.kprobes_table->len; i++) { | |
557 | tmpprobe = g_ptr_array_index(lttngtop.kprobes_table, i); | |
558 | newprobe = g_new0(struct kprobes, 1); | |
559 | memcpy(newprobe, tmpprobe, sizeof(struct kprobes)); | |
560 | tmpprobe->count = 0; | |
561 | g_ptr_array_add(dst->kprobes_table, newprobe); | |
562 | } | |
246d5992 | 563 | } |
85db4618 | 564 | /* FIXME : better algo */ |
1fc22eb4 JD |
565 | /* create the threads index if required */ |
566 | for (i = 0; i < dst->process_table->len; i++) { | |
567 | tmp = g_ptr_array_index(dst->process_table, i); | |
568 | if (tmp->pid == tmp->tid) { | |
569 | for (j = 0; j < dst->process_table->len; j++) { | |
570 | tmp2 = g_ptr_array_index(dst->process_table, j); | |
571 | if (tmp2->pid == tmp->pid) { | |
572 | tmp2->threadparent = tmp; | |
573 | g_ptr_array_add(tmp->threads, tmp2); | |
574 | } | |
575 | } | |
576 | } | |
577 | } | |
578 | ||
579 | // update_global_stats(dst); | |
580 | cleanup_processtop(); | |
581 | ||
582 | return dst; | |
583 | } | |
584 | ||
928f18a6 MB |
585 | |
586 | enum bt_cb_ret handle_statedump_process_state(struct bt_ctf_event *call_data, | |
587 | void *private_data) | |
588 | { | |
2e0a1190 | 589 | const struct bt_definition *scope; |
928f18a6 MB |
590 | struct processtop *proc; |
591 | unsigned long timestamp; | |
11d218ce | 592 | int64_t pid, tid, ppid, vtid, vpid, vppid; |
1d2391b4 | 593 | char *procname, *hostname = NULL; |
928f18a6 | 594 | |
c78f2cdc | 595 | timestamp = bt_ctf_get_timestamp(call_data); |
928f18a6 MB |
596 | if (timestamp == -1ULL) |
597 | goto error; | |
598 | ||
599 | scope = bt_ctf_get_top_level_scope(call_data, | |
600 | BT_EVENT_FIELDS); | |
601 | pid = bt_ctf_get_int64(bt_ctf_get_field(call_data, | |
602 | scope, "_pid")); | |
603 | if (bt_ctf_field_get_error()) { | |
604 | fprintf(stderr, "Missing pid context info\n"); | |
605 | goto error; | |
606 | } | |
11d218ce JD |
607 | ppid = bt_ctf_get_int64(bt_ctf_get_field(call_data, |
608 | scope, "_ppid")); | |
609 | if (bt_ctf_field_get_error()) { | |
8fe4d0cf | 610 | goto end; |
11d218ce | 611 | } |
928f18a6 MB |
612 | tid = bt_ctf_get_int64(bt_ctf_get_field(call_data, |
613 | scope, "_tid")); | |
614 | if (bt_ctf_field_get_error()) { | |
615 | fprintf(stderr, "Missing tid context info\n"); | |
616 | goto error; | |
617 | } | |
11d218ce JD |
618 | vtid = bt_ctf_get_int64(bt_ctf_get_field(call_data, |
619 | scope, "_vtid")); | |
620 | if (bt_ctf_field_get_error()) { | |
621 | fprintf(stderr, "Missing vtid context info\n"); | |
622 | goto error; | |
623 | } | |
624 | vpid = bt_ctf_get_int64(bt_ctf_get_field(call_data, | |
625 | scope, "_vpid")); | |
626 | if (bt_ctf_field_get_error()) { | |
b7194a4e | 627 | fprintf(stderr, "Missing vpid context info\n"); |
11d218ce JD |
628 | goto error; |
629 | } | |
630 | vppid = bt_ctf_get_int64(bt_ctf_get_field(call_data, | |
631 | scope, "_vppid")); | |
632 | if (bt_ctf_field_get_error()) { | |
b7194a4e | 633 | fprintf(stderr, "Missing vppid context info\n"); |
11d218ce JD |
634 | goto error; |
635 | } | |
636 | ||
928f18a6 MB |
637 | scope = bt_ctf_get_top_level_scope(call_data, |
638 | BT_EVENT_FIELDS); | |
639 | procname = bt_ctf_get_char_array(bt_ctf_get_field(call_data, | |
640 | scope, "_name")); | |
641 | if (bt_ctf_field_get_error()) { | |
642 | fprintf(stderr, "Missing process name context info\n"); | |
643 | goto error; | |
644 | } | |
645 | ||
646 | proc = find_process_tid(<tngtop, tid, procname); | |
647 | if (proc == NULL) | |
1d2391b4 JD |
648 | proc = add_proc(<tngtop, tid, procname, timestamp, hostname); |
649 | update_proc(proc, pid, tid, ppid, vpid, vtid, vppid, procname, hostname); | |
928f18a6 | 650 | |
96aa77de JD |
651 | if (proc) { |
652 | free(proc->comm); | |
653 | proc->comm = strdup(procname); | |
654 | proc->pid = pid; | |
655 | } | |
928f18a6 | 656 | |
8fe4d0cf | 657 | end: |
928f18a6 MB |
658 | return BT_CB_OK; |
659 | ||
660 | error: | |
661 | return BT_CB_ERROR_STOP; | |
662 | } | |
b520ab45 JD |
663 | |
664 | struct tm format_timestamp(uint64_t timestamp) | |
665 | { | |
666 | struct tm tm; | |
667 | uint64_t ts_sec = 0, ts_nsec; | |
668 | time_t time_s; | |
669 | ||
670 | ts_nsec = timestamp; | |
671 | ts_sec += ts_nsec / NSEC_PER_SEC; | |
672 | ts_nsec = ts_nsec % NSEC_PER_SEC; | |
673 | ||
674 | time_s = (time_t) ts_sec; | |
675 | ||
676 | localtime_r(&time_s, &tm); | |
677 | ||
678 | return tm; | |
679 | } | |
57bff788 JD |
680 | |
681 | int *lookup_tid_list(int tid) | |
682 | { | |
ea5d1dc9 | 683 | if (!tid_filter_list) |
da4353bb JD |
684 | return NULL; |
685 | ||
ea5d1dc9 | 686 | return g_hash_table_lookup(tid_filter_list, (gpointer) &tid); |
57bff788 | 687 | } |
c8d75a13 | 688 | |
114cae59 | 689 | struct host *lookup_hostname_list(const char *hostname) |
c8d75a13 | 690 | { |
114cae59 | 691 | if (!hostname || !global_host_list) |
c8d75a13 JD |
692 | return NULL; |
693 | ||
114cae59 | 694 | return g_hash_table_lookup(global_host_list, (gpointer) hostname); |
c8d75a13 | 695 | } |
da4353bb | 696 | |
114cae59 | 697 | int is_hostname_filtered(const char *hostname) |
906c08f6 | 698 | { |
114cae59 | 699 | struct host *host; |
906c08f6 | 700 | |
114cae59 JD |
701 | host = lookup_hostname_list(hostname); |
702 | if (host) | |
703 | return host->filter; | |
704 | return 0; | |
906c08f6 JD |
705 | } |
706 | ||
da4353bb JD |
707 | int *lookup_filter_tid_list(int tid) |
708 | { | |
709 | return g_hash_table_lookup(global_filter_list, (gpointer) &tid); | |
710 | } | |
711 | ||
b99227ca | 712 | void add_filter_tid_list(struct processtop *proc) |
da4353bb JD |
713 | { |
714 | unsigned long *hash_tid; | |
715 | ||
716 | hash_tid = malloc(sizeof(unsigned long)); | |
b99227ca | 717 | *hash_tid = proc->tid; |
da4353bb | 718 | g_hash_table_insert(global_filter_list, |
b99227ca | 719 | (gpointer) (unsigned long) hash_tid, proc); |
da4353bb JD |
720 | } |
721 | ||
722 | void remove_filter_tid_list(int tid) | |
723 | { | |
724 | g_hash_table_remove(global_filter_list, | |
725 | (gpointer) (unsigned long) &tid); | |
726 | } | |
467097ac | 727 | |
b99227ca | 728 | struct host *add_hostname_list(char *hostname, int filter) |
467097ac JD |
729 | { |
730 | struct host *host; | |
731 | ||
b99227ca JD |
732 | host = lookup_hostname_list(hostname); |
733 | if (host) | |
734 | return host; | |
467097ac JD |
735 | |
736 | host = g_new0(struct host, 1); | |
737 | host->hostname = strdup(hostname); | |
738 | host->filter = filter; | |
739 | g_hash_table_insert(global_host_list, | |
740 | (gpointer) host->hostname, | |
741 | (gpointer) host); | |
b99227ca JD |
742 | |
743 | return host; | |
744 | } | |
745 | ||
746 | void update_hostname_filter(struct host *host) | |
747 | { | |
748 | struct processtop *tmp; | |
749 | int i; | |
750 | ||
751 | for (i = 0; i < lttngtop.process_table->len; i++) { | |
752 | tmp = g_ptr_array_index(lttngtop.process_table, i); | |
753 | if (tmp->host == host) { | |
754 | if (host->filter) | |
755 | add_filter_tid_list(tmp); | |
756 | else | |
757 | remove_filter_tid_list(tmp->tid); | |
758 | } | |
759 | } | |
467097ac | 760 | } |
26e46dde JD |
761 | |
762 | char *lookup_procname(const char *procname) | |
763 | { | |
764 | if (!procname || !global_procname_list) | |
765 | return NULL; | |
766 | ||
767 | return g_hash_table_lookup(global_procname_list, (gpointer) procname); | |
768 | } | |
769 | ||
770 | char *add_procname_list(char *procname, int filter) | |
771 | { | |
772 | char *proc; | |
773 | ||
774 | proc = lookup_procname(procname); | |
775 | if (proc) | |
776 | return proc; | |
777 | ||
778 | proc = strdup(procname); | |
779 | g_hash_table_insert(global_procname_list, | |
780 | (gpointer) procname, (gpointer) procname); | |
781 | ||
782 | return proc; | |
783 | } |