function to extract cpu_id
[lttngtop.git] / src / common.c
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
23 uint64_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
38 struct 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
51 struct 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) {
60 newproc = g_new0(struct processtop, 1);
61 newproc->tid = tid;
62 newproc->birth = timestamp;
63 newproc->process_files_table = g_ptr_array_new();
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;
71 newproc->threads = g_ptr_array_new();
72 newproc->perf = g_hash_table_new(g_str_hash, g_str_equal);
73 g_ptr_array_add(ctx->process_table, newproc);
74 }
75 newproc->comm = strdup(comm);
76
77 return newproc;
78 }
79
80 struct 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 */
99 void 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
108 struct 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
118 void 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
131 struct cputime* add_cpu(int cpu)
132 {
133 struct cputime *newcpu;
134
135 newcpu = g_new0(struct cputime, 1);
136 newcpu->id = cpu;
137 newcpu->current_task = NULL;
138 newcpu->perf = g_hash_table_new(g_str_hash, g_str_equal);
139
140 g_ptr_array_add(lttngtop.cpu_table, newcpu);
141
142 return newcpu;
143 }
144 struct 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 */
162 void 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
183 void reset_perf_counter(gpointer key, gpointer value, gpointer user_data)
184 {
185 ((struct perfcounter*) value)->count = 0;
186 }
187
188 void copy_perf_counter(gpointer key, gpointer value, gpointer new_table)
189 {
190 struct perfcounter *newperf;
191
192 newperf = g_new0(struct perfcounter, 1);
193 newperf->count = ((struct perfcounter *) value)->count;
194 newperf->visible = ((struct perfcounter *) value)->visible;
195 newperf->sort = ((struct perfcounter *) value)->sort;
196 g_hash_table_insert((GHashTable *) new_table, strdup(key), newperf);
197 }
198
199 void 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
208 void cleanup_processtop()
209 {
210 gint i, j;
211 struct processtop *tmp;
212 struct files *tmpf; /* a temporary file */
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;
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 }
228 }
229 }
230
231 struct 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
240 dst = g_new0(struct lttngtop, 1);
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();
246 dst->perf_list = g_hash_table_new(g_str_hash, g_str_equal);
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);
253 new = g_new0(struct processtop, 1);
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();
259 new->perf = g_hash_table_new(g_str_hash, g_str_equal);
260 g_hash_table_foreach(tmp->perf, copy_perf_counter, new->perf);
261
262 /* compute the stream speed */
263 if (end - start != 0) {
264 time = (end - start) / NSEC_PER_SEC;
265 new->fileread = new->fileread/(time);
266 new->filewrite = new->filewrite/(time);
267 }
268
269 for (j = 0; j < tmp->process_files_table->len; j++) {
270 tmpfile = g_ptr_array_index(tmp->process_files_table, j);
271
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 }
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);
291 g_free(tmpfile);
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);
302 /* FIXME : TRUE does not mean clears the object in it */
303 g_ptr_array_free(tmp->threads, TRUE);
304 free(tmp->comm);
305 g_ptr_array_free(tmp->process_files_table, TRUE);
306 /* FIXME : clear elements */
307 g_hash_table_destroy(tmp->perf);
308 g_free(tmp);
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);
315 newcpu = g_new0(struct cputime, 1);
316 memcpy(newcpu, tmpcpu, sizeof(struct cputime));
317 newcpu->perf = g_hash_table_new(g_str_hash, g_str_equal);
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 }
325 /* FIXME : better algo */
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.054577 seconds and 5 git commands to generate.