displaying closed files
[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 19#include <stdlib.h>
ceb3a221 20#include <linux/unistd.h>
1fc22eb4
JD
21#include <string.h>
22#include "common.h"
23
3ba84bed 24uint64_t get_cpu_id(const struct bt_ctf_event *event)
d67167cd 25{
3ba84bed 26 const struct 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
3ba84bed 39uint64_t get_context_tid(const struct bt_ctf_event *event)
1dec520a 40{
3ba84bed 41 const struct 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()) {
48 fprintf(stderr, "Missing tid context info\n");
49 return -1ULL;
50 }
51
52 return tid;
53}
54
3ba84bed 55uint64_t get_context_pid(const struct bt_ctf_event *event)
1dec520a 56{
3ba84bed 57 const struct definition *scope;
1dec520a
JD
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
3ba84bed 71uint64_t get_context_ppid(const struct bt_ctf_event *event)
1dec520a 72{
3ba84bed 73 const struct definition *scope;
1dec520a
JD
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
3ba84bed 87char *get_context_comm(const struct bt_ctf_event *event)
1dec520a 88{
3ba84bed 89 const struct definition *scope;
1dec520a
JD
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();
ceb3a221 129 newproc->files_history = NULL;
b093de8a
MB
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;
ceb3a221
MB
290
291 if (tmpf->flag == __NR_close)
292 g_ptr_array_index(
293 tmp->process_files_table, j
294 ) = NULL;
b093de8a
MB
295 }
296 }
1fc22eb4
JD
297 }
298}
299
300struct lttngtop* get_copy_lttngtop(unsigned long start, unsigned long end)
301{
302 gint i, j;
303 unsigned long time;
304 struct lttngtop *dst;
305 struct processtop *tmp, *tmp2, *new;
306 struct cputime *tmpcpu, *newcpu;
307 struct files *tmpfile, *newfile;
308
559c9f86 309 dst = g_new0(struct lttngtop, 1);
1fc22eb4
JD
310 dst->start = start;
311 dst->end = end;
312 dst->process_table = g_ptr_array_new();
313 dst->files_table = g_ptr_array_new();
314 dst->cpu_table = g_ptr_array_new();
85db4618 315 dst->perf_list = g_hash_table_new(g_str_hash, g_str_equal);
1fc22eb4
JD
316
317 rotate_cputime(end);
318
319 g_hash_table_foreach(lttngtop.perf_list, copy_perf_counter, dst->perf_list);
320 for (i = 0; i < lttngtop.process_table->len; i++) {
321 tmp = g_ptr_array_index(lttngtop.process_table, i);
559c9f86 322 new = g_new0(struct processtop, 1);
1fc22eb4
JD
323
324 memcpy(new, tmp, sizeof(struct processtop));
325 new->threads = g_ptr_array_new();
326 new->comm = strdup(tmp->comm);
327 new->process_files_table = g_ptr_array_new();
ceb3a221 328 new->files_history = tmp->files_history;
85db4618 329 new->perf = g_hash_table_new(g_str_hash, g_str_equal);
1fc22eb4
JD
330 g_hash_table_foreach(tmp->perf, copy_perf_counter, new->perf);
331
1fc22eb4 332 /* compute the stream speed */
85db4618
JD
333 if (end - start != 0) {
334 time = (end - start) / NSEC_PER_SEC;
b093de8a
MB
335 new->fileread = new->fileread/(time);
336 new->filewrite = new->filewrite/(time);
1fc22eb4
JD
337 }
338
339 for (j = 0; j < tmp->process_files_table->len; j++) {
340 tmpfile = g_ptr_array_index(tmp->process_files_table, j);
1fc22eb4 341
b093de8a
MB
342 newfile = malloc(sizeof(struct files));
343
344 if (tmpfile != NULL) {
345 memcpy(newfile, tmpfile, sizeof(struct files));
346 newfile->name = strdup(tmpfile->name);
347 newfile->ref = new;
348 g_ptr_array_add(new->process_files_table,
349 newfile);
350 g_ptr_array_add(dst->files_table, newfile);
351 } else {
352 g_ptr_array_add(new->process_files_table, NULL);
353 g_ptr_array_add(dst->files_table, NULL);
354 }
1fc22eb4
JD
355 /*
356 * if the process died during the last period, we remove all
357 * files associated with if after the copy
358 */
359 if (tmp->death > 0 && tmp->death < end) {
360 g_ptr_array_remove(tmp->process_files_table, tmpfile);
559c9f86 361 g_free(tmpfile);
1fc22eb4
JD
362 }
363 }
364 g_ptr_array_add(dst->process_table, new);
365
366 /*
367 * if the process died during the last period, we remove it from
368 * the current process list after the copy
369 */
370 if (tmp->death > 0 && tmp->death < end) {
371 g_ptr_array_remove(lttngtop.process_table, tmp);
85db4618 372 /* FIXME : TRUE does not mean clears the object in it */
1fc22eb4
JD
373 g_ptr_array_free(tmp->threads, TRUE);
374 free(tmp->comm);
375 g_ptr_array_free(tmp->process_files_table, TRUE);
85db4618 376 /* FIXME : clear elements */
1fc22eb4 377 g_hash_table_destroy(tmp->perf);
559c9f86 378 g_free(tmp);
1fc22eb4
JD
379 }
380 }
381 rotate_perfcounter();
382
383 for (i = 0; i < lttngtop.cpu_table->len; i++) {
384 tmpcpu = g_ptr_array_index(lttngtop.cpu_table, i);
559c9f86 385 newcpu = g_new0(struct cputime, 1);
1fc22eb4 386 memcpy(newcpu, tmpcpu, sizeof(struct cputime));
85db4618 387 newcpu->perf = g_hash_table_new(g_str_hash, g_str_equal);
1fc22eb4
JD
388 g_hash_table_foreach(tmpcpu->perf, copy_perf_counter, newcpu->perf);
389 /*
390 * note : we don't care about the current process pointer in the copy
391 * so the reference is invalid after the memcpy
392 */
393 g_ptr_array_add(dst->cpu_table, newcpu);
394 }
85db4618 395 /* FIXME : better algo */
1fc22eb4
JD
396 /* create the threads index if required */
397 for (i = 0; i < dst->process_table->len; i++) {
398 tmp = g_ptr_array_index(dst->process_table, i);
399 if (tmp->pid == tmp->tid) {
400 for (j = 0; j < dst->process_table->len; j++) {
401 tmp2 = g_ptr_array_index(dst->process_table, j);
402 if (tmp2->pid == tmp->pid) {
403 tmp2->threadparent = tmp;
404 g_ptr_array_add(tmp->threads, tmp2);
405 }
406 }
407 }
408 }
409
410 // update_global_stats(dst);
411 cleanup_processtop();
412
413 return dst;
414}
415
This page took 0.060799 seconds and 4 git commands to generate.