oprof_start.cpp

Go to the documentation of this file.
00001 
00012 #include <sys/stat.h>
00013 #include <unistd.h>
00014 
00015 #include <ctime>
00016 #include <cstdio>
00017 #include <cmath>
00018 #include <sstream>
00019 #include <iostream>
00020 #include <fstream>
00021 #include <algorithm>
00022 
00023 #if QT3_SUPPORT
00024 #include <Qt/qlineedit.h>
00025 #include <Qt/qcheckbox.h>
00026 #include <Qt/qtabwidget.h>
00027 #include <Qt/qmessagebox.h>
00028 #include <Qt/qvalidator.h>
00029 #include <Qt/qlabel.h>
00030 #include <Qt/qpushbutton.h>
00031 #include <Qt/q3listview.h>
00032 #include <Qt/q3combobox.h>
00033 #include <Qt/q3listbox.h>
00034 #include <Qt/q3filedialog.h>
00035 #include <Qt/q3buttongroup.h>
00036 #include <Qt/q3header.h>
00037 #else
00038 #include <qlineedit.h>
00039 #include <qcheckbox.h>
00040 #include <qtabwidget.h>
00041 #include <qmessagebox.h>
00042 #include <qvalidator.h>
00043 #include <qlabel.h>
00044 #include <qpushbutton.h>
00045 #include <qlistview.h>
00046 #include <qcombobox.h>
00047 #include <qlistbox.h>
00048 #include <qfiledialog.h>
00049 #include <qbuttongroup.h>
00050 #include <qheader.h>
00051 #define Q3ListView QListView
00052 #endif
00053 
00054 #include "oprof_start.h"
00055 #include "op_config.h"
00056 #include "op_config_24.h"
00057 #include "string_manip.h"
00058 #include "op_cpufreq.h"
00059 #include "op_alloc_counter.h"
00060 #include "oprof_start_util.h"
00061 #include "file_manip.h"
00062 
00063 #include "op_hw_config.h"
00064 
00065 using namespace std;
00066 
00067 static char const * green_xpm[] = {
00068 "16 16 2 1",
00069 "   c None",
00070 ".  c #00FF00",
00071 "    .......     ",
00072 "  ...........   ",
00073 " .............  ",
00074 " .............  ",
00075 "............... ",
00076 "............... ",
00077 "............... ",
00078 "............... ",
00079 "............... ",
00080 "............... ",
00081 "............... ",
00082 " .............  ",
00083 " .............  ",
00084 "  ...........   ",
00085 "    .......     ",
00086 "                " };
00087 
00088 static char const * red_xpm[] = {
00089 "16 16 2 1",
00090 "   c None",
00091 ".  c #FF0000",
00092 "    .......     ",
00093 "  ...........   ",
00094 " .............  ",
00095 " .............  ",
00096 "............... ",
00097 "............... ",
00098 "............... ",
00099 "............... ",
00100 "............... ",
00101 "............... ",
00102 "............... ",
00103 " .............  ",
00104 " .............  ",
00105 "  ...........   ",
00106 "    .......     ",
00107 "                " };
00108 
00109 static QPixmap * green_pixmap;
00110 static QPixmap * red_pixmap;
00111 
00112 
00113 op_event_descr::op_event_descr()
00114     :
00115     counter_mask(0),
00116     val(0),
00117     unit(0),
00118     min_count(0)
00119 {
00120 }
00121 
00122 
00123 oprof_start::oprof_start()
00124     :
00125     oprof_start_base(0, 0, false, 0),
00126     event_count_validator(new QIntValidator(event_count_edit)),
00127     current_event(0),
00128     cpu_speed(op_cpu_frequency()),
00129     total_nr_interrupts(0)
00130 {
00131     green_pixmap = new QPixmap(green_xpm);
00132     red_pixmap = new QPixmap(red_xpm);
00133     vector<string> args;
00134     args.push_back("--init");
00135 
00136     if (do_exec_command(OP_BINDIR "/opcontrol", args))
00137         exit(EXIT_FAILURE);
00138 
00139     cpu_type = op_get_cpu_type();
00140     op_nr_counters = op_get_nr_counters(cpu_type);
00141 
00142     if (cpu_type == CPU_TIMER_INT) {
00143         setup_config_tab->removePage(counter_setup_page);
00144     } else {
00145         fill_events();
00146     }
00147 
00148     op_interface interface = op_get_interface();
00149     if (interface == OP_INTERFACE_NO_GOOD) {
00150         QMessageBox::warning(this, 0, "Couldn't determine kernel"
00151                              " interface version");
00152         exit(EXIT_FAILURE);
00153     }
00154     bool is_26 = interface == OP_INTERFACE_26;
00155 
00156     if (is_26) {
00157         note_table_size_edit->hide();
00158         note_table_size_label->hide();
00159         if (!op_file_readable("/dev/oprofile/backtrace_depth")) {
00160             callgraph_depth_label->hide();
00161             callgraph_depth_edit->hide();
00162         }
00163     } else {
00164         callgraph_depth_label->hide();
00165         callgraph_depth_edit->hide();
00166         buffer_watershed_label->hide();
00167         buffer_watershed_edit->hide();
00168         cpu_buffer_size_label->hide();
00169         cpu_buffer_size_edit->hide();
00170     }
00171 
00172     // setup the configuration page.
00173     kernel_filename_edit->setText(config.kernel_filename.c_str());
00174 
00175     no_vmlinux->setChecked(config.no_kernel);
00176 
00177     buffer_size_edit->setText(QString().setNum(config.buffer_size));
00178     buffer_watershed_edit->setText(QString().setNum(config.buffer_watershed));
00179     cpu_buffer_size_edit->setText(QString().setNum(config.cpu_buffer_size));
00180     note_table_size_edit->setText(QString().setNum(config.note_table_size));
00181     callgraph_depth_edit->setText(QString().setNum(config.callgraph_depth));
00182     verbose->setChecked(config.verbose);
00183     separate_lib_cb->setChecked(config.separate_lib);
00184     separate_kernel_cb->setChecked(config.separate_kernel);
00185     separate_cpu_cb->setChecked(config.separate_cpu);
00186     separate_thread_cb->setChecked(config.separate_thread);
00187 
00188     // the unit mask check boxes
00189     hide_masks();
00190 
00191     event_count_edit->setValidator(event_count_validator);
00192     QIntValidator * iv;
00193     iv = new QIntValidator(OP_MIN_BUF_SIZE, OP_MAX_BUF_SIZE, buffer_size_edit);
00194     buffer_size_edit->setValidator(iv);
00195     iv = new QIntValidator(OP_MIN_NOTE_TABLE_SIZE, OP_MAX_NOTE_TABLE_SIZE, note_table_size_edit);
00196     note_table_size_edit->setValidator(iv);
00197     iv = new QIntValidator(0, INT_MAX, callgraph_depth_edit);
00198     callgraph_depth_edit->setValidator(iv);
00199     iv = new QIntValidator(0, INT_MAX, buffer_watershed_edit);
00200     buffer_watershed_edit->setValidator(iv);
00201     iv = new QIntValidator(0, OP_MAX_CPU_BUF_SIZE, cpu_buffer_size_edit);
00202     cpu_buffer_size_edit->setValidator(iv);
00203 
00204     // daemon status timer
00205     startTimer(5000);
00206     timerEvent(0);
00207 
00208     resize(minimumSizeHint());
00209 
00210     // force the pixmap re-draw
00211     event_selected();
00212 }
00213 
00214 
00215 void oprof_start::fill_events()
00216 {
00217     // we need to build the event descr stuff before loading the
00218     // configuration because we use locate_event to get an event descr
00219     // from its name.
00220     struct list_head * pos;
00221     struct list_head * events = op_events(cpu_type);
00222 
00223     list_for_each(pos, events) {
00224         struct op_event * event = list_entry(pos, struct op_event, event_next);
00225 
00226         op_event_descr descr;
00227 
00228         descr.counter_mask = event->counter_mask;
00229         descr.val = event->val;
00230         if (event->unit->num) {
00231             descr.unit = event->unit;
00232         } else {
00233             descr.unit = 0;
00234         }
00235 
00236         descr.name = event->name;
00237         descr.help_str = event->desc;
00238         descr.min_count = event->min_count;
00239 
00240         for (uint ctr = 0; ctr < op_nr_counters; ++ctr) {
00241             uint count;
00242 
00243             if (!(descr.counter_mask & (1 << ctr)))
00244                 continue;
00245 
00246             if (cpu_type == CPU_RTC) {
00247                 count = 1024;
00248             } else {
00249                 /* setting to cpu Hz / 2000 gives a safe value for
00250                  * all events, and a good one for most.
00251                  */
00252                 if (cpu_speed)
00253                     count = int(cpu_speed * 500);
00254                 else
00255                     count = descr.min_count * 100;
00256             }
00257 
00258             event_cfgs[descr.name].count = count;
00259             event_cfgs[descr.name].umask = 0;
00260             if (descr.unit)
00261                 event_cfgs[descr.name].umask = descr.unit->default_mask;
00262             event_cfgs[descr.name].os_ring_count = 1;
00263             event_cfgs[descr.name].user_ring_count = 1;
00264         }
00265 
00266         v_events.push_back(descr);
00267     }
00268 
00269     events_list->header()->hide();
00270     events_list->setSorting(-1);
00271 
00272     fill_events_listbox();
00273 
00274     read_set_events();
00275 
00276     // FIXME: why this ?
00277     if (cpu_type == CPU_RTC)
00278         events_list->setCurrentItem(events_list->firstChild());
00279 
00280     load_config_file();
00281 }
00282 
00283 
00284 namespace {
00285 
00287 Q3ListViewItem * findItem(Q3ListView * view, char const * name)
00288 {
00289     // Qt 2.3.1 does not have QListView::findItem()
00290     Q3ListViewItem * item = view->firstChild();
00291 
00292     while (item && strcmp(item->text(0).latin1(), name))
00293         item = item->nextSibling();
00294 
00295     return item;
00296 }
00297 
00298 };
00299 
00300 
00301 void oprof_start::setup_default_event()
00302 {
00303     struct op_default_event_descr descr;
00304     op_default_event(cpu_type, &descr);
00305 
00306     event_cfgs[descr.name].umask = descr.um;
00307     event_cfgs[descr.name].count = descr.count;
00308     event_cfgs[descr.name].user_ring_count = 1;
00309     event_cfgs[descr.name].os_ring_count = 1;
00310 
00311     Q3ListViewItem * item = findItem(events_list, descr.name);
00312     if (item)
00313         item->setSelected(true);
00314 }
00315 
00316 
00317 void oprof_start::read_set_events()
00318 {
00319     string name = get_config_filename(".oprofile/daemonrc");
00320 
00321     ifstream in(name.c_str());
00322 
00323     if (!in) {
00324         setup_default_event();
00325         return;
00326     }
00327 
00328     string str;
00329 
00330     bool one_enabled = false;
00331 
00332     while (getline(in, str)) {
00333         string const val = split(str, '=');
00334         string const name = str;
00335 
00336         if (!is_prefix(name, "CHOSEN_EVENTS_"))
00337             continue;
00338 
00339         one_enabled = true;
00340 
00341         // CHOSEN_EVENTS_#nr=CPU_CLK_UNHALTED:10000:0:1:1
00342         vector<string> parts = separate_token(val, ':');
00343 
00344         if (parts.size() != 5 && parts.size() != 2) {
00345             cerr << "invalid configuration file\n";
00346             // FIXME
00347             exit(EXIT_FAILURE);
00348         }
00349 
00350         string ev_name = parts[0];
00351         event_cfgs[ev_name].count =
00352             op_lexical_cast<unsigned int>(parts[1]);
00353 
00354         // CPU_CLK_UNHALTED:10000 is also valid
00355         if (parts.size() == 5) {
00356             event_cfgs[ev_name].umask =
00357                 op_lexical_cast<unsigned int>(parts[2]);
00358             event_cfgs[ev_name].user_ring_count =
00359                 op_lexical_cast<unsigned int>(parts[3]);
00360             event_cfgs[ev_name].os_ring_count =
00361                 op_lexical_cast<unsigned int>(parts[4]);
00362         } else {
00363             event_cfgs[ev_name].umask = 0;
00364             event_cfgs[ev_name].user_ring_count = 1;
00365             event_cfgs[ev_name].os_ring_count = 1;
00366         }
00367 
00368         Q3ListViewItem * item = findItem(events_list, ev_name.c_str());
00369         if (item)
00370             item->setSelected(true);
00371     }
00372 
00373     // use default event if none set
00374     if (!one_enabled)
00375         setup_default_event();
00376 }
00377 
00378 
00379 void oprof_start::load_config_file()
00380 {
00381     string name = get_config_filename(".oprofile/daemonrc");
00382 
00383     ifstream in(name.c_str());
00384     if (!in) {
00385         if (!check_and_create_config_dir())
00386             return;
00387 
00388         ofstream out(name.c_str());
00389         if (!out) {
00390             QMessageBox::warning(this, 0, "Unable to open configuration "
00391                 "file ~/.oprofile/daemonrc");
00392         }
00393         return;
00394     }
00395 
00396     in >> config;
00397 }
00398 
00399 
00400 // user request a "normal" exit so save the config file.
00401 void oprof_start::accept()
00402 {
00403     // record the previous settings
00404     record_selected_event_config();
00405 
00406     save_config();
00407 
00408     QDialog::accept();
00409 }
00410 
00411 
00412 void oprof_start::closeEvent(QCloseEvent *)
00413 {
00414     accept();
00415 }
00416 
00417 
00418 void oprof_start::timerEvent(QTimerEvent *)
00419 {
00420     static time_t last = time(0);
00421 
00422     daemon_status dstat;
00423 
00424     flush_profiler_data_btn->setEnabled(dstat.running);
00425     stop_profiler_btn->setEnabled(dstat.running);
00426     start_profiler_btn->setEnabled(!dstat.running);
00427     reset_sample_files_btn->setEnabled(!dstat.running);
00428 
00429     if (!dstat.running) {
00430         daemon_label->setText("Profiler is not running.");
00431         return;
00432     }
00433 
00434     ostringstream ss;
00435     ss << "Profiler running:";
00436 
00437     time_t curr = time(0);
00438     total_nr_interrupts += dstat.nr_interrupts;
00439 
00440     if (curr - last)
00441         ss << " (" << dstat.nr_interrupts / (curr - last) << " interrupts / second, total " << total_nr_interrupts << ")";
00442 
00443     daemon_label->setText(ss.str().c_str());
00444 
00445     last = curr;
00446 }
00447 
00448 
00449 void oprof_start::fill_events_listbox()
00450 {
00451     setUpdatesEnabled(false);
00452 
00453     for (vector<op_event_descr>::reverse_iterator cit = v_events.rbegin();
00454          cit != v_events.rend(); ++cit) {
00455         new Q3ListViewItem(events_list, cit->name.c_str());
00456     }
00457 
00458     setUpdatesEnabled(true);
00459     update();
00460 }
00461 
00462 
00463 void oprof_start::display_event(op_event_descr const & descr)
00464 {
00465     setUpdatesEnabled(false);
00466 
00467     setup_unit_masks(descr);
00468     os_ring_count_cb->setEnabled(true);
00469     user_ring_count_cb->setEnabled(true);
00470     event_count_edit->setEnabled(true);
00471 
00472     event_setting & cfg = event_cfgs[descr.name];
00473 
00474     os_ring_count_cb->setChecked(cfg.os_ring_count);
00475     user_ring_count_cb->setChecked(cfg.user_ring_count);
00476     QString count_text;
00477     count_text.setNum(cfg.count);
00478     event_count_edit->setText(count_text);
00479     event_count_validator->setRange(descr.min_count, max_perf_count());
00480 
00481     setUpdatesEnabled(true);
00482     update();
00483 }
00484 
00485 
00486 bool oprof_start::is_selectable_event(Q3ListViewItem * item)
00487 {
00488     if (item->isSelected())
00489         return true;
00490 
00491     selected_events.insert(item);
00492 
00493     bool ret = false;
00494     if (alloc_selected_events())
00495         ret = true;
00496 
00497     selected_events.erase(item);
00498 
00499     return ret;
00500 }
00501 
00502 
00503 void oprof_start::draw_event_list()
00504 {
00505     Q3ListViewItem * cur;
00506     for (cur = events_list->firstChild(); cur; cur = cur->nextSibling()) {
00507         if (is_selectable_event(cur))
00508             cur->setPixmap(0, *green_pixmap);
00509         else
00510             cur->setPixmap(0, *red_pixmap);
00511     }
00512 }
00513 
00514 
00515 bool oprof_start::alloc_selected_events() const
00516 {
00517     vector<op_event const *> events;
00518 
00519     set<Q3ListViewItem *>::const_iterator it;
00520     for (it = selected_events.begin(); it != selected_events.end(); ++it)
00521         events.push_back(find_event_by_name((*it)->text(0).latin1(),0,0));
00522 
00523     size_t * map =
00524         map_event_to_counter(&events[0], events.size(), cpu_type);
00525 
00526     if (!map)
00527         return false;
00528 
00529     free(map);
00530     return true;
00531 }
00532 
00533 void oprof_start::event_selected()
00534 {
00535     // The deal is simple: QT lack of a way to know what item was the last
00536     // (de)selected item so we record a set of selected items and diff
00537     // it in the appropriate way with the previous list of selected items.
00538 
00539     set<Q3ListViewItem *> current_selection;
00540     Q3ListViewItem * cur;
00541     for (cur = events_list->firstChild(); cur; cur = cur->nextSibling()) {
00542         if (cur->isSelected())
00543             current_selection.insert(cur);
00544     }
00545 
00546     // First remove the deselected item.
00547     vector<Q3ListViewItem *> new_deselected;
00548     set_difference(selected_events.begin(), selected_events.end(),
00549                current_selection.begin(), current_selection.end(),
00550                back_inserter(new_deselected));
00551     vector<Q3ListViewItem *>::const_iterator it;
00552     for (it = new_deselected.begin(); it != new_deselected.end(); ++it)
00553         selected_events.erase(*it);
00554 
00555     // Now try to add the newly selected item if enough HW resource exists
00556     vector<Q3ListViewItem *> new_selected;
00557     set_difference(current_selection.begin(), current_selection.end(),
00558                selected_events.begin(), selected_events.end(),
00559                back_inserter(new_selected));
00560     for (it = new_selected.begin(); it != new_selected.end(); ++it) {
00561         selected_events.insert(*it);
00562         if (!alloc_selected_events()) {
00563             (*it)->setSelected(false);
00564             selected_events.erase(*it);
00565         } else {
00566             current_event = *it;
00567         }
00568     }
00569 
00570     draw_event_list();
00571 
00572     if (current_event)
00573         display_event(locate_event(current_event->text(0).latin1()));
00574 }
00575 
00576 
00577 void oprof_start::event_over(Q3ListViewItem * item)
00578 {
00579     op_event_descr const & descr = locate_event(item->text(0).latin1());
00580 
00581     string help_str = descr.help_str.c_str();
00582     if (!is_selectable_event(item)) {
00583         help_str += " conflicts with:";
00584 
00585         set<Q3ListViewItem *>::const_iterator it;
00586         for (it = selected_events.begin(); 
00587              it != selected_events.end(); ) {
00588             Q3ListViewItem * temp = *it;
00589             selected_events.erase(it++);
00590             if (is_selectable_event(item)) {
00591                 help_str += " ";
00592                 help_str += temp->text(0).latin1();
00593             }
00594             selected_events.insert(temp);
00595         }
00596     }
00597 
00598     event_help_label->setText(help_str.c_str());
00599 }
00600 
00601 
00603 void oprof_start::choose_kernel_filename()
00604 {
00605     string name = kernel_filename_edit->text().latin1();
00606     string result = do_open_file_or_dir(name, false);
00607 
00608     if (!result.empty())
00609         kernel_filename_edit->setText(result.c_str());
00610 }
00611 
00612 
00613 // this record the current selected event setting in the event_cfg[] stuff.
00614 // FIXME: need validation?
00615 void oprof_start::record_selected_event_config()
00616 {
00617     if (!current_event)
00618         return;
00619 
00620     string name(current_event->text(0).latin1());
00621 
00622     event_setting & cfg = event_cfgs[name];
00623     op_event_descr const & curr = locate_event(name);
00624 
00625     cfg.count = event_count_edit->text().toUInt();
00626     cfg.os_ring_count = os_ring_count_cb->isChecked();
00627     cfg.user_ring_count = user_ring_count_cb->isChecked();
00628     cfg.umask = get_unit_mask(curr);
00629 }
00630 
00631 
00632 // validate and save the configuration (The qt validator installed
00633 // are not sufficient to do the validation)
00634 bool oprof_start::record_config()
00635 {
00636     config.kernel_filename = kernel_filename_edit->text().latin1();
00637     config.no_kernel = no_vmlinux->isChecked();
00638 
00639     uint temp = buffer_size_edit->text().toUInt();
00640     if (temp < OP_MIN_BUF_SIZE || temp > OP_MAX_BUF_SIZE) {
00641         ostringstream error;
00642 
00643         error << "buffer size out of range: " << temp
00644               << " valid range is [" << OP_MIN_BUF_SIZE << ", "
00645               << OP_MAX_BUF_SIZE << "]";
00646 
00647         QMessageBox::warning(this, 0, error.str().c_str());
00648 
00649         return false;
00650     }
00651     config.buffer_size = temp;
00652 
00653     temp = buffer_watershed_edit->text().toUInt();
00654     // watershed above half of buffer size make little sense.
00655     if (temp > config.buffer_size / 2) {
00656         ostringstream error;
00657 
00658         error << "buffer watershed out of range: " << temp
00659               << " valid range is [0 (use default), buffer size/2] "
00660               << "generally 0.25 * buffer size is fine";
00661 
00662         QMessageBox::warning(this, 0, error.str().c_str());
00663 
00664         return false;
00665     }
00666     config.buffer_watershed = temp;
00667 
00668     temp = cpu_buffer_size_edit->text().toUInt();
00669     if ((temp != 0 && temp < OP_MIN_CPU_BUF_SIZE) ||
00670         temp > OP_MAX_CPU_BUF_SIZE) {
00671         ostringstream error;
00672 
00673         error << "cpu buffer size out of range: " << temp
00674               << " valid range is [" << OP_MIN_CPU_BUF_SIZE << ", "
00675               << OP_MAX_CPU_BUF_SIZE << "] (size = 0: use default)";
00676 
00677         QMessageBox::warning(this, 0, error.str().c_str());
00678 
00679         return false;
00680     }
00681     config.cpu_buffer_size = temp;
00682 
00683     temp = note_table_size_edit->text().toUInt();
00684     if (temp < OP_MIN_NOTE_TABLE_SIZE || temp > OP_MAX_NOTE_TABLE_SIZE) {
00685         ostringstream error;
00686 
00687         error << "note table size out of range: " << temp
00688               << " valid range is [" << OP_MIN_NOTE_TABLE_SIZE << ", "
00689               << OP_MAX_NOTE_TABLE_SIZE << "]";
00690 
00691         QMessageBox::warning(this, 0, error.str().c_str());
00692 
00693         return false;
00694     }
00695     config.note_table_size = temp;
00696 
00697     temp = callgraph_depth_edit->text().toUInt();
00698     if (temp > INT_MAX) {
00699         ostringstream error;
00700 
00701         error << "callgraph depth  out of range: " << temp
00702               << " valid range is [" << 0 << ", "
00703               << INT_MAX << "]";
00704 
00705         QMessageBox::warning(this, 0, error.str().c_str());
00706 
00707         return false;
00708     }
00709     config.callgraph_depth = temp;
00710 
00711     config.verbose = verbose->isChecked();
00712     config.separate_lib = separate_lib_cb->isChecked();
00713     config.separate_kernel = separate_kernel_cb->isChecked();
00714     config.separate_cpu = separate_cpu_cb->isChecked();
00715     config.separate_thread = separate_thread_cb->isChecked();
00716 
00717     return true;
00718 }
00719 
00720 
00721 void oprof_start::get_unit_mask_part(op_event_descr const & descr, uint num,
00722                                      bool selected, uint & mask)
00723 {
00724     if (!selected)
00725         return;
00726     if  (num >= descr.unit->num)
00727         return;
00728 
00729     if (descr.unit->unit_type_mask == utm_bitmask)
00730         mask |= descr.unit->um[num].value;
00731     else
00732         mask = descr.unit->um[num].value;
00733 }
00734 
00735 
00736 // return the unit mask selected through the unit mask check box
00737 uint oprof_start::get_unit_mask(op_event_descr const & descr)
00738 {
00739     uint mask = 0;
00740 
00741     if (!descr.unit)
00742         return 0;
00743 
00744     // mandatory mask is transparent for user.
00745     if (descr.unit->unit_type_mask == utm_mandatory) {
00746         mask = descr.unit->default_mask;
00747         return mask;
00748     }
00749 
00750     get_unit_mask_part(descr, 0, check0->isChecked(), mask);
00751     get_unit_mask_part(descr, 1, check1->isChecked(), mask);
00752     get_unit_mask_part(descr, 2, check2->isChecked(), mask);
00753     get_unit_mask_part(descr, 3, check3->isChecked(), mask);
00754     get_unit_mask_part(descr, 4, check4->isChecked(), mask);
00755     get_unit_mask_part(descr, 5, check5->isChecked(), mask);
00756     get_unit_mask_part(descr, 6, check6->isChecked(), mask);
00757     get_unit_mask_part(descr, 7, check7->isChecked(), mask);
00758     get_unit_mask_part(descr, 8, check8->isChecked(), mask);
00759     get_unit_mask_part(descr, 9, check9->isChecked(), mask);
00760     get_unit_mask_part(descr, 10, check10->isChecked(), mask);
00761     get_unit_mask_part(descr, 11, check11->isChecked(), mask);
00762     get_unit_mask_part(descr, 12, check12->isChecked(), mask);
00763     get_unit_mask_part(descr, 13, check13->isChecked(), mask);
00764     get_unit_mask_part(descr, 14, check14->isChecked(), mask);
00765     get_unit_mask_part(descr, 15, check15->isChecked(), mask);
00766     return mask;
00767 }
00768 
00769 
00770 void oprof_start::hide_masks()
00771 {
00772     check0->hide();
00773     check1->hide();
00774     check2->hide();
00775     check3->hide();
00776     check4->hide();
00777     check5->hide();
00778     check6->hide();
00779     check7->hide();
00780     check8->hide();
00781     check9->hide();
00782     check10->hide();
00783     check11->hide();
00784     check12->hide();
00785     check13->hide();
00786     check14->hide();
00787     check15->hide();
00788 }
00789 
00790 
00791 void oprof_start::setup_unit_masks(op_event_descr const & descr)
00792 {
00793     op_unit_mask const * um = descr.unit;
00794 
00795     hide_masks();
00796 
00797     if (!um || um->unit_type_mask == utm_mandatory)
00798         return;
00799 
00800     event_setting & cfg = event_cfgs[descr.name];
00801 
00802     unit_mask_group->setExclusive(um->unit_type_mask == utm_exclusive);
00803 
00804     for (size_t i = 0; i < um->num ; ++i) {
00805         QCheckBox * check = 0;
00806         switch (i) {
00807             case 0: check = check0; break;
00808             case 1: check = check1; break;
00809             case 2: check = check2; break;
00810             case 3: check = check3; break;
00811             case 4: check = check4; break;
00812             case 5: check = check5; break;
00813             case 6: check = check6; break;
00814             case 7: check = check7; break;
00815             case 8: check = check8; break;
00816             case 9: check = check9; break;
00817             case 10: check = check10; break;
00818             case 11: check = check11; break;
00819             case 12: check = check12; break;
00820             case 13: check = check13; break;
00821             case 14: check = check14; break;
00822             case 15: check = check15; break;
00823         }
00824         check->setText(um->um[i].desc);
00825         if (um->unit_type_mask == utm_exclusive)
00826             check->setChecked(cfg.umask == um->um[i].value);
00827         else
00828             check->setChecked(cfg.umask & um->um[i].value);
00829 
00830         check->show();
00831     }
00832     unit_mask_group->setMinimumSize(unit_mask_group->sizeHint());
00833     setup_config_tab->setMinimumSize(setup_config_tab->sizeHint());
00834 }
00835 
00836 
00837 uint oprof_start::max_perf_count() const
00838 {
00839     return cpu_type == CPU_RTC ? OP_MAX_RTC_COUNT : OP_MAX_PERF_COUNT;
00840 }
00841 
00842 
00843 void oprof_start::on_flush_profiler_data()
00844 {
00845     vector<string> args;
00846     args.push_back("--dump");
00847 
00848     if (daemon_status().running)
00849         do_exec_command(OP_BINDIR "/opcontrol", args);
00850     else
00851         QMessageBox::warning(this, 0, "The profiler is not started.");
00852 }
00853 
00854 
00855 // user is happy of its setting.
00856 void oprof_start::on_start_profiler()
00857 {
00858     // save the current settings
00859     record_selected_event_config();
00860 
00861     bool one_enable = false;
00862 
00863     Q3ListViewItem * cur;
00864     for (cur = events_list->firstChild(); cur; cur = cur->nextSibling()) {
00865         if (!cur->isSelected())
00866             continue;
00867 
00868         // the missing reference is intended: gcc 2.91.66 can compile
00869         // "op_event_descr const & descr = ..." w/o a warning
00870         op_event_descr const descr =
00871             locate_event(cur->text(0).latin1());
00872 
00873         event_setting & cfg = event_cfgs[cur->text(0).latin1()];
00874 
00875         one_enable = true;
00876 
00877         if (!cfg.os_ring_count && !cfg.user_ring_count) {
00878             QMessageBox::warning(this, 0, "You must select to "
00879                      "profile at least one of user binaries/kernel");
00880             return;
00881         }
00882 
00883         if (cfg.count < descr.min_count || 
00884             cfg.count > max_perf_count()) {
00885             ostringstream out;
00886 
00887             out << "event " << descr.name << " count of range: "
00888                 << cfg.count << " must be in [ "
00889                 << descr.min_count << ", "
00890                 << max_perf_count()
00891                 << "]";
00892 
00893             QMessageBox::warning(this, 0, out.str().c_str());
00894             return;
00895         }
00896 
00897         if (descr.unit &&
00898             descr.unit->unit_type_mask == utm_bitmask &&
00899             cfg.umask == 0) {
00900             ostringstream out;
00901 
00902             out << "event " << descr.name << " invalid unit mask: "
00903                 << cfg.umask << endl;
00904 
00905             QMessageBox::warning(this, 0, out.str().c_str());
00906             return;
00907         }
00908     }
00909 
00910     if (one_enable == false && cpu_type != CPU_TIMER_INT) {
00911         QMessageBox::warning(this, 0, "No counters enabled.\n");
00912         return;
00913     }
00914 
00915     if (daemon_status().running) {
00916         // gcc 2.91 work around
00917         int user_choice = 0;
00918         user_choice =
00919             QMessageBox::warning(this, 0,
00920                          "Profiler already started:\n\n"
00921                          "stop and restart it?",
00922                          "&Restart", "&Cancel", 0, 0, 1);
00923 
00924         if (user_choice == 1)
00925             return;
00926 
00927         // this flush profiler data also.
00928         on_stop_profiler();
00929     }
00930 
00931     vector<string> args;
00932 
00933     // save_config validate and setup the config
00934     if (save_config()) {
00935         // now actually start
00936         args.push_back("--start");
00937         if (config.verbose)
00938             args.push_back("--verbose");
00939         do_exec_command(OP_BINDIR "/opcontrol", args);
00940     }
00941 
00942     total_nr_interrupts = 0;
00943     timerEvent(0);
00944 }
00945 
00946 
00947 bool oprof_start::save_config()
00948 {
00949     if (!record_config())
00950         return false;
00951 
00952     vector<string> args;
00953 
00954     // saving config is done by running opcontrol --setup with appropriate
00955     // setted parameters so we use the same config file as command line
00956     // tools
00957 
00958     args.push_back("--setup");
00959 
00960     bool one_enabled = false;
00961 
00962     vector<string> tmpargs;
00963     tmpargs.push_back("--setup");
00964 
00965     Q3ListViewItem * cur;
00966     for (cur = events_list->firstChild(); cur; cur = cur->nextSibling()) {
00967         if (!cur->isSelected())
00968             continue;
00969 
00970         event_setting & cfg = event_cfgs[cur->text(0).latin1()];
00971 
00972         op_event_descr const & descr =
00973             locate_event(cur->text(0).latin1());
00974 
00975         one_enabled = true;
00976 
00977         string arg = "--event=" + descr.name;
00978         arg += ":" + op_lexical_cast<string>(cfg.count);
00979         arg += ":" + op_lexical_cast<string>(cfg.umask);
00980         arg += ":" + op_lexical_cast<string>(cfg.os_ring_count);
00981         arg += ":" + op_lexical_cast<string>(cfg.user_ring_count);
00982 
00983         tmpargs.push_back(arg);
00984     }
00985 
00986     // only set counters if at least one is enabled
00987     if (one_enabled)
00988         args = tmpargs;
00989 
00990     if (config.no_kernel) {
00991         args.push_back("--no-vmlinux");
00992     } else {
00993         args.push_back("--vmlinux=" + config.kernel_filename);
00994     }
00995 
00996     args.push_back("--buffer-size=" +
00997            op_lexical_cast<string>(config.buffer_size));
00998 
00999     if (op_get_interface() == OP_INTERFACE_24) {
01000         args.push_back("--note-table-size=" +
01001                op_lexical_cast<string>(config.note_table_size));
01002     } else {
01003         args.push_back("--buffer-watershed=" +
01004                op_lexical_cast<string>(config.buffer_watershed));
01005         args.push_back("--cpu-buffer-size=" +
01006                op_lexical_cast<string>(config.cpu_buffer_size));
01007         if (op_file_readable("/dev/oprofile/backtrace_depth")) {
01008             args.push_back("--callgraph=" +
01009                       op_lexical_cast<string>(config.callgraph_depth));
01010         }
01011     }
01012 
01013     string sep = "--separate=";
01014 
01015     if (config.separate_lib)
01016         sep += "library,";
01017     if (config.separate_kernel)
01018         sep += "kernel,";
01019     if (config.separate_cpu)
01020         sep += "cpu,";
01021     if (config.separate_thread)
01022         sep += "thread,";
01023 
01024     if (sep == "--separate=")
01025         sep += "none";
01026     args.push_back(sep);
01027 
01028     // 2.95 work-around, it didn't like return !do_exec_command() 
01029     bool ret = !do_exec_command(OP_BINDIR "/opcontrol", args);
01030     return ret;
01031 }
01032 
01033 
01034 // flush and stop the profiler if it was started.
01035 void oprof_start::on_stop_profiler()
01036 {
01037     vector<string> args;
01038     args.push_back("--shutdown");
01039 
01040     if (daemon_status().running)
01041         do_exec_command(OP_BINDIR "/opcontrol", args);
01042     else
01043         QMessageBox::warning(this, 0, "The profiler is already stopped.");
01044 
01045     timerEvent(0);
01046 }
01047 
01048 
01049 void oprof_start::on_separate_kernel_cb_changed(int state)
01050 {
01051     if (state == 2)
01052         separate_lib_cb->setChecked(true);
01053 }
01054 
01055 void oprof_start::on_reset_sample_files()
01056 {
01057     int ret = QMessageBox::warning(this, 0, "Are you sure you want to "
01058            "reset your last profile session ?", "Yes", "No", 0, 0, 1);
01059     if (!ret) {
01060         vector<string> args;
01061         args.push_back("--reset");
01062         if (!do_exec_command(OP_BINDIR "/opcontrol", args))
01063             // the next timer event will overwrite the message
01064             daemon_label->setText("Last profile session reseted.");
01065         else
01066             QMessageBox::warning(this, 0,
01067                  "Can't reset profiling session.");
01068     }
01069 }
01070 
01071 
01073 class event_name_eq {
01074     string name_;
01075 public:
01076     explicit event_name_eq(string const & s) : name_(s) {}
01077     bool operator()(op_event_descr const & d) const {
01078         return d.name == name_;
01079     }
01080 };
01081 
01082 
01083 // helper to retrieve an event descr through its name.
01084 op_event_descr const & oprof_start::locate_event(string const & name) const
01085 {
01086     return *(find_if(v_events.begin(), v_events.end(), event_name_eq(name)));
01087 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1