e59de36c8157ffb6512f6f3a01872978f9fbe098
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
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23 struct processtop
*find_process_tid(struct lttngtop
*ctx
, int tid
, char *comm
)
26 struct processtop
*tmp
;
28 for (i
= 0; i
< ctx
->process_table
->len
; i
++) {
29 tmp
= g_ptr_array_index(ctx
->process_table
, i
);
30 if (tmp
&& tmp
->tid
== tid
)
36 struct processtop
* add_proc(struct lttngtop
*ctx
, int tid
, char *comm
,
37 unsigned long timestamp
)
39 struct processtop
*newproc
;
41 /* if the PID already exists, we just rename the process */
42 /* FIXME : need to integrate with clone/fork/exit to be accurate */
43 newproc
= find_process_tid(ctx
, tid
, comm
);
45 newproc
= g_new0(struct processtop
, 1);
47 newproc
->birth
= timestamp
;
48 newproc
->process_files_table
= g_ptr_array_new();
49 newproc
->threads
= g_ptr_array_new();
50 newproc
->perf
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
51 newproc
->iostream
= g_new0(struct iostream
, 1);
52 newproc
->iostream
->ret_read
= 0;
53 newproc
->iostream
->ret_write
= 0;
54 newproc
->iostream
->ret_total
= 0;
55 newproc
->iostream
->syscall_info
= NULL
;
56 g_ptr_array_add(ctx
->process_table
, newproc
);
58 newproc
->comm
= strdup(comm
);
63 struct processtop
* update_proc(struct processtop
* proc
, int pid
, int tid
,
70 if (strcmp(proc
->comm
, comm
) != 0) {
72 proc
->comm
= strdup(comm
);
79 * This function just sets the time of death of a process.
80 * When we rotate the cputime we remove it from the process list.
82 void death_proc(struct lttngtop
*ctx
, int tid
, char *comm
,
83 unsigned long timestamp
)
85 struct processtop
*tmp
;
86 tmp
= find_process_tid(ctx
, tid
, comm
);
87 if (tmp
&& strcmp(tmp
->comm
, comm
) == 0)
88 tmp
->death
= timestamp
;
91 struct processtop
* get_proc(struct lttngtop
*ctx
, int tid
, char *comm
,
92 unsigned long timestamp
)
94 struct processtop
*tmp
;
95 tmp
= find_process_tid(ctx
, tid
, comm
);
96 if (tmp
&& strcmp(tmp
->comm
, comm
) == 0)
98 return add_proc(ctx
, tid
, comm
, timestamp
);
101 void add_thread(struct processtop
*parent
, struct processtop
*thread
)
104 struct processtop
*tmp
;
106 for (i
= 0; i
< parent
->threads
->len
; i
++) {
107 tmp
= g_ptr_array_index(parent
->threads
, i
);
111 g_ptr_array_add(parent
->threads
, thread
);
114 struct cputime
* add_cpu(int cpu
)
116 struct cputime
*newcpu
;
118 newcpu
= g_new0(struct cputime
, 1);
120 newcpu
->current_task
= NULL
;
121 newcpu
->perf
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
123 g_ptr_array_add(lttngtop
.cpu_table
, newcpu
);
127 struct cputime
* get_cpu(int cpu
)
132 for (i
= 0; i
< lttngtop
.cpu_table
->len
; i
++) {
133 tmp
= g_ptr_array_index(lttngtop
.cpu_table
, i
);
142 * At the end of a sampling period, we need to display the cpu time for each
143 * process and to reset it to zero for the next period
145 void rotate_cputime(unsigned long end
)
149 unsigned long elapsed
;
151 for (i
= 0; i
< lttngtop
.cpu_table
->len
; i
++) {
152 tmp
= g_ptr_array_index(lttngtop
.cpu_table
, i
);
153 elapsed
= end
- tmp
->task_start
;
154 if (tmp
->current_task
) {
155 tmp
->current_task
->totalcpunsec
+= elapsed
;
156 tmp
->current_task
->threadstotalcpunsec
+= elapsed
;
157 if (tmp
->current_task
->pid
!= tmp
->current_task
->tid
&&
158 tmp
->current_task
->threadparent
) {
159 tmp
->current_task
->threadparent
->threadstotalcpunsec
+= elapsed
;
162 tmp
->task_start
= end
;
166 void reset_perf_counter(gpointer key
, gpointer value
, gpointer user_data
)
168 ((struct perfcounter
*) value
)->count
= 0;
171 void copy_perf_counter(gpointer key
, gpointer value
, gpointer new_table
)
173 struct perfcounter
*newperf
;
175 newperf
= g_new0(struct perfcounter
, 1);
176 newperf
->count
= ((struct perfcounter
*) value
)->count
;
177 newperf
->visible
= ((struct perfcounter
*) value
)->visible
;
178 newperf
->sort
= ((struct perfcounter
*) value
)->sort
;
179 g_hash_table_insert((GHashTable
*) new_table
, key
, newperf
);
182 void rotate_perfcounter() {
184 struct processtop
*tmp
;
185 for (i
= 0; i
< lttngtop
.process_table
->len
; i
++) {
186 tmp
= g_ptr_array_index(lttngtop
.process_table
, i
);
187 g_hash_table_foreach(tmp
->perf
, reset_perf_counter
, NULL
);
191 void cleanup_processtop()
194 struct processtop
*tmp
;
196 for (i
= 0; i
< lttngtop
.process_table
->len
; i
++) {
197 tmp
= g_ptr_array_index(lttngtop
.process_table
, i
);
198 tmp
->totalcpunsec
= 0;
199 tmp
->threadstotalcpunsec
= 0;
200 tmp
->iostream
->ret_read
= 0;
201 tmp
->iostream
->ret_write
= 0;
205 struct lttngtop
* get_copy_lttngtop(unsigned long start
, unsigned long end
)
209 struct lttngtop
*dst
;
210 struct processtop
*tmp
, *tmp2
, *new;
211 struct cputime
*tmpcpu
, *newcpu
;
212 struct files
*tmpfile
, *newfile
;
214 dst
= g_new0(struct lttngtop
, 1);
217 dst
->process_table
= g_ptr_array_new();
218 dst
->files_table
= g_ptr_array_new();
219 dst
->cpu_table
= g_ptr_array_new();
220 dst
->perf_list
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
224 g_hash_table_foreach(lttngtop
.perf_list
, copy_perf_counter
, dst
->perf_list
);
225 for (i
= 0; i
< lttngtop
.process_table
->len
; i
++) {
226 tmp
= g_ptr_array_index(lttngtop
.process_table
, i
);
227 new = g_new0(struct processtop
, 1);
229 memcpy(new, tmp
, sizeof(struct processtop
));
230 new->threads
= g_ptr_array_new();
231 new->comm
= strdup(tmp
->comm
);
232 new->process_files_table
= g_ptr_array_new();
233 new->perf
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
234 g_hash_table_foreach(tmp
->perf
, copy_perf_counter
, new->perf
);
236 new->iostream
= g_new0(struct iostream
, 1);
237 memcpy(new->iostream
, tmp
->iostream
, sizeof(struct iostream
));
238 /* compute the stream speed */
239 if (end
- start
!= 0)
241 time
= (end
- start
)/NSEC_PER_SEC
;
242 new->iostream
->ret_read
= new->iostream
->ret_read
/(time
);
243 new->iostream
->ret_write
= new->iostream
->ret_write
/(time
);
246 for (j
= 0; j
< tmp
->process_files_table
->len
; j
++) {
247 tmpfile
= g_ptr_array_index(tmp
->process_files_table
, j
);
248 newfile
= g_new0(struct files
, 1);
250 memcpy(newfile
, tmpfile
, sizeof(struct files
));
252 newfile
->name
= strdup(tmpfile
->name
);
255 g_ptr_array_add(new->process_files_table
, newfile
);
256 g_ptr_array_add(dst
->files_table
, newfile
);
259 * if the process died during the last period, we remove all
260 * files associated with if after the copy
262 if (tmp
->death
> 0 && tmp
->death
< end
) {
263 g_ptr_array_remove(tmp
->process_files_table
, tmpfile
);
267 g_ptr_array_add(dst
->process_table
, new);
270 * if the process died during the last period, we remove it from
271 * the current process list after the copy
273 if (tmp
->death
> 0 && tmp
->death
< end
) {
274 g_ptr_array_remove(lttngtop
.process_table
, tmp
);
275 g_ptr_array_free(tmp
->threads
, TRUE
);
277 g_ptr_array_free(tmp
->process_files_table
, TRUE
);
278 g_hash_table_destroy(tmp
->perf
);
282 rotate_perfcounter();
284 for (i
= 0; i
< lttngtop
.cpu_table
->len
; i
++) {
285 tmpcpu
= g_ptr_array_index(lttngtop
.cpu_table
, i
);
286 newcpu
= g_new0(struct cputime
, 1);
287 memcpy(newcpu
, tmpcpu
, sizeof(struct cputime
));
288 newcpu
->perf
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
289 g_hash_table_foreach(tmpcpu
->perf
, copy_perf_counter
, newcpu
->perf
);
291 * note : we don't care about the current process pointer in the copy
292 * so the reference is invalid after the memcpy
294 g_ptr_array_add(dst
->cpu_table
, newcpu
);
296 /* create the threads index if required */
297 for (i
= 0; i
< dst
->process_table
->len
; i
++) {
298 tmp
= g_ptr_array_index(dst
->process_table
, i
);
299 if (tmp
->pid
== tmp
->tid
) {
300 for (j
= 0; j
< dst
->process_table
->len
; j
++) {
301 tmp2
= g_ptr_array_index(dst
->process_table
, j
);
302 if (tmp2
->pid
== tmp
->pid
) {
303 tmp2
->threadparent
= tmp
;
304 g_ptr_array_add(tmp
->threads
, tmp2
);
310 // update_global_stats(dst);
311 cleanup_processtop();
This page took 0.034896 seconds and 4 git commands to generate.