| // SPDX-License-Identifier: LGPL-2.1 |
| |
| /* |
| * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <ykaradzhov@vmware.com> |
| */ |
| |
| /** |
| * @file KsDualMarker.cpp |
| * @brief KernelShark Dual Marker. |
| */ |
| |
| #include "KsDualMarker.hpp" |
| #include "KsGLWidget.hpp" |
| |
| /** |
| * @brief Create KsGraphMark object. |
| * |
| * @param s: The Identifier of the marker (state A or state B). |
| */ |
| KsGraphMark::KsGraphMark(DualMarkerState s) |
| : _color(Qt::darkGreen), |
| _state(s) |
| { |
| reset(); |
| _mark._color << _color; |
| } |
| |
| /** |
| * @brief Create KsGraphMark object. |
| * |
| * @param s: The Identifier of the marker (state A or state B). |
| * @param col: The color of the marker. |
| */ |
| KsGraphMark::KsGraphMark(DualMarkerState s, QColor col) |
| : _color(col), |
| _state(s) |
| { |
| reset(); |
| _mark._color << _color; |
| } |
| |
| /** Reset the marker. */ |
| void KsGraphMark::reset() |
| { |
| _isSet = false; |
| _bin = -1; |
| _cpu = -1; |
| _task = -1; |
| _pos = 0; |
| |
| _mark._visible = false; |
| } |
| |
| /** |
| * @brief Set the marker. |
| * |
| * @param data: Input location for the Data Store object. |
| * @param histo: Input location for the model descriptor. |
| * @param pos: The index inside the data array this marker will points to. |
| * @param cpuGraph: The index of the CPU Graph this marker points to. |
| * @param taskGraph: The index of the Task Graph this marker points to. |
| */ |
| bool KsGraphMark::set(const KsDataStore &data, |
| kshark_trace_histo *histo, |
| size_t pos, int cpuGraph, int taskGraph) |
| { |
| _isSet = true; |
| _pos = pos; |
| _ts = data.rows()[_pos]->ts; |
| _cpu = cpuGraph; |
| _task = taskGraph; |
| |
| if (_ts > histo->max || _ts < histo->min) { |
| _bin = -1; |
| _mark._visible = false; |
| return false; |
| } |
| |
| _bin = (_ts - histo->min)/histo->bin_size; |
| setVisible(true); |
| |
| return true; |
| } |
| |
| /** |
| * @brief Use this function to update the marker when the state of the model |
| * has changed. |
| * |
| * @param data: Input location for the Data Store object. |
| * @param histo: Input location for the model descriptor. |
| */ |
| bool KsGraphMark::update(const KsDataStore &data, kshark_trace_histo *histo) |
| { |
| if (!_isSet) |
| return false; |
| |
| return set(data, histo, this->_pos, this->_cpu, this->_task); |
| } |
| |
| /** Unset the Marker and make it invisible. */ |
| void KsGraphMark::remove() |
| { |
| _isSet = false; |
| setVisible(false); |
| } |
| |
| /** An operator for getting the opposite state of the marker identifier. */ |
| DualMarkerState operator!(const DualMarkerState &state) |
| { |
| if (state == DualMarkerState::B) |
| return DualMarkerState::A; |
| |
| return DualMarkerState::B; |
| } |
| |
| /** @brief Create a Dual Marker State Machine. */ |
| KsDualMarkerSM::KsDualMarkerSM(QWidget *parent) |
| : QWidget(parent), |
| _buttonA("Marker A", this), |
| _buttonB("Marker B", this), |
| _labelDeltaDescr(" A,B Delta: ", this), |
| _markA(DualMarkerState::A, Qt::darkGreen), |
| _markB(DualMarkerState::B, Qt::darkCyan), |
| _scCtrlA(this), |
| _scCtrlB(this) |
| { |
| QString styleSheetA, styleSheetB; |
| |
| _buttonA.setFixedWidth(STRING_WIDTH(" Marker A ")); |
| _buttonB.setFixedWidth(STRING_WIDTH(" Marker B ")); |
| |
| for (auto const &l: {&_labelMA, &_labelMB, &_labelDelta}) { |
| l->setFrameStyle(QFrame::Panel | QFrame::Sunken); |
| l->setStyleSheet("QLabel {background-color : white;}"); |
| l->setTextInteractionFlags(Qt::TextSelectableByMouse); |
| l->setFixedWidth(FONT_WIDTH * 16); |
| } |
| |
| styleSheetA = "background : " + |
| _markA._color.name() + |
| "; color : white"; |
| |
| _stateA = new QState; |
| _stateA->setObjectName("A"); |
| _stateA->assignProperty(&_buttonA, |
| "styleSheet", |
| styleSheetA); |
| |
| _stateA->assignProperty(&_buttonB, |
| "styleSheet", |
| "color : rgb(70, 70, 70)"); |
| |
| styleSheetB = "background : " + |
| _markB._color.name() + |
| "; color : white"; |
| |
| _stateB = new QState; |
| _stateB->setObjectName("B"); |
| _stateB->assignProperty(&_buttonA, |
| "styleSheet", |
| "color : rgb(70, 70, 70)"); |
| |
| _stateB->assignProperty(&_buttonB, |
| "styleSheet", |
| styleSheetB); |
| |
| /* Define transitions from State A to State B. */ |
| _stateA->addTransition(this, &KsDualMarkerSM::machineToB, _stateB); |
| |
| _scCtrlA.setKey(Qt::CTRL + Qt::Key_A); |
| _stateA->addTransition(&_scCtrlB, &QShortcut::activated, _stateB); |
| |
| connect(&_scCtrlA, &QShortcut::activated, |
| this, &KsDualMarkerSM::_doStateA); |
| |
| _stateA->addTransition(&_buttonB, &QPushButton::clicked, _stateB); |
| |
| connect(&_buttonB, &QPushButton::clicked, |
| this, &KsDualMarkerSM::_doStateB); |
| |
| /* Define transitions from State B to State A. */ |
| _stateB->addTransition(this, &KsDualMarkerSM::machineToA, _stateA); |
| |
| _scCtrlB.setKey(Qt::CTRL + Qt::Key_B); |
| _stateB->addTransition(&_scCtrlA, &QShortcut::activated, _stateA); |
| |
| connect(&_scCtrlB, &QShortcut::activated, |
| this, &KsDualMarkerSM::_doStateB); |
| |
| _stateB->addTransition(&_buttonA, &QPushButton::clicked, _stateA); |
| |
| connect(&_buttonA, &QPushButton::clicked, |
| this, &KsDualMarkerSM::_doStateA); |
| |
| _machine.addState(_stateA); |
| _machine.addState(_stateB); |
| _machine.setInitialState(_stateA); |
| _markState = DualMarkerState::A; |
| _machine.start(); |
| } |
| |
| /** |
| * Reset the Mark A and Mark B and clear the information shown by the Marker's |
| * toolbar. |
| */ |
| void KsDualMarkerSM::reset() |
| { |
| _markA.reset(); |
| _markB.reset(); |
| _labelMA.setText(""); |
| _labelMB.setText(""); |
| _labelDelta.setText(""); |
| } |
| |
| /** Restart the Dual Marker State Machine. */ |
| void KsDualMarkerSM::restart() |
| { |
| _machine.stop(); |
| reset(); |
| _markState = DualMarkerState::A; |
| _machine.start(); |
| } |
| |
| void KsDualMarkerSM::_doStateA() |
| { |
| if (_markState != DualMarkerState::A) { |
| _markState = DualMarkerState::A; |
| emit markSwitchForView(); |
| } else if (activeMarker()._isSet) { |
| emit updateView(activeMarker()._pos, true); |
| emit updateGraph(activeMarker()._pos); |
| } |
| } |
| |
| void KsDualMarkerSM::_doStateB() |
| { |
| if (_markState != DualMarkerState::B) { |
| _markState = DualMarkerState::B; |
| emit markSwitchForView(); |
| } else if (activeMarker()._isSet) { |
| emit updateView(activeMarker()._pos, true); |
| emit updateGraph(activeMarker()._pos); |
| } |
| } |
| |
| /** Get the Graph marker associated with a given state. */ |
| KsGraphMark &KsDualMarkerSM::getMarker(DualMarkerState s) |
| { |
| if (s == DualMarkerState::A) |
| return _markA; |
| |
| return _markB; |
| } |
| |
| /** Position all buttons and labels of the Dual Marker in a toolbar. */ |
| void KsDualMarkerSM::placeInToolBar(QToolBar *tb) |
| { |
| tb->addWidget(new QLabel(" ")); |
| tb->addWidget(&_buttonA); |
| tb->addWidget(&_labelMA); |
| tb->addSeparator(); |
| tb->addWidget(new QLabel(" ")); |
| tb->addWidget(&_buttonB); |
| tb->addWidget(&_labelMB); |
| tb->addSeparator(); |
| tb->addWidget(&_labelDeltaDescr); |
| tb->addWidget(&_labelDelta); |
| } |
| |
| /** Set the state of the Dual Marker State Machine. */ |
| void KsDualMarkerSM::setState(DualMarkerState st) { |
| if (st == _markState) |
| return; |
| |
| if (st == DualMarkerState::A) { |
| emit machineToA(); |
| _doStateA(); |
| } |
| |
| if (st == DualMarkerState::B) { |
| emit machineToB(); |
| _doStateB(); |
| } |
| } |
| |
| /** |
| * @brief Use this function to update the two marker when the state of the |
| * model has changed. |
| * |
| * @param data: Input location for the Data Store object. |
| * @param glw: Input location for the OpenGL widget object. |
| */ |
| void KsDualMarkerSM::updateMarkers(const KsDataStore &data, |
| KsGLWidget *glw) |
| { |
| if(_markA.update(data, glw->model()->histo())) |
| glw->setMark(&_markA); |
| |
| if(_markB.update(data, glw->model()->histo())) |
| glw->setMark(&_markB); |
| |
| updateLabels(); |
| } |
| |
| /** |
| * @brief Use this function to update the labels when the state of the model |
| * has changed. |
| */ |
| void KsDualMarkerSM::updateLabels() |
| { |
| QString mark, delta; |
| |
| // Marker A |
| if (_markA._isSet) { |
| mark = KsUtils::Ts2String(_markA._ts, 7); |
| _labelMA.setText(mark); |
| } else { |
| _labelMA.setText(""); |
| } |
| |
| // Marker B |
| if (_markB._isSet) { |
| mark = KsUtils::Ts2String(_markB._ts, 7); |
| _labelMB.setText(mark); |
| } else { |
| _labelMB.setText(""); |
| } |
| |
| // Delta |
| if (_markA._isSet && _markB._isSet) { |
| delta = KsUtils::Ts2String(_markB._ts - _markA._ts, 7); |
| _labelDelta.setText(delta); |
| } else { |
| _labelDelta.setText(""); |
| } |
| } |