• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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