Control cache plot range with range slider
MODIFY
src/cachesim/cacheplotview.cpp
src/cachesim/cacheplotview.cpp
@@ -160,8 +160,8 @@ void CachePlotView::resizeObjects(const QSizeF& size) {
}
const int y = yOffset + m_chart->size().height() - 20;
marker->label->setPos(m_chart->size().width() / 4 - marker->label->boundingRect().width(), y);
- marker->coordX->setPos(m_chart->size().width() / 3, y);
- marker->coordY->setPos(m_chart->size().width() / 2, y);
+ marker->coordX->setPos(m_chart->size().width() * 0.33, y);
+ marker->coordY->setPos(m_chart->size().width() * 0.55, y);
marker->marker->updateLines();
}
}

MODIFY
src/cachesim/cacheplotwidget.cpp
src/cachesim/cacheplotwidget.cpp
@@ -41,6 +41,8 @@ CachePlotWidget::CachePlotWidget(QWidget* parent) : QWidget(parent), m_ui(new Ui
setEnumIndex(m_ui->num, Variable::Hits);
setEnumIndex(m_ui->den, Variable::Accesses);
+ m_rangeWidgets = {m_ui->rangeMax, m_ui->rangeMin, m_ui->rangeSlider};
+
connect(m_ui->num, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CachePlotWidget::variablesChanged);
connect(m_ui->den, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CachePlotWidget::variablesChanged);
connect(m_ui->windowed, &QCheckBox::toggled, this, &CachePlotWidget::variablesChanged);
@@ -49,8 +51,11 @@ CachePlotWidget::CachePlotWidget(QWidget* parent) : QWidget(parent), m_ui(new Ui
m_ui->rangeMin->setValue(0);
m_ui->rangeMax->setValue(ProcessorHandler::getProcessor()->getCycleCount());
- connect(m_ui->rangeMin, QOverload<int>::of(&QSpinBox::valueChanged), this, &CachePlotWidget::rangeChanged);
- connect(m_ui->rangeMax, QOverload<int>::of(&QSpinBox::valueChanged), this, &CachePlotWidget::rangeChanged);
+ connect(m_ui->rangeMin, QOverload<int>::of(&QSpinBox::valueChanged),
+ [=] { rangeChanged(RangeChangeSource::Comboboxes); });
+ connect(m_ui->rangeMax, QOverload<int>::of(&QSpinBox::valueChanged),
+ [=] { rangeChanged(RangeChangeSource::Comboboxes); });
+ connect(m_ui->rangeSlider, &ctkRangeSlider::valuesChanged, [=] { rangeChanged(RangeChangeSource::Slider); });
const QIcon sizeBreakdownIcon = QIcon(":/icons/info.svg");
m_ui->sizeBreakdownButton->setIcon(sizeBreakdownIcon);
@@ -82,15 +87,15 @@ void CachePlotWidget::setCache(std::shared_ptr<CacheSim> cache) {
m_ui->size->setText(QString::number(m_cache->getCacheSize().bits));
connect(ProcessorHandler::get(), &ProcessorHandler::processorClockedNonRun, [=] {
- updateAllowedRange();
+ updateAllowedRange(RangeChangeSource::Cycles);
updateRatioPlot();
});
connect(ProcessorHandler::get(), &ProcessorHandler::runFinished, [=] {
- updateAllowedRange();
+ updateAllowedRange(RangeChangeSource::Cycles);
updateRatioPlot();
});
connect(m_cache.get(), &CacheSim::cacheInvalidated, [=] {
- updateAllowedRange();
+ updateAllowedRange(RangeChangeSource::Cycles);
resetRatioPlot();
});
@@ -112,17 +117,48 @@ void CachePlotWidget::setCache(std::shared_ptr<CacheSim> cache) {
setupPlotActions();
variablesChanged();
- rangeChanged();
+ rangeChanged(RangeChangeSource::Comboboxes);
updateHitrate();
}
-void CachePlotWidget::updateAllowedRange() {
+void CachePlotWidget::updateAllowedRange(const RangeChangeSource src) {
+ // Block all range signals while changing ranges
+ for (const auto& w : m_rangeWidgets) {
+ w->blockSignals(true);
+ }
+
// Update allowed ranges
const unsigned cycles = ProcessorHandler::getProcessor()->getCycleCount();
- m_ui->rangeMax->setMinimum(m_ui->rangeMin->value());
- m_ui->rangeMax->setMaximum(cycles);
+
+ bool atMax = false;
+
+ if (src == RangeChangeSource::Cycles) {
+ atMax = m_ui->rangeSlider->maximumPosition() == m_ui->rangeSlider->maximum();
+ }
+
m_ui->rangeMin->setMinimum(0);
- m_ui->rangeMin->setMaximum(m_ui->rangeMax->value());
+ m_ui->rangeSlider->setMinimum(0);
+ m_ui->rangeSlider->setMaximum(cycles);
+ m_ui->rangeMax->setMaximum(cycles);
+
+ if (src == RangeChangeSource::Comboboxes) {
+ m_ui->rangeSlider->setMinimumPosition(m_ui->rangeMin->value());
+ m_ui->rangeSlider->setMaximumPosition(m_ui->rangeMax->value());
+ } else if (src == RangeChangeSource::Slider) {
+ m_ui->rangeMax->setMinimum(m_ui->rangeSlider->minimumValue());
+ m_ui->rangeMin->setMaximum(m_ui->rangeSlider->maximumValue());
+ m_ui->rangeMin->setValue(m_ui->rangeSlider->minimumPosition());
+ m_ui->rangeMax->setValue(m_ui->rangeSlider->maximumPosition());
+ }
+
+ if (atMax) {
+ m_ui->rangeSlider->setMaximumPosition(cycles);
+ m_ui->rangeMax->setValue(cycles);
+ }
+
+ for (const auto& w : m_rangeWidgets) {
+ w->blockSignals(false);
+ }
}
CachePlotWidget::~CachePlotWidget() {
@@ -211,11 +247,11 @@ void CachePlotWidget::copyPlotDataToClipboard() const {
QApplication::clipboard()->setText(outString);
}
-void CachePlotWidget::rangeChanged() {
+void CachePlotWidget::rangeChanged(const RangeChangeSource src) {
+ updateAllowedRange(src);
if (m_plot) {
m_plot->axes(Qt::Horizontal).first()->setRange(m_ui->rangeMin->value(), m_ui->rangeMax->value());
}
- updateAllowedRange();
}
void CachePlotWidget::variablesChanged() {
@@ -377,12 +413,11 @@ void CachePlotWidget::updateRatioPlot() {
m_plot->createDefaultAxes();
- const unsigned maxX = ProcessorHandler::getProcessor()->getCycleCount();
-
// Add space to label to add space between labels and axis
QValueAxis* axisY = qobject_cast<QValueAxis*>(m_series->chart()->axes(Qt::Vertical).first());
QValueAxis* axisX = qobject_cast<QValueAxis*>(m_series->chart()->axes(Qt::Horizontal).first());
Q_ASSERT(axisY);
+ Q_ASSERT(axisX);
axisY->setLabelFormat("%.1f ");
axisY->setTitleText("%");
int tickInterval = (m_maxY - m_minY) / axisY->tickCount();
@@ -397,11 +432,11 @@ void CachePlotWidget::updateRatioPlot() {
axisMaxY = 100;
}
- axisY->setRange(m_minY, axisMaxY);
-
axisX->setLabelFormat("%d ");
axisX->setTitleText("Cycle");
- axisX->setRange(0, maxX);
+
+ axisY->setRange(m_minY, axisMaxY);
+ axisX->setRange(m_ui->rangeSlider->minimumPosition(), m_ui->rangeSlider->maximumPosition());
}
void CachePlotWidget::resetRatioPlot() {

MODIFY
src/cachesim/cacheplotwidget.h
src/cachesim/cacheplotwidget.h
@@ -43,6 +43,8 @@ class CachePlotWidget;
class CachePlotWidget : public QWidget {
Q_OBJECT
+ enum class RangeChangeSource { Slider, Comboboxes, Cycles };
+
public:
enum Variable { Writes = 0, Reads, Hits, Misses, Writebacks, Accesses, N_TraceVars, Unary };
explicit CachePlotWidget(QWidget* parent = nullptr);
@@ -53,7 +55,7 @@ public slots:
private slots:
void variablesChanged();
- void rangeChanged();
+ void rangeChanged(const RangeChangeSource src);
void updateHitrate();
private:
@@ -68,7 +70,7 @@ private:
void copyPlotDataToClipboard() const;
void savePlot();
void updateRatioPlot();
- void updateAllowedRange();
+ void updateAllowedRange(const RangeChangeSource src);
/**
* @brief resampleToScreen
@@ -101,6 +103,8 @@ private:
QAction* m_savePlotAction = nullptr;
QAction* m_totalMarkerAction = nullptr;
QAction* m_mavgMarkerAction = nullptr;
+
+ std::vector<QWidget*> m_rangeWidgets;
};
const static std::map<CachePlotWidget::Variable, QString> s_cacheVariableStrings{

MODIFY
src/cachesim/cacheplotwidget.ui
src/cachesim/cacheplotwidget.ui
<number>0</number>
</property>
<item row="0" column="0">
- <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,1,0">
+ <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,1,0,0">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_2">
- <item row="1" column="3">
- <widget class="QComboBox" name="den"/>
- </item>
- <item row="0" column="2">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Numerator</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QSpinBox" name="rangeMax">
- <property name="maximum">
- <number>999999999</number>
- </property>
- </widget>
- </item>
<item row="1" column="2">
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>Denominator</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="label_6">
- <property name="text">
- <string>Cycles min.</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_7">
- <property name="text">
- <string>Cycles max.</string>
- </property>
- </widget>
- </item>
- <item row="0" column="3">
- <widget class="QComboBox" name="num"/>
- </item>
- <item row="0" column="1">
- <widget class="QSpinBox" name="rangeMin">
- <property name="maximum">
- <number>999999999</number>
- </property>
- </widget>
+ <widget class="QComboBox" name="den"/>
</item>
- <item row="2" column="0">
+ <item row="2" column="1">
<widget class="QCheckBox" name="windowed">
<property name="text">
<string>Moving avg.</string>
</property>
</widget>
</item>
- <item row="2" column="1">
+ <item row="0" column="2">
+ <widget class="QComboBox" name="num"/>
+ </item>
+ <item row="2" column="2">
<widget class="QSpinBox" name="windowCycles">
<property name="enabled">
<bool>true</bool>
</property>
+ <property name="suffix">
+ <string> cyc.</string>
+ </property>
<property name="minimum">
<number>1</number>
</property>
</property>
</widget>
</item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Denominator</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Numerator</string>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
</layout>
<item>
<widget class="CachePlotView" name="plotView"/>
</item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,1,0">
+ <item>
+ <widget class="QSpinBox" name="rangeMin">
+ <property name="toolTip">
+ <string>Min. cycle</string>
+ </property>
+ <property name="maximum">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="ctkRangeSlider" name="rangeSlider">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Plot range (cycles)</string>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="rangeMax">
+ <property name="toolTip">
+ <string>Max. cycle</string>
+ </property>
+ <property name="maximum">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<extends>QGraphicsView</extends>
<header>cachesim/cacheplotview.h</header>
</customwidget>
+ <customwidget>
+ <class>ctkRangeSlider</class>
+ <extends>QSlider</extends>
+ <header>ctkrangeslider.h</header>
+ </customwidget>
</customwidgets>
<resources/>
<connections/>

Control cache plot range with range slider