1 /**
2 * @file oprof_start.cpp
3 * The GUI start main class
4 *
5 * @remark Copyright 2002 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author Philippe Elie
9 * @author John Levon
10 */
11
12 #include <sys/stat.h>
13 #include <unistd.h>
14
15 #include <ctime>
16 #include <cstdio>
17 #include <cmath>
18 #include <sstream>
19 #include <iostream>
20 #include <fstream>
21 #include <algorithm>
22
23 #include <qlineedit.h>
24 #include <qlistview.h>
25 #include <qcombobox.h>
26 #include <qlistbox.h>
27 #include <qfiledialog.h>
28 #include <qbuttongroup.h>
29 #include <qcheckbox.h>
30 #include <qtabwidget.h>
31 #include <qmessagebox.h>
32 #include <qvalidator.h>
33 #include <qlabel.h>
34 #include <qpushbutton.h>
35 #include <qheader.h>
36
37 #include "config.h"
38 #include "oprof_start.h"
39 #include "op_config.h"
40 #include "op_config_24.h"
41 #include "string_manip.h"
42 #include "op_cpufreq.h"
43 #include "op_alloc_counter.h"
44 #include "oprof_start_util.h"
45 #include "file_manip.h"
46
47 #include "op_hw_config.h"
48
49 using namespace std;
50
51 static char const * green_xpm[] = {
52 "16 16 2 1",
53 " c None",
54 ". c #00FF00",
55 " ....... ",
56 " ........... ",
57 " ............. ",
58 " ............. ",
59 "............... ",
60 "............... ",
61 "............... ",
62 "............... ",
63 "............... ",
64 "............... ",
65 "............... ",
66 " ............. ",
67 " ............. ",
68 " ........... ",
69 " ....... ",
70 " " };
71
72 static char const * red_xpm[] = {
73 "16 16 2 1",
74 " c None",
75 ". c #FF0000",
76 " ....... ",
77 " ........... ",
78 " ............. ",
79 " ............. ",
80 "............... ",
81 "............... ",
82 "............... ",
83 "............... ",
84 "............... ",
85 "............... ",
86 "............... ",
87 " ............. ",
88 " ............. ",
89 " ........... ",
90 " ....... ",
91 " " };
92
93 static QPixmap * green_pixmap;
94 static QPixmap * red_pixmap;
95
96
op_event_descr()97 op_event_descr::op_event_descr()
98 :
99 counter_mask(0),
100 val(0),
101 unit(0),
102 min_count(0)
103 {
104 }
105
106
oprof_start()107 oprof_start::oprof_start()
108 :
109 oprof_start_base(0, 0, false, 0),
110 event_count_validator(new QIntValidator(event_count_edit)),
111 current_event(0),
112 cpu_speed(op_cpu_frequency()),
113 total_nr_interrupts(0)
114 {
115 green_pixmap = new QPixmap(green_xpm);
116 red_pixmap = new QPixmap(red_xpm);
117 vector<string> args;
118 args.push_back("--init");
119
120 if (do_exec_command(OP_BINDIR "/opcontrol", args))
121 exit(EXIT_FAILURE);
122
123 cpu_type = op_get_cpu_type();
124 op_nr_counters = op_get_nr_counters(cpu_type);
125
126 if (cpu_type == CPU_TIMER_INT) {
127 setup_config_tab->removePage(counter_setup_page);
128 } else {
129 fill_events();
130 }
131
132 op_interface interface = op_get_interface();
133 if (interface == OP_INTERFACE_NO_GOOD) {
134 QMessageBox::warning(this, 0, "Couldn't determine kernel"
135 " interface version");
136 exit(EXIT_FAILURE);
137 }
138 bool is_26 = interface == OP_INTERFACE_26;
139
140 if (is_26) {
141 note_table_size_edit->hide();
142 note_table_size_label->hide();
143 if (!op_file_readable("/dev/oprofile/backtrace_depth")) {
144 callgraph_depth_label->hide();
145 callgraph_depth_edit->hide();
146 }
147 } else {
148 callgraph_depth_label->hide();
149 callgraph_depth_edit->hide();
150 buffer_watershed_label->hide();
151 buffer_watershed_edit->hide();
152 cpu_buffer_size_label->hide();
153 cpu_buffer_size_edit->hide();
154 }
155
156 // setup the configuration page.
157 kernel_filename_edit->setText(config.kernel_filename.c_str());
158
159 no_vmlinux->setChecked(config.no_kernel);
160
161 buffer_size_edit->setText(QString().setNum(config.buffer_size));
162 buffer_watershed_edit->setText(QString().setNum(config.buffer_watershed));
163 cpu_buffer_size_edit->setText(QString().setNum(config.cpu_buffer_size));
164 note_table_size_edit->setText(QString().setNum(config.note_table_size));
165 callgraph_depth_edit->setText(QString().setNum(config.callgraph_depth));
166 verbose->setChecked(config.verbose);
167 separate_lib_cb->setChecked(config.separate_lib);
168 separate_kernel_cb->setChecked(config.separate_kernel);
169 separate_cpu_cb->setChecked(config.separate_cpu);
170 separate_thread_cb->setChecked(config.separate_thread);
171
172 // the unit mask check boxes
173 hide_masks();
174
175 event_count_edit->setValidator(event_count_validator);
176 QIntValidator * iv;
177 iv = new QIntValidator(OP_MIN_BUF_SIZE, OP_MAX_BUF_SIZE, buffer_size_edit);
178 buffer_size_edit->setValidator(iv);
179 iv = new QIntValidator(OP_MIN_NOTE_TABLE_SIZE, OP_MAX_NOTE_TABLE_SIZE, note_table_size_edit);
180 note_table_size_edit->setValidator(iv);
181 iv = new QIntValidator(0, INT_MAX, callgraph_depth_edit);
182 callgraph_depth_edit->setValidator(iv);
183 iv = new QIntValidator(0, INT_MAX, buffer_watershed_edit);
184 buffer_watershed_edit->setValidator(iv);
185 iv = new QIntValidator(0, OP_MAX_CPU_BUF_SIZE, cpu_buffer_size_edit);
186 cpu_buffer_size_edit->setValidator(iv);
187
188 // daemon status timer
189 startTimer(5000);
190 timerEvent(0);
191
192 resize(minimumSizeHint());
193
194 // force the pixmap re-draw
195 event_selected();
196 }
197
198
fill_events()199 void oprof_start::fill_events()
200 {
201 // we need to build the event descr stuff before loading the
202 // configuration because we use locate_event to get an event descr
203 // from its name.
204 struct list_head * pos;
205 struct list_head * events = op_events(cpu_type);
206
207 list_for_each(pos, events) {
208 struct op_event * event = list_entry(pos, struct op_event, event_next);
209
210 op_event_descr descr;
211
212 descr.counter_mask = event->counter_mask;
213 descr.val = event->val;
214 if (event->unit->num) {
215 descr.unit = event->unit;
216 } else {
217 descr.unit = 0;
218 }
219
220 descr.name = event->name;
221 descr.help_str = event->desc;
222 descr.min_count = event->min_count;
223
224 for (uint ctr = 0; ctr < op_nr_counters; ++ctr) {
225 uint count;
226
227 if (!(descr.counter_mask & (1 << ctr)))
228 continue;
229
230 if (cpu_type == CPU_RTC) {
231 count = 1024;
232 } else {
233 /* setting to cpu Hz / 2000 gives a safe value for
234 * all events, and a good one for most.
235 */
236 if (cpu_speed)
237 count = int(cpu_speed * 500);
238 else
239 count = descr.min_count * 100;
240 }
241
242 event_cfgs[descr.name].count = count;
243 event_cfgs[descr.name].umask = 0;
244 if (descr.unit)
245 event_cfgs[descr.name].umask = descr.unit->default_mask;
246 event_cfgs[descr.name].os_ring_count = 1;
247 event_cfgs[descr.name].user_ring_count = 1;
248 }
249
250 v_events.push_back(descr);
251 }
252
253 events_list->header()->hide();
254 events_list->setSorting(-1);
255
256 fill_events_listbox();
257
258 read_set_events();
259
260 // FIXME: why this ?
261 if (cpu_type == CPU_RTC)
262 events_list->setCurrentItem(events_list->firstChild());
263
264 load_config_file();
265 }
266
267
268 namespace {
269
270 /// find the first item with the given text in column 0 or return NULL
findItem(QListView * view,char const * name)271 QListViewItem * findItem(QListView * view, char const * name)
272 {
273 // Qt 2.3.1 does not have QListView::findItem()
274 QListViewItem * item = view->firstChild();
275
276 while (item && strcmp(item->text(0).latin1(), name))
277 item = item->nextSibling();
278
279 return item;
280 }
281
282 };
283
284
setup_default_event()285 void oprof_start::setup_default_event()
286 {
287 struct op_default_event_descr descr;
288 op_default_event(cpu_type, &descr);
289
290 event_cfgs[descr.name].umask = descr.um;
291 event_cfgs[descr.name].count = descr.count;
292 event_cfgs[descr.name].user_ring_count = 1;
293 event_cfgs[descr.name].os_ring_count = 1;
294
295 QListViewItem * item = findItem(events_list, descr.name);
296 if (item)
297 item->setSelected(true);
298 }
299
300
read_set_events()301 void oprof_start::read_set_events()
302 {
303 string name = get_config_filename(".oprofile/daemonrc");
304
305 ifstream in(name.c_str());
306
307 if (!in) {
308 setup_default_event();
309 return;
310 }
311
312 string str;
313
314 bool one_enabled = false;
315
316 while (getline(in, str)) {
317 string const val = split(str, '=');
318 string const name = str;
319
320 if (!is_prefix(name, "CHOSEN_EVENTS_"))
321 continue;
322
323 one_enabled = true;
324
325 // CHOSEN_EVENTS_#nr=CPU_CLK_UNHALTED:10000:0:1:1
326 vector<string> parts = separate_token(val, ':');
327
328 if (parts.size() != 5 && parts.size() != 2) {
329 cerr << "invalid configuration file\n";
330 // FIXME
331 exit(EXIT_FAILURE);
332 }
333
334 string ev_name = parts[0];
335 event_cfgs[ev_name].count =
336 op_lexical_cast<unsigned int>(parts[1]);
337
338 // CPU_CLK_UNHALTED:10000 is also valid
339 if (parts.size() == 5) {
340 event_cfgs[ev_name].umask =
341 op_lexical_cast<unsigned int>(parts[2]);
342 event_cfgs[ev_name].user_ring_count =
343 op_lexical_cast<unsigned int>(parts[3]);
344 event_cfgs[ev_name].os_ring_count =
345 op_lexical_cast<unsigned int>(parts[4]);
346 } else {
347 event_cfgs[ev_name].umask = 0;
348 event_cfgs[ev_name].user_ring_count = 1;
349 event_cfgs[ev_name].os_ring_count = 1;
350 }
351
352 QListViewItem * item = findItem(events_list, ev_name.c_str());
353 if (item)
354 item->setSelected(true);
355 }
356
357 // use default event if none set
358 if (!one_enabled)
359 setup_default_event();
360 }
361
362
load_config_file()363 void oprof_start::load_config_file()
364 {
365 string name = get_config_filename(".oprofile/daemonrc");
366
367 ifstream in(name.c_str());
368 if (!in) {
369 if (!check_and_create_config_dir())
370 return;
371
372 ofstream out(name.c_str());
373 if (!out) {
374 QMessageBox::warning(this, 0, "Unable to open configuration "
375 "file ~/.oprofile/daemonrc");
376 }
377 return;
378 }
379
380 in >> config;
381 }
382
383
384 // user request a "normal" exit so save the config file.
accept()385 void oprof_start::accept()
386 {
387 // record the previous settings
388 record_selected_event_config();
389
390 save_config();
391
392 QDialog::accept();
393 }
394
395
closeEvent(QCloseEvent *)396 void oprof_start::closeEvent(QCloseEvent *)
397 {
398 accept();
399 }
400
401
timerEvent(QTimerEvent *)402 void oprof_start::timerEvent(QTimerEvent *)
403 {
404 static time_t last = time(0);
405
406 daemon_status dstat;
407
408 flush_profiler_data_btn->setEnabled(dstat.running);
409 stop_profiler_btn->setEnabled(dstat.running);
410 start_profiler_btn->setEnabled(!dstat.running);
411 reset_sample_files_btn->setEnabled(!dstat.running);
412
413 if (!dstat.running) {
414 daemon_label->setText("Profiler is not running.");
415 return;
416 }
417
418 ostringstream ss;
419 ss << "Profiler running:";
420
421 time_t curr = time(0);
422 total_nr_interrupts += dstat.nr_interrupts;
423
424 if (curr - last)
425 ss << " (" << dstat.nr_interrupts / (curr - last) << " interrupts / second, total " << total_nr_interrupts << ")";
426
427 daemon_label->setText(ss.str().c_str());
428
429 last = curr;
430 }
431
432
fill_events_listbox()433 void oprof_start::fill_events_listbox()
434 {
435 setUpdatesEnabled(false);
436
437 for (vector<op_event_descr>::reverse_iterator cit = v_events.rbegin();
438 cit != v_events.rend(); ++cit) {
439 new QListViewItem(events_list, cit->name.c_str());
440 }
441
442 setUpdatesEnabled(true);
443 update();
444 }
445
446
display_event(op_event_descr const & descr)447 void oprof_start::display_event(op_event_descr const & descr)
448 {
449 setUpdatesEnabled(false);
450
451 setup_unit_masks(descr);
452 os_ring_count_cb->setEnabled(true);
453 user_ring_count_cb->setEnabled(true);
454 event_count_edit->setEnabled(true);
455
456 event_setting & cfg = event_cfgs[descr.name];
457
458 os_ring_count_cb->setChecked(cfg.os_ring_count);
459 user_ring_count_cb->setChecked(cfg.user_ring_count);
460 QString count_text;
461 count_text.setNum(cfg.count);
462 event_count_edit->setText(count_text);
463 event_count_validator->setRange(descr.min_count, max_perf_count());
464
465 setUpdatesEnabled(true);
466 update();
467 }
468
469
is_selectable_event(QListViewItem * item)470 bool oprof_start::is_selectable_event(QListViewItem * item)
471 {
472 if (item->isSelected())
473 return true;
474
475 selected_events.insert(item);
476
477 bool ret = false;
478 if (alloc_selected_events())
479 ret = true;
480
481 selected_events.erase(item);
482
483 return ret;
484 }
485
486
draw_event_list()487 void oprof_start::draw_event_list()
488 {
489 QListViewItem * cur;
490 for (cur = events_list->firstChild(); cur; cur = cur->nextSibling()) {
491 if (is_selectable_event(cur))
492 cur->setPixmap(0, *green_pixmap);
493 else
494 cur->setPixmap(0, *red_pixmap);
495 }
496 }
497
498
alloc_selected_events() const499 bool oprof_start::alloc_selected_events() const
500 {
501 vector<op_event const *> events;
502
503 set<QListViewItem *>::const_iterator it;
504 for (it = selected_events.begin(); it != selected_events.end(); ++it)
505 events.push_back(find_event_by_name((*it)->text(0).latin1(),0,0));
506
507 size_t * map =
508 map_event_to_counter(&events[0], events.size(), cpu_type);
509
510 if (!map)
511 return false;
512
513 free(map);
514 return true;
515 }
516
event_selected()517 void oprof_start::event_selected()
518 {
519 // The deal is simple: QT lack of a way to know what item was the last
520 // (de)selected item so we record a set of selected items and diff
521 // it in the appropriate way with the previous list of selected items.
522
523 set<QListViewItem *> current_selection;
524 QListViewItem * cur;
525 for (cur = events_list->firstChild(); cur; cur = cur->nextSibling()) {
526 if (cur->isSelected())
527 current_selection.insert(cur);
528 }
529
530 // First remove the deselected item.
531 vector<QListViewItem *> new_deselected;
532 set_difference(selected_events.begin(), selected_events.end(),
533 current_selection.begin(), current_selection.end(),
534 back_inserter(new_deselected));
535 vector<QListViewItem *>::const_iterator it;
536 for (it = new_deselected.begin(); it != new_deselected.end(); ++it)
537 selected_events.erase(*it);
538
539 // Now try to add the newly selected item if enough HW resource exists
540 vector<QListViewItem *> new_selected;
541 set_difference(current_selection.begin(), current_selection.end(),
542 selected_events.begin(), selected_events.end(),
543 back_inserter(new_selected));
544 for (it = new_selected.begin(); it != new_selected.end(); ++it) {
545 selected_events.insert(*it);
546 if (!alloc_selected_events()) {
547 (*it)->setSelected(false);
548 selected_events.erase(*it);
549 } else {
550 current_event = *it;
551 }
552 }
553
554 draw_event_list();
555
556 if (current_event)
557 display_event(locate_event(current_event->text(0).latin1()));
558 }
559
560
event_over(QListViewItem * item)561 void oprof_start::event_over(QListViewItem * item)
562 {
563 op_event_descr const & descr = locate_event(item->text(0).latin1());
564
565 string help_str = descr.help_str.c_str();
566 if (!is_selectable_event(item)) {
567 help_str += " conflicts with:";
568
569 set<QListViewItem *>::const_iterator it;
570 for (it = selected_events.begin();
571 it != selected_events.end(); ) {
572 QListViewItem * temp = *it;
573 selected_events.erase(it++);
574 if (is_selectable_event(item)) {
575 help_str += " ";
576 help_str += temp->text(0).latin1();
577 }
578 selected_events.insert(temp);
579 }
580 }
581
582 event_help_label->setText(help_str.c_str());
583 }
584
585
586 /// select the kernel image filename
choose_kernel_filename()587 void oprof_start::choose_kernel_filename()
588 {
589 string name = kernel_filename_edit->text().latin1();
590 string result = do_open_file_or_dir(name, false);
591
592 if (!result.empty())
593 kernel_filename_edit->setText(result.c_str());
594 }
595
596
597 // this record the current selected event setting in the event_cfg[] stuff.
598 // FIXME: need validation?
record_selected_event_config()599 void oprof_start::record_selected_event_config()
600 {
601 if (!current_event)
602 return;
603
604 string name(current_event->text(0).latin1());
605
606 event_setting & cfg = event_cfgs[name];
607 op_event_descr const & curr = locate_event(name);
608
609 cfg.count = event_count_edit->text().toUInt();
610 cfg.os_ring_count = os_ring_count_cb->isChecked();
611 cfg.user_ring_count = user_ring_count_cb->isChecked();
612 cfg.umask = get_unit_mask(curr);
613 }
614
615
616 // validate and save the configuration (The qt validator installed
617 // are not sufficient to do the validation)
record_config()618 bool oprof_start::record_config()
619 {
620 config.kernel_filename = kernel_filename_edit->text().latin1();
621 config.no_kernel = no_vmlinux->isChecked();
622
623 uint temp = buffer_size_edit->text().toUInt();
624 if (temp < OP_MIN_BUF_SIZE || temp > OP_MAX_BUF_SIZE) {
625 ostringstream error;
626
627 error << "buffer size out of range: " << temp
628 << " valid range is [" << OP_MIN_BUF_SIZE << ", "
629 << OP_MAX_BUF_SIZE << "]";
630
631 QMessageBox::warning(this, 0, error.str().c_str());
632
633 return false;
634 }
635 config.buffer_size = temp;
636
637 temp = buffer_watershed_edit->text().toUInt();
638 // watershed above half of buffer size make little sense.
639 if (temp > config.buffer_size / 2) {
640 ostringstream error;
641
642 error << "buffer watershed out of range: " << temp
643 << " valid range is [0 (use default), buffer size/2] "
644 << "generally 0.25 * buffer size is fine";
645
646 QMessageBox::warning(this, 0, error.str().c_str());
647
648 return false;
649 }
650 config.buffer_watershed = temp;
651
652 temp = cpu_buffer_size_edit->text().toUInt();
653 if ((temp != 0 && temp < OP_MIN_CPU_BUF_SIZE) ||
654 temp > OP_MAX_CPU_BUF_SIZE) {
655 ostringstream error;
656
657 error << "cpu buffer size out of range: " << temp
658 << " valid range is [" << OP_MIN_CPU_BUF_SIZE << ", "
659 << OP_MAX_CPU_BUF_SIZE << "] (size = 0: use default)";
660
661 QMessageBox::warning(this, 0, error.str().c_str());
662
663 return false;
664 }
665 config.cpu_buffer_size = temp;
666
667 temp = note_table_size_edit->text().toUInt();
668 if (temp < OP_MIN_NOTE_TABLE_SIZE || temp > OP_MAX_NOTE_TABLE_SIZE) {
669 ostringstream error;
670
671 error << "note table size out of range: " << temp
672 << " valid range is [" << OP_MIN_NOTE_TABLE_SIZE << ", "
673 << OP_MAX_NOTE_TABLE_SIZE << "]";
674
675 QMessageBox::warning(this, 0, error.str().c_str());
676
677 return false;
678 }
679 config.note_table_size = temp;
680
681 temp = callgraph_depth_edit->text().toUInt();
682 if (temp > INT_MAX) {
683 ostringstream error;
684
685 error << "callgraph depth out of range: " << temp
686 << " valid range is [" << 0 << ", "
687 << INT_MAX << "]";
688
689 QMessageBox::warning(this, 0, error.str().c_str());
690
691 return false;
692 }
693 config.callgraph_depth = temp;
694
695 config.verbose = verbose->isChecked();
696 config.separate_lib = separate_lib_cb->isChecked();
697 config.separate_kernel = separate_kernel_cb->isChecked();
698 config.separate_cpu = separate_cpu_cb->isChecked();
699 config.separate_thread = separate_thread_cb->isChecked();
700
701 return true;
702 }
703
704
get_unit_mask_part(op_event_descr const & descr,uint num,bool selected,uint & mask)705 void oprof_start::get_unit_mask_part(op_event_descr const & descr, uint num,
706 bool selected, uint & mask)
707 {
708 if (!selected)
709 return;
710 if (num >= descr.unit->num)
711 return;
712
713 if (descr.unit->unit_type_mask == utm_bitmask)
714 mask |= descr.unit->um[num].value;
715 else
716 mask = descr.unit->um[num].value;
717 }
718
719
720 // return the unit mask selected through the unit mask check box
get_unit_mask(op_event_descr const & descr)721 uint oprof_start::get_unit_mask(op_event_descr const & descr)
722 {
723 uint mask = 0;
724
725 if (!descr.unit)
726 return 0;
727
728 // mandatory mask is transparent for user.
729 if (descr.unit->unit_type_mask == utm_mandatory) {
730 mask = descr.unit->default_mask;
731 return mask;
732 }
733
734 get_unit_mask_part(descr, 0, check0->isChecked(), mask);
735 get_unit_mask_part(descr, 1, check1->isChecked(), mask);
736 get_unit_mask_part(descr, 2, check2->isChecked(), mask);
737 get_unit_mask_part(descr, 3, check3->isChecked(), mask);
738 get_unit_mask_part(descr, 4, check4->isChecked(), mask);
739 get_unit_mask_part(descr, 5, check5->isChecked(), mask);
740 get_unit_mask_part(descr, 6, check6->isChecked(), mask);
741 get_unit_mask_part(descr, 7, check7->isChecked(), mask);
742 get_unit_mask_part(descr, 8, check8->isChecked(), mask);
743 get_unit_mask_part(descr, 9, check9->isChecked(), mask);
744 get_unit_mask_part(descr, 10, check10->isChecked(), mask);
745 get_unit_mask_part(descr, 11, check11->isChecked(), mask);
746 get_unit_mask_part(descr, 12, check12->isChecked(), mask);
747 get_unit_mask_part(descr, 13, check13->isChecked(), mask);
748 get_unit_mask_part(descr, 14, check14->isChecked(), mask);
749 get_unit_mask_part(descr, 15, check15->isChecked(), mask);
750 return mask;
751 }
752
753
hide_masks()754 void oprof_start::hide_masks()
755 {
756 check0->hide();
757 check1->hide();
758 check2->hide();
759 check3->hide();
760 check4->hide();
761 check5->hide();
762 check6->hide();
763 check7->hide();
764 check8->hide();
765 check9->hide();
766 check10->hide();
767 check11->hide();
768 check12->hide();
769 check13->hide();
770 check14->hide();
771 check15->hide();
772 }
773
774
setup_unit_masks(op_event_descr const & descr)775 void oprof_start::setup_unit_masks(op_event_descr const & descr)
776 {
777 op_unit_mask const * um = descr.unit;
778
779 hide_masks();
780
781 if (!um || um->unit_type_mask == utm_mandatory)
782 return;
783
784 event_setting & cfg = event_cfgs[descr.name];
785
786 unit_mask_group->setExclusive(um->unit_type_mask == utm_exclusive);
787
788 for (size_t i = 0; i < um->num ; ++i) {
789 QCheckBox * check = 0;
790 switch (i) {
791 case 0: check = check0; break;
792 case 1: check = check1; break;
793 case 2: check = check2; break;
794 case 3: check = check3; break;
795 case 4: check = check4; break;
796 case 5: check = check5; break;
797 case 6: check = check6; break;
798 case 7: check = check7; break;
799 case 8: check = check8; break;
800 case 9: check = check9; break;
801 case 10: check = check10; break;
802 case 11: check = check11; break;
803 case 12: check = check12; break;
804 case 13: check = check13; break;
805 case 14: check = check14; break;
806 case 15: check = check15; break;
807 }
808 check->setText(um->um[i].desc);
809 if (um->unit_type_mask == utm_exclusive)
810 check->setChecked(cfg.umask == um->um[i].value);
811 else
812 check->setChecked(cfg.umask & um->um[i].value);
813
814 check->show();
815 }
816 unit_mask_group->setMinimumSize(unit_mask_group->sizeHint());
817 setup_config_tab->setMinimumSize(setup_config_tab->sizeHint());
818 }
819
820
max_perf_count() const821 uint oprof_start::max_perf_count() const
822 {
823 return cpu_type == CPU_RTC ? OP_MAX_RTC_COUNT : OP_MAX_PERF_COUNT;
824 }
825
826
on_flush_profiler_data()827 void oprof_start::on_flush_profiler_data()
828 {
829 vector<string> args;
830 args.push_back("--dump");
831
832 if (daemon_status().running)
833 do_exec_command(OP_BINDIR "/opcontrol", args);
834 else
835 QMessageBox::warning(this, 0, "The profiler is not started.");
836 }
837
838
839 // user is happy of its setting.
on_start_profiler()840 void oprof_start::on_start_profiler()
841 {
842 // save the current settings
843 record_selected_event_config();
844
845 bool one_enable = false;
846
847 QListViewItem * cur;
848 for (cur = events_list->firstChild(); cur; cur = cur->nextSibling()) {
849 if (!cur->isSelected())
850 continue;
851
852 // the missing reference is intended: gcc 2.91.66 can compile
853 // "op_event_descr const & descr = ..." w/o a warning
854 op_event_descr const descr =
855 locate_event(cur->text(0).latin1());
856
857 event_setting & cfg = event_cfgs[cur->text(0).latin1()];
858
859 one_enable = true;
860
861 if (!cfg.os_ring_count && !cfg.user_ring_count) {
862 QMessageBox::warning(this, 0, "You must select to "
863 "profile at least one of user binaries/kernel");
864 return;
865 }
866
867 if (cfg.count < descr.min_count ||
868 cfg.count > max_perf_count()) {
869 ostringstream out;
870
871 out << "event " << descr.name << " count of range: "
872 << cfg.count << " must be in [ "
873 << descr.min_count << ", "
874 << max_perf_count()
875 << "]";
876
877 QMessageBox::warning(this, 0, out.str().c_str());
878 return;
879 }
880
881 if (descr.unit &&
882 descr.unit->unit_type_mask == utm_bitmask &&
883 cfg.umask == 0) {
884 ostringstream out;
885
886 out << "event " << descr.name << " invalid unit mask: "
887 << cfg.umask << endl;
888
889 QMessageBox::warning(this, 0, out.str().c_str());
890 return;
891 }
892 }
893
894 if (one_enable == false && cpu_type != CPU_TIMER_INT) {
895 QMessageBox::warning(this, 0, "No counters enabled.\n");
896 return;
897 }
898
899 if (daemon_status().running) {
900 // gcc 2.91 work around
901 int user_choice = 0;
902 user_choice =
903 QMessageBox::warning(this, 0,
904 "Profiler already started:\n\n"
905 "stop and restart it?",
906 "&Restart", "&Cancel", 0, 0, 1);
907
908 if (user_choice == 1)
909 return;
910
911 // this flush profiler data also.
912 on_stop_profiler();
913 }
914
915 vector<string> args;
916
917 // save_config validate and setup the config
918 if (save_config()) {
919 // now actually start
920 args.push_back("--start");
921 if (config.verbose)
922 args.push_back("--verbose");
923 do_exec_command(OP_BINDIR "/opcontrol", args);
924 }
925
926 total_nr_interrupts = 0;
927 timerEvent(0);
928 }
929
930
save_config()931 bool oprof_start::save_config()
932 {
933 if (!record_config())
934 return false;
935
936 vector<string> args;
937
938 // saving config is done by running opcontrol --setup with appropriate
939 // setted parameters so we use the same config file as command line
940 // tools
941
942 args.push_back("--setup");
943
944 bool one_enabled = false;
945
946 vector<string> tmpargs;
947 tmpargs.push_back("--setup");
948
949 QListViewItem * cur;
950 for (cur = events_list->firstChild(); cur; cur = cur->nextSibling()) {
951 if (!cur->isSelected())
952 continue;
953
954 event_setting & cfg = event_cfgs[cur->text(0).latin1()];
955
956 op_event_descr const & descr =
957 locate_event(cur->text(0).latin1());
958
959 one_enabled = true;
960
961 string arg = "--event=" + descr.name;
962 arg += ":" + op_lexical_cast<string>(cfg.count);
963 arg += ":" + op_lexical_cast<string>(cfg.umask);
964 arg += ":" + op_lexical_cast<string>(cfg.os_ring_count);
965 arg += ":" + op_lexical_cast<string>(cfg.user_ring_count);
966
967 tmpargs.push_back(arg);
968 }
969
970 // only set counters if at least one is enabled
971 if (one_enabled)
972 args = tmpargs;
973
974 if (config.no_kernel) {
975 args.push_back("--no-vmlinux");
976 } else {
977 args.push_back("--vmlinux=" + config.kernel_filename);
978 }
979
980 args.push_back("--buffer-size=" +
981 op_lexical_cast<string>(config.buffer_size));
982
983 if (op_get_interface() == OP_INTERFACE_24) {
984 args.push_back("--note-table-size=" +
985 op_lexical_cast<string>(config.note_table_size));
986 } else {
987 args.push_back("--buffer-watershed=" +
988 op_lexical_cast<string>(config.buffer_watershed));
989 args.push_back("--cpu-buffer-size=" +
990 op_lexical_cast<string>(config.cpu_buffer_size));
991 if (op_file_readable("/dev/oprofile/backtrace_depth")) {
992 args.push_back("--callgraph=" +
993 op_lexical_cast<string>(config.callgraph_depth));
994 }
995 }
996
997 string sep = "--separate=";
998
999 if (config.separate_lib)
1000 sep += "library,";
1001 if (config.separate_kernel)
1002 sep += "kernel,";
1003 if (config.separate_cpu)
1004 sep += "cpu,";
1005 if (config.separate_thread)
1006 sep += "thread,";
1007
1008 if (sep == "--separate=")
1009 sep += "none";
1010 args.push_back(sep);
1011
1012 // 2.95 work-around, it didn't like return !do_exec_command()
1013 bool ret = !do_exec_command(OP_BINDIR "/opcontrol", args);
1014 return ret;
1015 }
1016
1017
1018 // flush and stop the profiler if it was started.
on_stop_profiler()1019 void oprof_start::on_stop_profiler()
1020 {
1021 vector<string> args;
1022 args.push_back("--shutdown");
1023
1024 if (daemon_status().running)
1025 do_exec_command(OP_BINDIR "/opcontrol", args);
1026 else
1027 QMessageBox::warning(this, 0, "The profiler is already stopped.");
1028
1029 timerEvent(0);
1030 }
1031
1032
on_separate_kernel_cb_changed(int state)1033 void oprof_start::on_separate_kernel_cb_changed(int state)
1034 {
1035 if (state == 2)
1036 separate_lib_cb->setChecked(true);
1037 }
1038
on_reset_sample_files()1039 void oprof_start::on_reset_sample_files()
1040 {
1041 int ret = QMessageBox::warning(this, 0, "Are you sure you want to "
1042 "reset your last profile session ?", "Yes", "No", 0, 0, 1);
1043 if (!ret) {
1044 vector<string> args;
1045 args.push_back("--reset");
1046 if (!do_exec_command(OP_BINDIR "/opcontrol", args))
1047 // the next timer event will overwrite the message
1048 daemon_label->setText("Last profile session reseted.");
1049 else
1050 QMessageBox::warning(this, 0,
1051 "Can't reset profiling session.");
1052 }
1053 }
1054
1055
1056 /// function object for matching against name
1057 class event_name_eq {
1058 string name_;
1059 public:
event_name_eq(string const & s)1060 explicit event_name_eq(string const & s) : name_(s) {}
operator ()(op_event_descr const & d) const1061 bool operator()(op_event_descr const & d) const {
1062 return d.name == name_;
1063 }
1064 };
1065
1066
1067 // helper to retrieve an event descr through its name.
locate_event(string const & name) const1068 op_event_descr const & oprof_start::locate_event(string const & name) const
1069 {
1070 return *(find_if(v_events.begin(), v_events.end(), event_name_eq(name)));
1071 }
1072