Commit | Line | Data |
---|---|---|
715cf83c PBT |
1 | /* |
2 | * Copyright (C) 2011-2012 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 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. | |
16 | */ | |
17 | ||
18 | extern "C" { | |
19 | #include <babeltrace/ctf/events.h> | |
20 | } | |
21 | #include <stdlib.h> | |
22 | #include <linux/unistd.h> | |
23 | #include <string.h> | |
24 | #include "common.h" | |
25 | ||
26 | StateSystem *state_system; | |
27 | std::set<Quark> modified_quarks; | |
28 | unsigned long last_display_update = 0; | |
29 | unsigned long first_display_update = 0; | |
30 | sem_t goodtodisplay, goodtoupdate, timer, pause_sem, end_trace_sem, bootstrap; | |
31 | ||
32 | int get_cpu_id(const struct bt_ctf_event *event) | |
33 | { | |
34 | const struct definition *scope; | |
35 | int cpu_id; | |
36 | ||
37 | scope = bt_ctf_get_top_level_scope(event, BT_STREAM_PACKET_CONTEXT); | |
38 | cpu_id = bt_ctf_get_uint64(bt_ctf_get_field(event, scope, "cpu_id")); | |
39 | if (bt_ctf_field_get_error()) { | |
40 | fprintf(stderr, "[error] get cpu_id\n"); | |
41 | return -1; | |
42 | } | |
43 | ||
44 | return cpu_id; | |
45 | } | |
46 | ||
47 | int get_context_tid(const struct bt_ctf_event *event) | |
48 | { | |
49 | const struct definition *scope; | |
50 | int tid; | |
51 | ||
52 | scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT); | |
53 | tid = bt_ctf_get_int64(bt_ctf_get_field(event, scope, "_tid")); | |
54 | if (bt_ctf_field_get_error()) { | |
55 | fprintf(stderr, "Missing tid context info\n"); | |
56 | return -1; | |
57 | } | |
58 | ||
59 | return tid; | |
60 | } | |
61 | ||
62 | int get_context_pid(const struct bt_ctf_event *event) | |
63 | { | |
64 | const struct definition *scope; | |
65 | int pid; | |
66 | ||
67 | scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT); | |
68 | pid = bt_ctf_get_int64(bt_ctf_get_field(event, scope, "_pid")); | |
69 | if (bt_ctf_field_get_error()) { | |
70 | fprintf(stderr, "Missing pid context info\n"); | |
71 | return -1; | |
72 | } | |
73 | ||
74 | return pid; | |
75 | } | |
76 | ||
77 | int get_context_ppid(const struct bt_ctf_event *event) | |
78 | { | |
79 | const struct definition *scope; | |
80 | int ppid; | |
81 | ||
82 | scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT); | |
83 | ppid = bt_ctf_get_int64(bt_ctf_get_field(event, scope, "_ppid")); | |
84 | if (bt_ctf_field_get_error()) { | |
85 | fprintf(stderr, "Missing ppid context info\n"); | |
86 | return -1; | |
87 | } | |
88 | ||
89 | return ppid; | |
90 | } | |
91 | ||
92 | char *get_context_comm(const struct bt_ctf_event *event) | |
93 | { | |
94 | const struct definition *scope; | |
95 | char *comm; | |
96 | ||
97 | scope = bt_ctf_get_top_level_scope(event, BT_STREAM_EVENT_CONTEXT); | |
98 | comm = bt_ctf_get_char_array(bt_ctf_get_field(event, | |
99 | scope, "_procname")); | |
100 | if (bt_ctf_field_get_error()) { | |
101 | fprintf(stderr, "Missing comm context info\n"); | |
102 | return NULL; | |
103 | } | |
104 | ||
105 | return comm; | |
106 | } | |
107 | ||
108 | /* | |
109 | * To get the parent process, put the pid in the tid field | |
110 | * because the parent process gets pid = tid | |
111 | */ | |
112 | bool find_process_tid(int tid, Quark &ret_proc_quark) | |
113 | { | |
114 | std::string path_name = path_name_from_tid(tid); | |
115 | ||
116 | if (state_system->attributeExists(path_name)) { | |
117 | ret_proc_quark = state_system->getQuark(path_name); | |
118 | return true; | |
119 | } else { | |
120 | return false; | |
121 | } | |
122 | } | |
123 | ||
124 | Quark add_proc(int tid, std::string comm, unsigned long timestamp) | |
125 | { | |
126 | Quark proc_quark = state_system->getQuark(path_name_from_tid(tid)); | |
127 | ||
128 | modify_attribute(timestamp, &proc_quark, "comm", comm); | |
129 | modify_attribute(timestamp, &proc_quark, "tid", tid); | |
130 | modify_attribute(timestamp, &proc_quark, "birth", timestamp); | |
131 | modify_attribute(timestamp, &proc_quark, "totalfileread", 0); | |
132 | modify_attribute(timestamp, &proc_quark, "totalfilewrite", 0); | |
133 | modify_attribute(timestamp, &proc_quark, "fileread", 0); | |
134 | modify_attribute(timestamp, &proc_quark, "filewrite", 0); | |
135 | modify_attribute(timestamp, &proc_quark, "totalcpunsec", 0UL); | |
136 | modify_attribute(timestamp, &proc_quark, "threadstotalcpunsec", 0UL); | |
137 | modify_attribute(timestamp, &proc_quark, "selected", 0); | |
138 | ||
139 | increment_attribute(timestamp, NULL, "nbnewthreads"); | |
140 | increment_attribute(timestamp, NULL, "nbthreads"); | |
141 | ||
142 | add_in_sequence(timestamp, proc_quark, state_system->getQuark("proc")); | |
143 | ||
144 | return proc_quark; | |
145 | } | |
146 | ||
147 | void update_proc(unsigned long timestamp, Quark proc, int pid, int tid, | |
148 | int ppid, char *comm) | |
149 | { | |
150 | modify_attribute(timestamp, &proc, "pid", pid); | |
151 | modify_attribute(timestamp, &proc, "tid", tid); | |
152 | modify_attribute(timestamp, &proc, "ppid", ppid); | |
153 | modify_attribute(timestamp, &proc, "comm", comm); | |
154 | } | |
155 | ||
156 | /* | |
157 | * This function just sets the time of death of a process. | |
158 | * When we rotate the cputime we remove it from the process list. | |
159 | */ | |
160 | void death_proc(int tid, char *comm, unsigned long timestamp) | |
161 | { | |
162 | Quark proc_quark; | |
163 | std::string procname; | |
164 | bool proc_found; | |
165 | bool procname_found; | |
166 | ||
167 | proc_found = find_process_tid(tid, proc_quark); | |
168 | if (proc_found) { | |
169 | procname_found = get_current_attribute_value_string( | |
170 | &proc_quark, "comm", procname); | |
171 | if (procname_found && procname == comm) { | |
172 | modify_attribute(timestamp, &proc_quark, "death", | |
173 | timestamp); | |
174 | increment_attribute(timestamp, NULL, "nbdeadthreads"); | |
175 | decrement_attribute(timestamp, NULL, "nbthreads"); | |
176 | } | |
177 | } | |
178 | } | |
179 | ||
180 | Quark get_proc(int tid, char *comm, unsigned long timestamp) | |
181 | { | |
182 | Quark proc_quark; | |
183 | std::string proc_comm; | |
184 | bool exists = find_process_tid(tid, proc_quark); | |
185 | std::string comm_str(comm); | |
186 | ||
187 | if (!exists) | |
188 | proc_quark = add_proc(tid, comm_str, timestamp); | |
189 | ||
190 | /* If PID already exists under different name, | |
191 | we just rename the process */ | |
192 | /* FIXME : need to integrate with clone/fork/exit to be accurate */ | |
193 | else { | |
194 | get_current_attribute_value_string(&proc_quark, "comm", | |
195 | proc_comm); | |
196 | if (comm_str != proc_comm) | |
197 | modify_attribute(timestamp, &proc_quark, "comm", comm); | |
198 | } | |
199 | ||
200 | return proc_quark; | |
201 | } | |
202 | ||
203 | Quark get_proc_pid(int pid, int tid, unsigned long timestamp) | |
204 | { | |
205 | Quark proc; | |
206 | bool proc_found; | |
207 | int proc_pid; | |
208 | bool pid_found; | |
209 | ||
210 | proc_found = find_process_tid(tid, proc); | |
211 | if (proc_found) { | |
212 | pid_found = get_current_attribute_value_int(&proc, "pid", | |
213 | proc_pid); | |
214 | if (pid_found && proc_pid == pid) | |
215 | return proc; | |
216 | } | |
217 | return add_proc(tid, "Unknown", timestamp); | |
218 | } | |
219 | ||
220 | void add_thread(unsigned long timestamp, Quark parent, Quark thread) | |
221 | { | |
222 | std::string path; | |
223 | int tid; | |
224 | Quark thread_in_parent; | |
225 | ||
226 | get_current_attribute_value_int(&thread, "tid", tid); | |
227 | path = thread_path_name_from_tid(tid); | |
228 | ||
229 | if (!state_system->attributeExists(parent, path)) { | |
230 | thread_in_parent = state_system->getQuark(parent, path); | |
231 | modify_attribute(timestamp, &thread_in_parent, "", thread); | |
232 | add_in_sequence(timestamp, thread_in_parent, | |
233 | state_system->getQuark(parent, "threads")); | |
234 | } | |
235 | } | |
236 | ||
237 | Quark add_cpu(int cpu, unsigned long timestamp) | |
238 | { | |
239 | Quark cpu_quark = state_system->getQuark(path_name_from_cpuid(cpu)); | |
240 | Quark cpu_root = state_system->getQuark("cpu"); | |
241 | modify_attribute(timestamp, &cpu_quark, "id", cpu); | |
242 | ||
243 | add_in_sequence(timestamp, cpu_quark, cpu_root); | |
244 | ||
245 | return cpu_quark; | |
246 | } | |
247 | ||
248 | Quark get_cpu(int cpu, unsigned long timestamp) | |
249 | { | |
250 | std::string path = path_name_from_cpuid(cpu); | |
251 | if (state_system->attributeExists(path)) | |
252 | return state_system->getQuark(path); | |
253 | else | |
254 | return add_cpu(cpu, timestamp); | |
255 | } | |
256 | ||
257 | /* | |
258 | * At the end of a sampling period, we need to display the cpu time for each | |
259 | * process | |
260 | */ | |
261 | void rotate_cputime(unsigned long end) | |
262 | { | |
263 | Quark cpu; | |
264 | Quark current_task; | |
265 | unsigned long elapsed; | |
266 | unsigned long start; | |
267 | int tid; | |
268 | int pid; | |
269 | ||
270 | if (!get_current_attribute_value_quark(NULL, "cpu", cpu)) { | |
271 | // No CPU to process | |
272 | return; | |
273 | } | |
274 | ||
275 | do { | |
276 | get_current_attribute_value_ulong(&cpu, "task_start", start); | |
277 | elapsed = end - start; | |
278 | if (get_current_attribute_value_quark(&cpu, "current_task", | |
279 | current_task)) { | |
280 | increase_attribute( | |
281 | end, ¤t_task, "totalcpunsec", elapsed); | |
282 | increase_attribute( | |
283 | end, ¤t_task, "threadstotalcpunsec", | |
284 | elapsed); | |
285 | get_current_attribute_value_int( | |
286 | ¤t_task, "pid", pid); | |
287 | get_current_attribute_value_int( | |
288 | ¤t_task, "tid", tid); | |
289 | if (pid != tid && | |
290 | state_system->attributeExists( | |
291 | current_task, "threadparent")) { | |
292 | increase_attribute( | |
293 | end, ¤t_task, | |
294 | "threadparent/threadstotalcpunsec", | |
295 | elapsed); | |
296 | } | |
297 | } | |
298 | modify_attribute(end + 1, &cpu, "task_start", end); | |
299 | } while (get_current_attribute_value_quark(&cpu, "next", cpu)); | |
300 | } | |
301 | ||
302 | void update_state_on_refresh(unsigned long start, unsigned long end) | |
303 | { | |
304 | Quark proc; | |
305 | ||
306 | rotate_cputime(end); | |
307 | ||
308 | if (get_current_attribute_value_quark(NULL, "proc", proc)) { | |
309 | do { | |
310 | update_proc_on_refresh(proc, start, end); | |
311 | } while (get_current_attribute_value_quark( | |
312 | &proc, "next", proc)); | |
313 | } | |
314 | } | |
315 | ||
316 | enum bt_cb_ret handle_statedump_process_state( | |
317 | struct bt_ctf_event *call_data, void *private_data) | |
318 | { | |
319 | const struct definition *scope; | |
320 | unsigned long timestamp; | |
321 | int pid, tid; | |
322 | /* FIXME */ | |
323 | /* char *procname; */ | |
324 | Quark proc_quark; | |
325 | ||
326 | timestamp = bt_ctf_get_timestamp(call_data); | |
327 | if (timestamp == -1ULL) | |
328 | goto error; | |
329 | ||
330 | scope = bt_ctf_get_top_level_scope(call_data, | |
331 | BT_EVENT_FIELDS); | |
332 | pid = bt_ctf_get_int64(bt_ctf_get_field(call_data, | |
333 | scope, "_pid")); | |
334 | if (bt_ctf_field_get_error()) { | |
335 | fprintf(stderr, "Missing pid context info\n"); | |
336 | goto error; | |
337 | } | |
338 | ||
339 | scope = bt_ctf_get_top_level_scope(call_data, | |
340 | BT_EVENT_FIELDS); | |
341 | tid = bt_ctf_get_int64(bt_ctf_get_field(call_data, | |
342 | scope, "_tid")); | |
343 | if (bt_ctf_field_get_error()) { | |
344 | fprintf(stderr, "Missing tid context info\n"); | |
345 | goto error; | |
346 | } | |
347 | ||
348 | /* | |
349 | * FIXME | |
350 | * I first tried with bt_ctf_get_string but doesn`t work at all | |
351 | * It couldn`t find the field _name because it is an integer in | |
352 | * the metadata and not a string like _filename for the | |
353 | * statedump_file_descriptor | |
354 | */ | |
355 | /* | |
356 | * FIXME | |
357 | * We use "Dumped" instead of procname because procname sometimes | |
358 | * causes memory corruption. All FIXME's in this function are | |
359 | * related to this. | |
360 | */ | |
361 | /* procname = bt_ctf_get_char_array(bt_ctf_get_field(call_data, | |
362 | scope, "_name")); */ | |
363 | if (bt_ctf_field_get_error()) { | |
364 | fprintf(stderr, "Missing process name context info\n"); | |
365 | goto error; | |
366 | } | |
367 | ||
368 | proc_quark = get_proc(tid, (char *)"Dumped", timestamp); | |
369 | modify_attribute(timestamp, &proc_quark, "pid", pid); | |
370 | ||
371 | /* FIXME */ | |
372 | /* free(procname); */ | |
373 | ||
374 | return BT_CB_OK; | |
375 | ||
376 | error: | |
377 | return BT_CB_ERROR_STOP; | |
378 | } | |
379 | ||
380 | std::string path_name_from_cpuid(int cpuid) | |
381 | { | |
382 | std::stringstream ss; | |
383 | ss << "cpus/" << cpuid; | |
384 | return ss.str(); | |
385 | } | |
386 | ||
387 | std::string thread_path_name_from_tid(int tid) | |
388 | { | |
389 | std::stringstream ss; | |
390 | ss << "threads/" << tid; | |
391 | return ss.str(); | |
392 | } | |
393 | ||
394 | std::string path_name_from_tid(int tid) | |
395 | { | |
396 | std::stringstream ss; | |
397 | ss << "processes/" << tid; | |
398 | return ss.str(); | |
399 | } | |
400 | ||
401 | std::string path_name_from_fd(int fd) | |
402 | { | |
403 | std::stringstream ss; | |
404 | ss << "files/" << fd; | |
405 | return ss.str(); | |
406 | } | |
407 | ||
408 | void update_file_on_refresh(Quark proc, Quark file, unsigned long end) | |
409 | { | |
410 | int flag; | |
411 | int fd; | |
412 | std::string path; | |
413 | Quark file_pointer; | |
414 | ||
415 | /* File closed */ | |
416 | get_current_attribute_value_int(&file, "file/flag", flag); | |
417 | if (flag == __NR_close) { | |
418 | get_current_attribute_value_int(&file, "file/fd", fd); | |
419 | if (fd != -1) { | |
420 | path = path_name_from_fd(fd); | |
421 | file_pointer = state_system->getQuark(proc, path); | |
422 | state_system->removeAttribute(end + 1, file_pointer); | |
423 | state_system->modifyAttribute(end + 1, | |
424 | state_system->getQuark( | |
425 | file, "file/fd"), | |
426 | -1); | |
427 | } | |
428 | } | |
429 | } | |
430 | ||
431 | void update_proc_on_refresh(Quark proc, unsigned long start, unsigned long end) | |
432 | { | |
433 | ||
434 | int fileread = 0; | |
435 | int filewrite = 0; | |
436 | unsigned long time; | |
437 | unsigned long death; | |
438 | Quark parent; | |
439 | Quark file; | |
440 | int tid; | |
441 | std::string path; | |
442 | ||
443 | /* Process died */ | |
444 | if (get_current_attribute_value_ulong(&proc, "death", death) && | |
445 | death > 0 && death <= end) { | |
446 | /* Remove thread from threadparent's threads */ | |
447 | if (get_current_attribute_value_quark( | |
448 | &proc, "threadparent", parent)) { | |
449 | get_current_attribute_value_int(&proc, "tid", tid); | |
450 | path = thread_path_name_from_tid(tid); | |
451 | remove_from_sequence( | |
452 | end + 1, | |
453 | state_system->getQuark(parent, path), | |
454 | state_system->getQuark(parent, "threads")); | |
455 | } | |
456 | ||
457 | remove_from_sequence(end + 1, proc, | |
458 | state_system->getQuark("proc")); | |
459 | return; | |
460 | } | |
461 | ||
462 | /* Files */ | |
463 | if (get_current_attribute_value_quark( | |
464 | &proc, "files_history/current", file)) { | |
465 | do { | |
466 | update_file_on_refresh(proc, file, end); | |
467 | } while (get_current_attribute_value_quark( | |
468 | &file, "next", file)); | |
469 | } | |
470 | ||
471 | /* compute the stream speed */ | |
472 | if (end - start != 0) { | |
473 | time = end - start; | |
474 | get_current_attribute_value_int(&proc, "fileread", fileread); | |
475 | get_current_attribute_value_int(&proc, "filewrite", filewrite); | |
476 | modify_attribute(end, &proc, "fileread", (int)(fileread / time)); | |
477 | modify_attribute(end, &proc, "filewrite", (int)(filewrite / time)); | |
478 | } | |
479 | } | |
480 | ||
481 | void modify_attribute(unsigned long timestamp, const Quark *starting_node, | |
482 | std::string attribute, int value) | |
483 | { | |
484 | Quark q; | |
485 | if (starting_node) | |
486 | q = state_system->getQuark(*starting_node, attribute); | |
487 | else | |
488 | q = state_system->getQuark(attribute); | |
489 | state_system->updateCurrentState(q, value); | |
490 | ||
491 | modified_quarks.insert(q); | |
492 | } | |
493 | ||
494 | void modify_attribute(unsigned long timestamp, const Quark *starting_node, | |
495 | std::string attribute, Quark value) | |
496 | { | |
497 | Quark q; | |
498 | if (starting_node) | |
499 | q = state_system->getQuark(*starting_node, attribute); | |
500 | else | |
501 | q = state_system->getQuark(attribute); | |
502 | state_system->updateCurrentState(q, StateValue::SharedPtr( | |
503 | new QuarkStateValue(value))); | |
504 | ||
505 | modified_quarks.insert(q); | |
506 | } | |
507 | ||
508 | void modify_attribute(unsigned long timestamp, const Quark *starting_node, | |
509 | std::string attribute, char *value) | |
510 | { | |
511 | Quark q; | |
512 | if (starting_node) | |
513 | q = state_system->getQuark(*starting_node, attribute); | |
514 | else | |
515 | q = state_system->getQuark(attribute); | |
516 | state_system->updateCurrentState(q, std::string(value)); | |
517 | ||
518 | modified_quarks.insert(q); | |
519 | } | |
520 | ||
521 | void modify_attribute(unsigned long timestamp, const Quark *starting_node, | |
522 | std::string attribute, std::string value) | |
523 | { | |
524 | Quark q; | |
525 | if (starting_node) | |
526 | q = state_system->getQuark(*starting_node, attribute); | |
527 | else | |
528 | q = state_system->getQuark(attribute); | |
529 | state_system->updateCurrentState(q, value); | |
530 | ||
531 | modified_quarks.insert(q); | |
532 | } | |
533 | ||
534 | void modify_attribute(unsigned long timestamp, const Quark *starting_node, | |
535 | std::string attribute, unsigned long value) | |
536 | { | |
537 | // Libstate works with 32-bit ints, we split the 64-bit ulong | |
538 | // into 2 32-bit ints | |
539 | unsigned int h = value >> 32; | |
540 | unsigned int l = value & 0xffffffff; | |
541 | Quark ql, qh; | |
542 | ||
543 | if (starting_node) { | |
544 | ql = state_system->getQuark(*starting_node, attribute + "/l"); | |
545 | qh = state_system->getQuark(*starting_node, attribute + "/h"); | |
546 | } | |
547 | else { | |
548 | ql = state_system->getQuark(attribute + "/l"); | |
549 | qh = state_system->getQuark(attribute + "/h"); | |
550 | } | |
551 | state_system->updateCurrentState(ql, l); | |
552 | state_system->updateCurrentState(qh, h); | |
553 | ||
554 | modified_quarks.insert(ql); | |
555 | modified_quarks.insert(qh); | |
556 | } | |
557 | ||
558 | void nullify_attribute(unsigned long timestamp, const Quark *starting_node, | |
559 | std::string attribute) | |
560 | { | |
561 | Quark q; | |
562 | q = state_system->getQuark(*starting_node, attribute); | |
563 | state_system->updateCurrentState(q, StateValue::getNullValue()); | |
564 | ||
565 | modified_quarks.insert(q); | |
566 | } | |
567 | ||
568 | void increment_attribute(unsigned long timestamp, const Quark *starting_node, | |
569 | std::string attribute) | |
570 | { | |
571 | increase_attribute(timestamp, starting_node, attribute, 1); | |
572 | } | |
573 | ||
574 | void increase_attribute(unsigned long timestamp, const Quark *starting_node, | |
575 | std::string attribute, int amount) | |
576 | { | |
577 | int starting_value = 0; | |
578 | get_current_attribute_value_int(starting_node, attribute, | |
579 | starting_value); | |
580 | modify_attribute(timestamp, starting_node, attribute, | |
581 | starting_value + amount); | |
582 | } | |
583 | ||
584 | void increase_attribute(unsigned long timestamp, const Quark *starting_node, | |
585 | std::string attribute, unsigned long amount) | |
586 | { | |
587 | unsigned long starting_value = 0; | |
588 | get_current_attribute_value_ulong(starting_node, attribute, | |
589 | starting_value); | |
590 | modify_attribute(timestamp, starting_node, attribute, | |
591 | starting_value + amount); | |
592 | } | |
593 | ||
594 | void decrement_attribute(unsigned long timestamp, const Quark *starting_node, | |
595 | std::string attribute) | |
596 | { | |
597 | decrease_attribute(timestamp, starting_node, attribute, 1); | |
598 | } | |
599 | ||
600 | void decrease_attribute(unsigned long timestamp, const Quark *starting_node, | |
601 | std::string attribute, int amount) | |
602 | { | |
603 | int starting_value = 0; | |
604 | get_current_attribute_value_int(starting_node, attribute, | |
605 | starting_value); | |
606 | modify_attribute(timestamp, starting_node, attribute, | |
607 | starting_value - amount); | |
608 | } | |
609 | ||
610 | void decrease_attribute(unsigned long timestamp, const Quark *starting_node, | |
611 | std::string attribute, unsigned long amount) | |
612 | { | |
613 | unsigned long starting_value = 0; | |
614 | get_current_attribute_value_ulong(starting_node, attribute, | |
615 | starting_value); | |
616 | modify_attribute(timestamp, starting_node, attribute, | |
617 | starting_value - amount); | |
618 | } | |
619 | ||
620 | bool get_current_attribute_value_int(const Quark *starting_node, | |
621 | std::string attribute, int &value) | |
622 | { | |
623 | IntegerStateValue::SharedPtr value_ptr; | |
624 | Quark q; | |
625 | ||
626 | if (starting_node == NULL) | |
627 | q = state_system->getQuark(attribute); | |
628 | else | |
629 | q = state_system->getQuark(*starting_node, attribute); | |
630 | value_ptr = std::tr1::dynamic_pointer_cast<IntegerStateValue>( | |
631 | state_system->getCurrentStateValue(q)); | |
632 | ||
633 | if (value_ptr) { | |
634 | value = value_ptr->getValue(); | |
635 | return true; | |
636 | } | |
637 | return false; | |
638 | } | |
639 | ||
640 | bool get_current_attribute_value_ulong(const Quark *starting_node, | |
641 | std::string attribute, | |
642 | unsigned long &value) | |
643 | { | |
644 | // Libstate works with 32-bit ints, we split the 64-bit ulong | |
645 | // into 2 32-bit ints | |
646 | IntegerStateValue::SharedPtr value_ptr_l, value_ptr_h; | |
647 | Quark ql, qh; | |
648 | unsigned int l, h; | |
649 | ||
650 | if (starting_node == NULL) { | |
651 | ql = state_system->getQuark(attribute + "/l"); | |
652 | qh = state_system->getQuark(attribute + "/h"); | |
653 | } | |
654 | else { | |
655 | ql = state_system->getQuark(*starting_node, attribute + "/l"); | |
656 | qh = state_system->getQuark(*starting_node, attribute + "/h"); | |
657 | } | |
658 | value_ptr_l = std::tr1::dynamic_pointer_cast<IntegerStateValue>( | |
659 | state_system->getCurrentStateValue(ql)); | |
660 | value_ptr_h = std::tr1::dynamic_pointer_cast<IntegerStateValue>( | |
661 | state_system->getCurrentStateValue(qh)); | |
662 | ||
663 | if (value_ptr_l && value_ptr_h) { | |
664 | l = value_ptr_l->getValue(); | |
665 | h = value_ptr_h->getValue(); | |
666 | value = (unsigned long)h << 32 | l; | |
667 | return true; | |
668 | } | |
669 | return false; | |
670 | } | |
671 | ||
672 | bool get_current_attribute_value_quark(const Quark *starting_node, | |
673 | std::string attribute, Quark &value) | |
674 | { | |
675 | QuarkStateValue::SharedPtr value_ptr; | |
676 | IntegerStateValue::SharedPtr value_ptr_int; | |
677 | Quark q; | |
678 | ||
679 | if (starting_node == NULL) | |
680 | q = state_system->getQuark(attribute); | |
681 | else | |
682 | q = state_system->getQuark(*starting_node, attribute); | |
683 | value_ptr = std::tr1::dynamic_pointer_cast<QuarkStateValue>( | |
684 | state_system->getCurrentStateValue(q)); | |
685 | ||
686 | if (value_ptr) { | |
687 | value = value_ptr->getValue(); | |
688 | return true; | |
689 | } else { | |
690 | /* Quark attribute support is not fully integrated in libstate | |
691 | and librbrntrvll so quarks may get demoted to ints */ | |
692 | value_ptr_int = std::tr1::dynamic_pointer_cast<IntegerStateValue>( | |
693 | state_system->getCurrentStateValue(q)); | |
694 | if (value_ptr_int) { | |
695 | value = (Quark)value_ptr_int->getValue(); | |
696 | return true; | |
697 | } | |
698 | } | |
699 | return false; | |
700 | } | |
701 | ||
702 | bool get_current_attribute_value_string(const Quark *starting_node, | |
703 | std::string attribute, std::string &value) | |
704 | { | |
705 | StringStateValue::SharedPtr value_ptr; | |
706 | Quark q; | |
707 | ||
708 | if (starting_node == NULL) | |
709 | q = state_system->getQuark(attribute); | |
710 | else | |
711 | q = state_system->getQuark(*starting_node, attribute); | |
712 | value_ptr = std::tr1::dynamic_pointer_cast<StringStateValue>( | |
713 | state_system->getCurrentStateValue(q)); | |
714 | ||
715 | if (value_ptr) { | |
716 | value = value_ptr->getValue(); | |
717 | return true; | |
718 | } | |
719 | return false; | |
720 | } | |
721 | ||
722 | bool get_attribute_value_at_int(unsigned long timestamp, | |
723 | const Quark *starting_node, | |
724 | std::string attribute, | |
725 | int &value) | |
726 | { | |
727 | StateInterval interval; | |
728 | Quark q; | |
729 | IntegerStateValue::SharedPtr value_ptr; | |
730 | ||
731 | if (starting_node == NULL) | |
732 | q = state_system->getQuark(attribute); | |
733 | else | |
734 | q = state_system->getQuark(*starting_node, attribute); | |
735 | interval = state_system->getStateOfAt(timestamp, q); | |
736 | value_ptr = std::tr1::dynamic_pointer_cast<IntegerStateValue>( | |
737 | interval.value); | |
738 | ||
739 | if (value_ptr) { | |
740 | value = value_ptr->getValue(); | |
741 | return true; | |
742 | } | |
743 | return false; | |
744 | } | |
745 | ||
746 | bool get_attribute_value_at_ulong(unsigned long timestamp, | |
747 | const Quark *starting_node, | |
748 | std::string attribute, | |
749 | unsigned long &value) | |
750 | { | |
751 | // Libstate works with 32-bit ints, we split the 64-bit ulong | |
752 | // into 2 32-bit ints | |
753 | StateInterval interval_l, interval_h; | |
754 | Quark ql, qh; | |
755 | IntegerStateValue::SharedPtr value_ptr_l, value_ptr_h; | |
756 | unsigned int l, h; | |
757 | ||
758 | if (starting_node == NULL) { | |
759 | ql = state_system->getQuark(attribute + "/l"); | |
760 | qh = state_system->getQuark(attribute + "/h"); | |
761 | } | |
762 | else { | |
763 | ql = state_system->getQuark(*starting_node, attribute + "/l"); | |
764 | qh = state_system->getQuark(*starting_node, attribute + "/h"); | |
765 | } | |
766 | interval_l = state_system->getStateOfAt(timestamp, ql); | |
767 | interval_h = state_system->getStateOfAt(timestamp, qh); | |
768 | value_ptr_l = std::tr1::dynamic_pointer_cast<IntegerStateValue>( | |
769 | interval_l.value); | |
770 | value_ptr_h = std::tr1::dynamic_pointer_cast<IntegerStateValue>( | |
771 | interval_h.value); | |
772 | ||
773 | if (value_ptr_l && value_ptr_h) { | |
774 | l = value_ptr_l->getValue(); | |
775 | h = value_ptr_h->getValue(); | |
776 | value = (unsigned long)h << 32 | l; | |
777 | return true; | |
778 | } | |
779 | return false; | |
780 | } | |
781 | ||
782 | bool get_attribute_value_at_quark(unsigned long timestamp, | |
783 | const Quark *starting_node, | |
784 | std::string attribute, | |
785 | Quark &value) | |
786 | { | |
787 | StateInterval interval; | |
788 | Quark q; | |
789 | QuarkStateValue::SharedPtr value_ptr; | |
790 | IntegerStateValue::SharedPtr value_ptr_int; | |
791 | ||
792 | if (starting_node == NULL) | |
793 | q = state_system->getQuark(attribute); | |
794 | else | |
795 | q = state_system->getQuark(*starting_node, attribute); | |
796 | interval = state_system->getStateOfAt(timestamp, q); | |
797 | value_ptr = std::tr1::dynamic_pointer_cast<QuarkStateValue>( | |
798 | interval.value); | |
799 | ||
800 | if (value_ptr) { | |
801 | value = value_ptr->getValue(); | |
802 | return true; | |
803 | } else { | |
804 | /* Quark attribute support is not fully integrated in libstate | |
805 | and librbrntrvll so quarks may get demoted to ints */ | |
806 | value_ptr_int = std::tr1::dynamic_pointer_cast<IntegerStateValue>( | |
807 | interval.value); | |
808 | if (value_ptr_int) { | |
809 | value = (Quark)value_ptr_int->getValue(); | |
810 | return true; | |
811 | } | |
812 | } | |
813 | return false; | |
814 | } | |
815 | ||
816 | bool get_attribute_value_at_string(unsigned long timestamp, | |
817 | const Quark *starting_node, | |
818 | std::string attribute, | |
819 | std::string &value) | |
820 | { | |
821 | StateInterval interval; | |
822 | Quark q; | |
823 | StringStateValue::SharedPtr value_ptr; | |
824 | ||
825 | if (starting_node == NULL) | |
826 | q = state_system->getQuark(attribute); | |
827 | else | |
828 | q = state_system->getQuark(*starting_node, attribute); | |
829 | interval = state_system->getStateOfAt(timestamp, q); | |
830 | value_ptr = std::tr1::dynamic_pointer_cast<StringStateValue>( | |
831 | interval.value); | |
832 | ||
833 | if (value_ptr) { | |
834 | value = value_ptr->getValue(); | |
835 | return true; | |
836 | } | |
837 | return false; | |
838 | } | |
839 | ||
840 | void add_in_sequence(unsigned long timestamp, Quark item, Quark beg) | |
841 | { | |
842 | Quark old_newest; | |
843 | if (get_current_attribute_value_quark(&beg, "", old_newest)) { | |
844 | modify_attribute(timestamp, &item, "next", old_newest); | |
845 | modify_attribute(timestamp, &old_newest, "prev", item); | |
846 | } | |
847 | modify_attribute(timestamp, &beg, "", item); | |
848 | ||
849 | } | |
850 | ||
851 | void remove_from_sequence(unsigned long timestamp, Quark item, Quark beg) | |
852 | { | |
853 | Quark prev; | |
854 | Quark next; | |
855 | bool hasPrev; | |
856 | bool hasNext; | |
857 | ||
858 | hasPrev = get_current_attribute_value_quark(&item, | |
859 | "prev", prev); | |
860 | hasNext = get_current_attribute_value_quark(&item, | |
861 | "next", next); | |
862 | if (hasPrev && hasNext) { | |
863 | state_system->modifyAttribute(timestamp, | |
864 | state_system->getQuark(next, "prev"), | |
865 | StateValue::SharedPtr( | |
866 | new QuarkStateValue(prev))); | |
867 | state_system->modifyAttribute(timestamp, | |
868 | state_system->getQuark(prev, "next"), | |
869 | StateValue::SharedPtr( | |
870 | new QuarkStateValue(next))); | |
871 | } else if (hasPrev) { | |
872 | state_system->modifyAttribute(timestamp, | |
873 | state_system->getQuark(prev, "next"), | |
874 | StateValue::getNullValue()); | |
875 | } else if (hasNext) { | |
876 | state_system->modifyAttribute(timestamp, | |
877 | state_system->getQuark(next, "prev"), | |
878 | StateValue::getNullValue()); | |
879 | state_system->modifyAttribute(timestamp, beg, | |
880 | StateValue::SharedPtr( | |
881 | new QuarkStateValue(next))); | |
882 | } else { | |
883 | state_system->modifyAttribute(timestamp, beg, | |
884 | StateValue::getNullValue()); | |
885 | } | |
886 | ||
887 | state_system->removeAttribute(timestamp, item); | |
888 | } | |
889 | ||
890 | int get_sequence_length(unsigned long timestamp, Quark beg) | |
891 | { | |
892 | int length = 0; | |
893 | Quark it; | |
894 | ||
895 | if (get_attribute_value_at_quark(timestamp, &beg, "", it)) { | |
896 | do { | |
897 | length++; | |
898 | } while (get_attribute_value_at_quark( | |
899 | timestamp, &it, "next", it)); | |
900 | } | |
901 | ||
902 | return length; | |
903 | } | |
904 | ||
905 | bool get_interval_value_int(unsigned long start, | |
906 | unsigned long end, | |
907 | const Quark *starting_node, | |
908 | std::string attribute, | |
909 | int &value) | |
910 | { | |
911 | int start_value, end_value; | |
912 | ||
913 | if (get_attribute_value_at_int( | |
914 | start, starting_node, attribute, start_value) && | |
915 | get_attribute_value_at_int( | |
916 | end, starting_node, attribute, end_value)) { | |
917 | value = end_value - start_value; | |
918 | return true; | |
919 | } | |
920 | return false; | |
921 | } | |
922 | ||
923 | bool get_interval_value_ulong(unsigned long start, | |
924 | unsigned long end, | |
925 | const Quark *starting_node, | |
926 | std::string attribute, | |
927 | unsigned long &value) | |
928 | { | |
929 | unsigned long start_value, end_value; | |
930 | ||
931 | if (get_attribute_value_at_ulong( | |
932 | start, starting_node, attribute, start_value) && | |
933 | get_attribute_value_at_ulong( | |
934 | end, starting_node, attribute, end_value)) { | |
935 | value = end_value - start_value; | |
936 | return true; | |
937 | } | |
938 | return false; | |
939 | } | |
940 | ||
941 | int sequence_to_array(unsigned long timestamp, Quark beg, Quark *arr, | |
942 | int len) | |
943 | { | |
944 | int ret = 0; | |
945 | Quark it; | |
946 | ||
947 | if (arr == NULL || len < 1) | |
948 | return 0; | |
949 | ||
950 | if (get_attribute_value_at_quark(timestamp, &beg, "", it)) { | |
951 | do { | |
952 | arr[ret] = it; | |
953 | ret++; | |
954 | } while (get_attribute_value_at_quark( | |
955 | timestamp, &it, "next", it) && ret < len); | |
956 | } | |
957 | ||
958 | return ret; | |
959 | } | |
960 | ||
961 | int get_global_perf_list(unsigned long timestamp, Quark *arr, int len) | |
962 | { | |
963 | std::map<std::string, int> perfs; | |
964 | std::string key; | |
965 | int val; | |
966 | int ret; | |
967 | Quark proc; | |
968 | Quark perf; | |
969 | std::map<std::string, int>::const_iterator iter; | |
970 | ||
971 | if (arr == NULL || len < 1) | |
972 | return 0; | |
973 | ||
974 | if (get_attribute_value_at_quark(timestamp, NULL, "proc", proc)) { | |
975 | do { | |
976 | if (get_attribute_value_at_quark(timestamp, &proc, | |
977 | "perf", perf)) { | |
978 | do { | |
979 | get_attribute_value_at_string(timestamp, | |
980 | &perf, | |
981 | "key", | |
982 | key); | |
983 | get_attribute_value_at_int(timestamp, | |
984 | &perf, | |
985 | "count", | |
986 | val); | |
987 | if (perfs.find(key) != perfs.end()) | |
988 | perfs[key] += val; | |
989 | else | |
990 | perfs[key] = val; | |
991 | } while (get_attribute_value_at_quark(timestamp, | |
992 | &perf, | |
993 | "next", | |
994 | perf)); | |
995 | } | |
996 | } while (get_attribute_value_at_quark(timestamp, &proc, "next", | |
997 | proc)); | |
998 | } | |
999 | ||
1000 | for (iter = perfs.begin(), ret = 0; iter != perfs.end() && ret < len; | |
1001 | iter++, ret++) { | |
1002 | perf = state_system->getQuark("perf/" + iter->first); | |
1003 | modify_attribute(timestamp, &perf, "count", iter->second); | |
1004 | arr[ret] = perf; | |
1005 | } | |
1006 | ||
1007 | return ret; | |
1008 | } | |
1009 | ||
1010 | int get_global_perf_list_size(unsigned long timestamp) | |
1011 | { | |
1012 | std::set<std::string> perfs; | |
1013 | std::string key; | |
1014 | int len = 0; | |
1015 | Quark proc; | |
1016 | Quark perf; | |
1017 | ||
1018 | if (get_attribute_value_at_quark(timestamp, NULL, "proc", proc)) { | |
1019 | do { | |
1020 | if (get_attribute_value_at_quark(timestamp, &proc, | |
1021 | "perf", perf)) { | |
1022 | do { | |
1023 | get_attribute_value_at_string(timestamp, | |
1024 | &perf, | |
1025 | "key", | |
1026 | key); | |
1027 | if (perfs.find(key) == perfs.end()) { | |
1028 | perfs.insert(key); | |
1029 | len++; | |
1030 | } | |
1031 | } while (get_attribute_value_at_quark(timestamp, | |
1032 | &perf, | |
1033 | "next", | |
1034 | perf)); | |
1035 | } | |
1036 | } while (get_attribute_value_at_quark(timestamp, &proc, "next", | |
1037 | proc)); | |
1038 | } | |
1039 | ||
1040 | return len; | |
1041 | } | |
1042 | ||
1043 | int get_number_of_opened_files(unsigned long timestamp, Quark proc) | |
1044 | { | |
1045 | int len = 0; | |
1046 | Quark fh; | |
1047 | int fd; | |
1048 | ||
1049 | if (get_attribute_value_at_quark(timestamp, &proc, | |
1050 | "files_history/current", fh)) { | |
1051 | do { | |
1052 | get_attribute_value_at_int(timestamp, &fh, "file/fd", | |
1053 | fd); | |
1054 | if (fd != -1) | |
1055 | len++; | |
1056 | } while (get_attribute_value_at_quark(timestamp, &fh, "next", | |
1057 | fh)); | |
1058 | } | |
1059 | ||
1060 | return len; | |
1061 | } | |
1062 | ||
1063 | int get_opened_files(unsigned long timestamp, Quark proc, Quark *arr, int len) | |
1064 | { | |
1065 | int ret = 0; | |
1066 | Quark file, fh; | |
1067 | int fd; | |
1068 | ||
1069 | if (arr == NULL || len < 1) | |
1070 | return 0; | |
1071 | ||
1072 | if (get_attribute_value_at_quark(timestamp, &proc, | |
1073 | "files_history/current", fh)) { | |
1074 | do { | |
1075 | file = state_system->getQuark(fh, "file"); | |
1076 | get_attribute_value_at_int(timestamp, &file, "fd", | |
1077 | fd); | |
1078 | if (fd != -1) { | |
1079 | arr[ret] = file; | |
1080 | ret++; | |
1081 | } | |
1082 | if (ret == len) | |
1083 | break; | |
1084 | } while (get_attribute_value_at_quark(timestamp, &fh, "next", | |
1085 | fh)); | |
1086 | } | |
1087 | ||
1088 | return ret; | |
1089 | } |