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