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