Home | History | Annotate | Download | only in gui
      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 
     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 
    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 
    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
    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 
    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 
    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 
    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.
    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 
    396 void oprof_start::closeEvent(QCloseEvent *)
    397 {
    398 	accept();
    399 }
    400 
    401 
    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 
    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 
    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 
    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 
    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 
    499 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 
    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 
    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
    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?
    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)
    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 
    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
    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 
    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 
    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 
    821 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 
    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.
    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 
    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.
   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 
   1033 void oprof_start::on_separate_kernel_cb_changed(int state)
   1034 {
   1035 	if (state == 2)
   1036 		separate_lib_cb->setChecked(true);
   1037 }
   1038 
   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:
   1060 	explicit event_name_eq(string const & s) : name_(s) {}
   1061 	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.
   1068 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