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