replace malloc with g_new
[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
19#include <stdlib.h>
20#include <string.h>
21#include "common.h"
22
23struct processtop *find_process_tid(struct lttngtop *ctx, int tid, char *comm)
24{
25 gint i;
26 struct processtop *tmp;
27
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)
31 return tmp;
32 }
33 return NULL;
34}
35
36struct processtop* add_proc(struct lttngtop *ctx, int tid, char *comm,
37 unsigned long timestamp)
38{
39 struct processtop *newproc;
40
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);
44 if (!newproc) {
559c9f86 45 newproc = g_new0(struct processtop, 1);
1fc22eb4
JD
46 newproc->tid = tid;
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);
559c9f86 51 newproc->iostream = g_new0(struct iostream, 1);
1fc22eb4
JD
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);
57 }
58 newproc->comm = strdup(comm);
59
60 return newproc;
61}
62
63struct processtop* update_proc(struct processtop* proc, int pid, int tid,
64 int ppid, char *comm)
65{
66 if (proc) {
67 proc->pid = pid;
68 proc->tid = tid;
69 proc->ppid = ppid;
70 if (strcmp(proc->comm, comm) != 0) {
71 free(proc->comm);
72 proc->comm = strdup(comm);
73 }
74 }
75 return proc;
76}
77
78/*
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.
81 */
82void death_proc(struct lttngtop *ctx, int tid, char *comm,
83 unsigned long timestamp)
84{
85 struct processtop *tmp;
86 tmp = find_process_tid(ctx, tid, comm);
87 if (tmp && strcmp(tmp->comm, comm) == 0)
88 tmp->death = timestamp;
89}
90
91struct processtop* get_proc(struct lttngtop *ctx, int tid, char *comm,
92 unsigned long timestamp)
93{
94 struct processtop *tmp;
95 tmp = find_process_tid(ctx, tid, comm);
96 if (tmp && strcmp(tmp->comm, comm) == 0)
97 return tmp;
98 return add_proc(ctx, tid, comm, timestamp);
99}
100
101void add_thread(struct processtop *parent, struct processtop *thread)
102{
103 gint i;
104 struct processtop *tmp;
105
106 for (i = 0; i < parent->threads->len; i++) {
107 tmp = g_ptr_array_index(parent->threads, i);
108 if (tmp == thread)
109 return;
110 }
111 g_ptr_array_add(parent->threads, thread);
112}
113
114struct cputime* add_cpu(int cpu)
115{
116 struct cputime *newcpu;
117
559c9f86 118 newcpu = g_new0(struct cputime, 1);
1fc22eb4
JD
119 newcpu->id = cpu;
120 newcpu->current_task = NULL;
121 newcpu->perf = g_hash_table_new(g_direct_hash, g_direct_equal);
122
123 g_ptr_array_add(lttngtop.cpu_table, newcpu);
124
125 return newcpu;
126}
127struct cputime* get_cpu(int cpu)
128{
129 gint i;
130 struct cputime *tmp;
131
132 for (i = 0; i < lttngtop.cpu_table->len; i++) {
133 tmp = g_ptr_array_index(lttngtop.cpu_table, i);
134 if (tmp->id == cpu)
135 return tmp;
136 }
137
138 return add_cpu(cpu);
139}
140
141/*
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
144 */
145void rotate_cputime(unsigned long end)
146{
147 gint i;
148 struct cputime *tmp;
149 unsigned long elapsed;
150
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;
160 }
161 }
162 tmp->task_start = end;
163 }
164}
165
166void reset_perf_counter(gpointer key, gpointer value, gpointer user_data)
167{
168 ((struct perfcounter*) value)->count = 0;
169}
170
171void copy_perf_counter(gpointer key, gpointer value, gpointer new_table)
172{
173 struct perfcounter *newperf;
174
559c9f86 175 newperf = g_new0(struct perfcounter, 1);
1fc22eb4
JD
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);
180}
181
182void rotate_perfcounter() {
183 int i;
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);
188 }
189}
190
191void cleanup_processtop()
192{
193 gint i;
194 struct processtop *tmp;
195
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;
202 }
203}
204
205struct lttngtop* get_copy_lttngtop(unsigned long start, unsigned long end)
206{
207 gint i, j;
208 unsigned long time;
209 struct lttngtop *dst;
210 struct processtop *tmp, *tmp2, *new;
211 struct cputime *tmpcpu, *newcpu;
212 struct files *tmpfile, *newfile;
213
559c9f86 214 dst = g_new0(struct lttngtop, 1);
1fc22eb4
JD
215 dst->start = start;
216 dst->end = end;
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);
221
222 rotate_cputime(end);
223
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);
559c9f86 227 new = g_new0(struct processtop, 1);
1fc22eb4
JD
228
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);
235
559c9f86 236 new->iostream = g_new0(struct iostream, 1);
1fc22eb4
JD
237 memcpy(new->iostream, tmp->iostream, sizeof(struct iostream));
238 /* compute the stream speed */
239 if (end - start != 0)
240 {
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);
244 }
245
246 for (j = 0; j < tmp->process_files_table->len; j++) {
247 tmpfile = g_ptr_array_index(tmp->process_files_table, j);
559c9f86 248 newfile = g_new0(struct files, 1);
1fc22eb4
JD
249
250 memcpy(newfile, tmpfile, sizeof(struct files));
251
252 newfile->name = strdup(tmpfile->name);
253 newfile->ref = new;
254
255 g_ptr_array_add(new->process_files_table, newfile);
256 g_ptr_array_add(dst->files_table, newfile);
257
258 /*
259 * if the process died during the last period, we remove all
260 * files associated with if after the copy
261 */
262 if (tmp->death > 0 && tmp->death < end) {
263 g_ptr_array_remove(tmp->process_files_table, tmpfile);
559c9f86 264 g_free(tmpfile);
1fc22eb4
JD
265 }
266 }
267 g_ptr_array_add(dst->process_table, new);
268
269 /*
270 * if the process died during the last period, we remove it from
271 * the current process list after the copy
272 */
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);
276 free(tmp->comm);
277 g_ptr_array_free(tmp->process_files_table, TRUE);
278 g_hash_table_destroy(tmp->perf);
559c9f86 279 g_free(tmp);
1fc22eb4
JD
280 }
281 }
282 rotate_perfcounter();
283
284 for (i = 0; i < lttngtop.cpu_table->len; i++) {
285 tmpcpu = g_ptr_array_index(lttngtop.cpu_table, i);
559c9f86 286 newcpu = g_new0(struct cputime, 1);
1fc22eb4
JD
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);
290 /*
291 * note : we don't care about the current process pointer in the copy
292 * so the reference is invalid after the memcpy
293 */
294 g_ptr_array_add(dst->cpu_table, newcpu);
295 }
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);
305 }
306 }
307 }
308 }
309
310 // update_global_stats(dst);
311 cleanup_processtop();
312
313 return dst;
314}
315
This page took 0.05081 seconds and 4 git commands to generate.