2 * Copyright (C) 2011 Julien Desfossez
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;
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.
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.
18 #include <babeltrace/ctf/events.h>
23 uint64_t get_cpu_id(struct bt_ctf_event
*event
)
25 struct definition
*scope
;
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");
38 uint64_t get_context_tid(struct bt_ctf_event
*event
)
40 struct definition
*scope
;
43 scope
= bt_ctf_get_top_level_scope(event
, BT_STREAM_EVENT_CONTEXT
);
44 tid
= bt_ctf_get_int64(bt_ctf_get_field(event
,
46 if (bt_ctf_field_get_error()) {
47 fprintf(stderr
, "Missing tid context info\n");
54 uint64_t get_context_pid(struct bt_ctf_event
*event
)
56 struct definition
*scope
;
59 scope
= bt_ctf_get_top_level_scope(event
, BT_STREAM_EVENT_CONTEXT
);
60 pid
= bt_ctf_get_int64(bt_ctf_get_field(event
,
62 if (bt_ctf_field_get_error()) {
63 fprintf(stderr
, "Missing pid context info\n");
70 uint64_t get_context_ppid(struct bt_ctf_event
*event
)
72 struct definition
*scope
;
75 scope
= bt_ctf_get_top_level_scope(event
, BT_STREAM_EVENT_CONTEXT
);
76 ppid
= bt_ctf_get_int64(bt_ctf_get_field(event
,
78 if (bt_ctf_field_get_error()) {
79 fprintf(stderr
, "Missing ppid context info\n");
86 char *get_context_comm(struct bt_ctf_event
*event
)
88 struct definition
*scope
;
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
,
94 if (bt_ctf_field_get_error()) {
95 fprintf(stderr
, "Missing comm context info\n");
102 struct processtop
*find_process_tid(struct lttngtop
*ctx
, int tid
, char *comm
)
105 struct processtop
*tmp
;
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
)
115 struct processtop
* add_proc(struct lttngtop
*ctx
, int tid
, char *comm
,
116 unsigned long timestamp
)
118 struct processtop
*newproc
;
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
);
124 newproc
= g_new0(struct processtop
, 1);
126 newproc
->birth
= timestamp
;
127 newproc
->process_files_table
= g_ptr_array_new();
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
;
135 newproc
->threads
= g_ptr_array_new();
136 newproc
->perf
= g_hash_table_new(g_str_hash
, g_str_equal
);
137 g_ptr_array_add(ctx
->process_table
, newproc
);
139 newproc
->comm
= strdup(comm
);
144 struct processtop
* update_proc(struct processtop
* proc
, int pid
, int tid
,
145 int ppid
, char *comm
)
151 if (strcmp(proc
->comm
, comm
) != 0) {
153 proc
->comm
= strdup(comm
);
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.
163 void death_proc(struct lttngtop
*ctx
, int tid
, char *comm
,
164 unsigned long timestamp
)
166 struct processtop
*tmp
;
167 tmp
= find_process_tid(ctx
, tid
, comm
);
168 if (tmp
&& strcmp(tmp
->comm
, comm
) == 0)
169 tmp
->death
= timestamp
;
172 struct processtop
* get_proc(struct lttngtop
*ctx
, int tid
, char *comm
,
173 unsigned long timestamp
)
175 struct processtop
*tmp
;
176 tmp
= find_process_tid(ctx
, tid
, comm
);
177 if (tmp
&& strcmp(tmp
->comm
, comm
) == 0)
179 return add_proc(ctx
, tid
, comm
, timestamp
);
182 void add_thread(struct processtop
*parent
, struct processtop
*thread
)
185 struct processtop
*tmp
;
187 for (i
= 0; i
< parent
->threads
->len
; i
++) {
188 tmp
= g_ptr_array_index(parent
->threads
, i
);
192 g_ptr_array_add(parent
->threads
, thread
);
195 struct cputime
* add_cpu(int cpu
)
197 struct cputime
*newcpu
;
199 newcpu
= g_new0(struct cputime
, 1);
201 newcpu
->current_task
= NULL
;
202 newcpu
->perf
= g_hash_table_new(g_str_hash
, g_str_equal
);
204 g_ptr_array_add(lttngtop
.cpu_table
, newcpu
);
208 struct cputime
* get_cpu(int cpu
)
213 for (i
= 0; i
< lttngtop
.cpu_table
->len
; i
++) {
214 tmp
= g_ptr_array_index(lttngtop
.cpu_table
, i
);
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
226 void rotate_cputime(unsigned long end
)
230 unsigned long elapsed
;
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
;
243 tmp
->task_start
= end
;
247 void reset_perf_counter(gpointer key
, gpointer value
, gpointer user_data
)
249 ((struct perfcounter
*) value
)->count
= 0;
252 void copy_perf_counter(gpointer key
, gpointer value
, gpointer new_table
)
254 struct perfcounter
*newperf
;
256 newperf
= g_new0(struct perfcounter
, 1);
257 newperf
->count
= ((struct perfcounter
*) value
)->count
;
258 newperf
->visible
= ((struct perfcounter
*) value
)->visible
;
259 newperf
->sort
= ((struct perfcounter
*) value
)->sort
;
260 g_hash_table_insert((GHashTable
*) new_table
, strdup(key
), newperf
);
263 void rotate_perfcounter() {
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
);
272 void cleanup_processtop()
275 struct processtop
*tmp
;
276 struct files
*tmpf
; /* a temporary file */
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;
285 for (j
= 0; j
< tmp
->process_files_table
->len
; j
++) {
286 tmpf
= g_ptr_array_index(tmp
->process_files_table
, j
);
295 struct lttngtop
* get_copy_lttngtop(unsigned long start
, unsigned long end
)
299 struct lttngtop
*dst
;
300 struct processtop
*tmp
, *tmp2
, *new;
301 struct cputime
*tmpcpu
, *newcpu
;
302 struct files
*tmpfile
, *newfile
;
304 dst
= g_new0(struct lttngtop
, 1);
307 dst
->process_table
= g_ptr_array_new();
308 dst
->files_table
= g_ptr_array_new();
309 dst
->cpu_table
= g_ptr_array_new();
310 dst
->perf_list
= g_hash_table_new(g_str_hash
, g_str_equal
);
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
);
317 new = g_new0(struct processtop
, 1);
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();
323 new->perf
= g_hash_table_new(g_str_hash
, g_str_equal
);
324 g_hash_table_foreach(tmp
->perf
, copy_perf_counter
, new->perf
);
326 /* compute the stream speed */
327 if (end
- start
!= 0) {
328 time
= (end
- start
) / NSEC_PER_SEC
;
329 new->fileread
= new->fileread
/(time
);
330 new->filewrite
= new->filewrite
/(time
);
333 for (j
= 0; j
< tmp
->process_files_table
->len
; j
++) {
334 tmpfile
= g_ptr_array_index(tmp
->process_files_table
, j
);
336 newfile
= malloc(sizeof(struct files
));
338 if (tmpfile
!= NULL
) {
339 memcpy(newfile
, tmpfile
, sizeof(struct files
));
340 newfile
->name
= strdup(tmpfile
->name
);
342 g_ptr_array_add(new->process_files_table
,
344 g_ptr_array_add(dst
->files_table
, newfile
);
346 g_ptr_array_add(new->process_files_table
, NULL
);
347 g_ptr_array_add(dst
->files_table
, NULL
);
350 * if the process died during the last period, we remove all
351 * files associated with if after the copy
353 if (tmp
->death
> 0 && tmp
->death
< end
) {
354 g_ptr_array_remove(tmp
->process_files_table
, tmpfile
);
358 g_ptr_array_add(dst
->process_table
, new);
361 * if the process died during the last period, we remove it from
362 * the current process list after the copy
364 if (tmp
->death
> 0 && tmp
->death
< end
) {
365 g_ptr_array_remove(lttngtop
.process_table
, tmp
);
366 /* FIXME : TRUE does not mean clears the object in it */
367 g_ptr_array_free(tmp
->threads
, TRUE
);
369 g_ptr_array_free(tmp
->process_files_table
, TRUE
);
370 /* FIXME : clear elements */
371 g_hash_table_destroy(tmp
->perf
);
375 rotate_perfcounter();
377 for (i
= 0; i
< lttngtop
.cpu_table
->len
; i
++) {
378 tmpcpu
= g_ptr_array_index(lttngtop
.cpu_table
, i
);
379 newcpu
= g_new0(struct cputime
, 1);
380 memcpy(newcpu
, tmpcpu
, sizeof(struct cputime
));
381 newcpu
->perf
= g_hash_table_new(g_str_hash
, g_str_equal
);
382 g_hash_table_foreach(tmpcpu
->perf
, copy_perf_counter
, newcpu
->perf
);
384 * note : we don't care about the current process pointer in the copy
385 * so the reference is invalid after the memcpy
387 g_ptr_array_add(dst
->cpu_table
, newcpu
);
389 /* FIXME : better algo */
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
);
404 // update_global_stats(dst);
405 cleanup_processtop();
This page took 0.042071 seconds and 4 git commands to generate.