Remove the # in the example so we can just copy/paste it to a shell
[lttngtop.git] / src / common.c
CommitLineData
1fc22eb4
JD
1/*
2 * Copyright (C) 2011 Julien Desfossez
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 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
1dec520a 19#include <babeltrace/ctf/events.h>
1fc22eb4
JD
20#include <stdlib.h>
21#include <string.h>
22#include "common.h"
23
d67167cd
JD
24uint64_t get_cpu_id(struct bt_ctf_event *event)
25{
26 struct definition *scope;
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
1dec520a
JD
39uint64_t get_context_tid(struct bt_ctf_event *event)
40{
41 struct definition *scope;
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()) {
48 fprintf(stderr, "Missing tid context info\n");
49 return -1ULL;
50 }
51
52 return tid;
53}
54
55uint64_t get_context_pid(struct bt_ctf_event *event)
56{
57 struct definition *scope;
58 uint64_t pid;
59
60 scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT);
61 pid = bt_ctf_get_int64(bt_ctf_get_field(event,
62 scope, "_pid"));
63 if (bt_ctf_field_get_error()) {
64 fprintf(stderr, "Missing pid context info\n");
65 return -1ULL;
66 }
67
68 return pid;
69}
70
71uint64_t get_context_ppid(struct bt_ctf_event *event)
72{
73 struct definition *scope;
74 uint64_t ppid;
75
76 scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT);
77 ppid = bt_ctf_get_int64(bt_ctf_get_field(event,
78 scope, "_ppid"));
79 if (bt_ctf_field_get_error()) {
80 fprintf(stderr, "Missing ppid context info\n");
81 return -1ULL;
82 }
83
84 return ppid;
85}
86
87char *get_context_comm(struct bt_ctf_event *event)
88{
89 struct definition *scope;
90 char *comm;
91
92 scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT);
93 comm = bt_ctf_get_char_array(bt_ctf_get_field(event,
94 scope, "_procname"));
95 if (bt_ctf_field_get_error()) {
96 fprintf(stderr, "Missing comm context info\n");
97 return NULL;
98 }
99
100 return comm;
101}
102
1fc22eb4
JD
103struct processtop *find_process_tid(struct lttngtop *ctx, int tid, char *comm)
104{
105 gint i;
106 struct processtop *tmp;
107
108 for (i = 0; i < ctx->process_table->len; i++) {
109 tmp = g_ptr_array_index(ctx->process_table, i);
110 if (tmp && tmp->tid == tid)
111 return tmp;
112 }
113 return NULL;
114}
115
116struct processtop* add_proc(struct lttngtop *ctx, int tid, char *comm,
117 unsigned long timestamp)
118{
119 struct processtop *newproc;
120
121 /* if the PID already exists, we just rename the process */
122 /* FIXME : need to integrate with clone/fork/exit to be accurate */
123 newproc = find_process_tid(ctx, tid, comm);
124 if (!newproc) {
559c9f86 125 newproc = g_new0(struct processtop, 1);
1fc22eb4
JD
126 newproc->tid = tid;
127 newproc->birth = timestamp;
128 newproc->process_files_table = g_ptr_array_new();
b093de8a
MB
129 newproc->files_history = g_new0(struct file_history, 1);
130 newproc->files_history->next = NULL;
131 newproc->totalfileread = 0;
132 newproc->totalfilewrite = 0;
133 newproc->fileread = 0;
134 newproc->filewrite = 0;
135 newproc->syscall_info = NULL;
1fc22eb4 136 newproc->threads = g_ptr_array_new();
85db4618 137 newproc->perf = g_hash_table_new(g_str_hash, g_str_equal);
1fc22eb4
JD
138 g_ptr_array_add(ctx->process_table, newproc);
139 }
140 newproc->comm = strdup(comm);
141
142 return newproc;
143}
144
145struct processtop* update_proc(struct processtop* proc, int pid, int tid,
146 int ppid, char *comm)
147{
148 if (proc) {
149 proc->pid = pid;
150 proc->tid = tid;
151 proc->ppid = ppid;
152 if (strcmp(proc->comm, comm) != 0) {
153 free(proc->comm);
154 proc->comm = strdup(comm);
155 }
156 }
157 return proc;
158}
159
160/*
161 * This function just sets the time of death of a process.
162 * When we rotate the cputime we remove it from the process list.
163 */
164void death_proc(struct lttngtop *ctx, int tid, char *comm,
165 unsigned long timestamp)
166{
167 struct processtop *tmp;
168 tmp = find_process_tid(ctx, tid, comm);
169 if (tmp && strcmp(tmp->comm, comm) == 0)
170 tmp->death = timestamp;
171}
172
173struct processtop* get_proc(struct lttngtop *ctx, int tid, char *comm,
174 unsigned long timestamp)
175{
176 struct processtop *tmp;
177 tmp = find_process_tid(ctx, tid, comm);
178 if (tmp && strcmp(tmp->comm, comm) == 0)
179 return tmp;
180 return add_proc(ctx, tid, comm, timestamp);
181}
182
183void add_thread(struct processtop *parent, struct processtop *thread)
184{
185 gint i;
186 struct processtop *tmp;
187
188 for (i = 0; i < parent->threads->len; i++) {
189 tmp = g_ptr_array_index(parent->threads, i);
190 if (tmp == thread)
191 return;
192 }
193 g_ptr_array_add(parent->threads, thread);
194}
195
196struct cputime* add_cpu(int cpu)
197{
198 struct cputime *newcpu;
199
559c9f86 200 newcpu = g_new0(struct cputime, 1);
1fc22eb4
JD
201 newcpu->id = cpu;
202 newcpu->current_task = NULL;
85db4618 203 newcpu->perf = g_hash_table_new(g_str_hash, g_str_equal);
1fc22eb4
JD
204
205 g_ptr_array_add(lttngtop.cpu_table, newcpu);
206
207 return newcpu;
208}
209struct cputime* get_cpu(int cpu)
210{
211 gint i;
212 struct cputime *tmp;
213
214 for (i = 0; i < lttngtop.cpu_table->len; i++) {
215 tmp = g_ptr_array_index(lttngtop.cpu_table, i);
216 if (tmp->id == cpu)
217 return tmp;
218 }
219
220 return add_cpu(cpu);
221}
222
223/*
224 * At the end of a sampling period, we need to display the cpu time for each
225 * process and to reset it to zero for the next period
226 */
227void rotate_cputime(unsigned long end)
228{
229 gint i;
230 struct cputime *tmp;
231 unsigned long elapsed;
232
233 for (i = 0; i < lttngtop.cpu_table->len; i++) {
234 tmp = g_ptr_array_index(lttngtop.cpu_table, i);
235 elapsed = end - tmp->task_start;
236 if (tmp->current_task) {
237 tmp->current_task->totalcpunsec += elapsed;
238 tmp->current_task->threadstotalcpunsec += elapsed;
239 if (tmp->current_task->pid != tmp->current_task->tid &&
240 tmp->current_task->threadparent) {
241 tmp->current_task->threadparent->threadstotalcpunsec += elapsed;
242 }
243 }
244 tmp->task_start = end;
245 }
246}
247
248void reset_perf_counter(gpointer key, gpointer value, gpointer user_data)
249{
250 ((struct perfcounter*) value)->count = 0;
251}
252
253void copy_perf_counter(gpointer key, gpointer value, gpointer new_table)
254{
255 struct perfcounter *newperf;
256
559c9f86 257 newperf = g_new0(struct perfcounter, 1);
1fc22eb4
JD
258 newperf->count = ((struct perfcounter *) value)->count;
259 newperf->visible = ((struct perfcounter *) value)->visible;
260 newperf->sort = ((struct perfcounter *) value)->sort;
85db4618 261 g_hash_table_insert((GHashTable *) new_table, strdup(key), newperf);
1fc22eb4
JD
262}
263
264void rotate_perfcounter() {
265 int i;
266 struct processtop *tmp;
267 for (i = 0; i < lttngtop.process_table->len; i++) {
268 tmp = g_ptr_array_index(lttngtop.process_table, i);
269 g_hash_table_foreach(tmp->perf, reset_perf_counter, NULL);
270 }
271}
272
273void cleanup_processtop()
274{
b093de8a 275 gint i, j;
1fc22eb4 276 struct processtop *tmp;
b093de8a 277 struct files *tmpf; /* a temporary file */
1fc22eb4
JD
278
279 for (i = 0; i < lttngtop.process_table->len; i++) {
280 tmp = g_ptr_array_index(lttngtop.process_table, i);
281 tmp->totalcpunsec = 0;
282 tmp->threadstotalcpunsec = 0;
b093de8a
MB
283 tmp->fileread = 0;
284 tmp->filewrite = 0;
285
286 for (j = 0; j < tmp->process_files_table->len; j++) {
287 tmpf = g_ptr_array_index(tmp->process_files_table, j);
288 if (tmpf != NULL) {
289 tmpf->read = 0;
290 tmpf->write = 0;
291 }
292 }
1fc22eb4
JD
293 }
294}
295
296struct lttngtop* get_copy_lttngtop(unsigned long start, unsigned long end)
297{
298 gint i, j;
299 unsigned long time;
300 struct lttngtop *dst;
301 struct processtop *tmp, *tmp2, *new;
302 struct cputime *tmpcpu, *newcpu;
303 struct files *tmpfile, *newfile;
304
559c9f86 305 dst = g_new0(struct lttngtop, 1);
1fc22eb4
JD
306 dst->start = start;
307 dst->end = end;
308 dst->process_table = g_ptr_array_new();
309 dst->files_table = g_ptr_array_new();
310 dst->cpu_table = g_ptr_array_new();
85db4618 311 dst->perf_list = g_hash_table_new(g_str_hash, g_str_equal);
1fc22eb4
JD
312
313 rotate_cputime(end);
314
315 g_hash_table_foreach(lttngtop.perf_list, copy_perf_counter, dst->perf_list);
316 for (i = 0; i < lttngtop.process_table->len; i++) {
317 tmp = g_ptr_array_index(lttngtop.process_table, i);
559c9f86 318 new = g_new0(struct processtop, 1);
1fc22eb4
JD
319
320 memcpy(new, tmp, sizeof(struct processtop));
321 new->threads = g_ptr_array_new();
322 new->comm = strdup(tmp->comm);
323 new->process_files_table = g_ptr_array_new();
85db4618 324 new->perf = g_hash_table_new(g_str_hash, g_str_equal);
1fc22eb4
JD
325 g_hash_table_foreach(tmp->perf, copy_perf_counter, new->perf);
326
1fc22eb4 327 /* compute the stream speed */
85db4618
JD
328 if (end - start != 0) {
329 time = (end - start) / NSEC_PER_SEC;
b093de8a
MB
330 new->fileread = new->fileread/(time);
331 new->filewrite = new->filewrite/(time);
1fc22eb4
JD
332 }
333
334 for (j = 0; j < tmp->process_files_table->len; j++) {
335 tmpfile = g_ptr_array_index(tmp->process_files_table, j);
1fc22eb4 336
b093de8a
MB
337 newfile = malloc(sizeof(struct files));
338
339 if (tmpfile != NULL) {
340 memcpy(newfile, tmpfile, sizeof(struct files));
341 newfile->name = strdup(tmpfile->name);
342 newfile->ref = new;
343 g_ptr_array_add(new->process_files_table,
344 newfile);
345 g_ptr_array_add(dst->files_table, newfile);
346 } else {
347 g_ptr_array_add(new->process_files_table, NULL);
348 g_ptr_array_add(dst->files_table, NULL);
349 }
1fc22eb4
JD
350 /*
351 * if the process died during the last period, we remove all
352 * files associated with if after the copy
353 */
354 if (tmp->death > 0 && tmp->death < end) {
355 g_ptr_array_remove(tmp->process_files_table, tmpfile);
559c9f86 356 g_free(tmpfile);
1fc22eb4
JD
357 }
358 }
359 g_ptr_array_add(dst->process_table, new);
360
361 /*
362 * if the process died during the last period, we remove it from
363 * the current process list after the copy
364 */
365 if (tmp->death > 0 && tmp->death < end) {
366 g_ptr_array_remove(lttngtop.process_table, tmp);
85db4618 367 /* FIXME : TRUE does not mean clears the object in it */
1fc22eb4
JD
368 g_ptr_array_free(tmp->threads, TRUE);
369 free(tmp->comm);
370 g_ptr_array_free(tmp->process_files_table, TRUE);
85db4618 371 /* FIXME : clear elements */
1fc22eb4 372 g_hash_table_destroy(tmp->perf);
559c9f86 373 g_free(tmp);
1fc22eb4
JD
374 }
375 }
376 rotate_perfcounter();
377
378 for (i = 0; i < lttngtop.cpu_table->len; i++) {
379 tmpcpu = g_ptr_array_index(lttngtop.cpu_table, i);
559c9f86 380 newcpu = g_new0(struct cputime, 1);
1fc22eb4 381 memcpy(newcpu, tmpcpu, sizeof(struct cputime));
85db4618 382 newcpu->perf = g_hash_table_new(g_str_hash, g_str_equal);
1fc22eb4
JD
383 g_hash_table_foreach(tmpcpu->perf, copy_perf_counter, newcpu->perf);
384 /*
385 * note : we don't care about the current process pointer in the copy
386 * so the reference is invalid after the memcpy
387 */
388 g_ptr_array_add(dst->cpu_table, newcpu);
389 }
85db4618 390 /* FIXME : better algo */
1fc22eb4
JD
391 /* create the threads index if required */
392 for (i = 0; i < dst->process_table->len; i++) {
393 tmp = g_ptr_array_index(dst->process_table, i);
394 if (tmp->pid == tmp->tid) {
395 for (j = 0; j < dst->process_table->len; j++) {
396 tmp2 = g_ptr_array_index(dst->process_table, j);
397 if (tmp2->pid == tmp->pid) {
398 tmp2->threadparent = tmp;
399 g_ptr_array_add(tmp->threads, tmp2);
400 }
401 }
402 }
403 }
404
405 // update_global_stats(dst);
406 cleanup_processtop();
407
408 return dst;
409}
410
This page took 0.037241 seconds and 4 git commands to generate.