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