QBenchlib: pass the metric type alongside the measurement value

And pass the value in a qreal, which is what QBenchlib stores
anyway. This increases the code size a little because the conversion
from integer to qreal is in multiple places, but doesn't meaningfully
increase the overhead: in the SysV ABI, we still return Measurement in
registers and even using the floating point registers where applicable.

This is the first step in allowing the Perf benchmarker to benchmark more
than one event.

Change-Id: I3c79b7e08fa346988dfefffd172027a8677f17c0
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Thiago Macieira 2022-10-21 11:04:26 -07:00
parent 0f55580ec5
commit 985b942152
11 changed files with 46 additions and 72 deletions

View File

@ -96,8 +96,8 @@ int QBenchmarkTestMethodData::adjustIterationCount(int suggestion)
return iterationCount;
}
void QBenchmarkTestMethodData::setResult(
qreal value, QTest::QBenchmarkMetric metric, bool setByMacro)
void QBenchmarkTestMethodData::setResult(QBenchmarkMeasurerBase::Measurement m,
bool setByMacro)
{
bool accepted = false;
@ -114,9 +114,9 @@ void QBenchmarkTestMethodData::setResult(
// Test the result directly without calling the measurer if the minimum time
// has been specified on the command line with -minimumvalue.
else if (QBenchmarkGlobalData::current->walltimeMinimum != -1)
accepted = (value > QBenchmarkGlobalData::current->walltimeMinimum);
accepted = (m.value > QBenchmarkGlobalData::current->walltimeMinimum);
else
accepted = QBenchmarkGlobalData::current->measurer->isMeasurementAccepted(value);
accepted = QBenchmarkGlobalData::current->measurer->isMeasurementAccepted(m);
// Accept the result or double the number of iterations.
if (accepted)
@ -125,7 +125,7 @@ void QBenchmarkTestMethodData::setResult(
iterationCount *= 2;
this->result = QBenchmarkResult(
QBenchmarkGlobalData::current->context, value, iterationCount, metric, setByMacro);
QBenchmarkGlobalData::current->context, m.value, iterationCount, m.metric, setByMacro);
}
/*!
@ -157,8 +157,8 @@ QTest::QBenchmarkIterationController::QBenchmarkIterationController()
*/
QTest::QBenchmarkIterationController::~QBenchmarkIterationController()
{
const qreal result = QTest::endBenchmarkMeasurement();
QBenchmarkTestMethodData::current->setResult(result, QBenchmarkGlobalData::current->measurer->metricType());
QBenchmarkMeasurerBase::Measurement measurement = QTest::endBenchmarkMeasurement();
QBenchmarkTestMethodData::current->setResult(measurement);
}
/*! \internal
@ -209,7 +209,7 @@ void QTest::beginBenchmarkMeasurement()
/*! \internal
*/
quint64 QTest::endBenchmarkMeasurement()
QBenchmarkMeasurerBase::Measurement QTest::endBenchmarkMeasurement()
{
// the clock is ticking before the line below, don't add code here.
return QBenchmarkGlobalData::current->measurer->stop();
@ -234,7 +234,7 @@ quint64 QTest::endBenchmarkMeasurement()
*/
void QTest::setBenchmarkResult(qreal result, QTest::QBenchmarkMetric metric)
{
QBenchmarkTestMethodData::current->setResult(result, metric, false);
QBenchmarkTestMethodData::current->setResult({ result, metric }, false);
}
template <typename T>

View File

@ -139,7 +139,7 @@ public:
bool isBenchmark() const { return result.valid; }
bool resultsAccepted() const { return resultAccepted; }
int adjustIterationCount(int suggestion);
void setResult(qreal value, QTest::QBenchmarkMetric metric, bool setByMacro = true);
void setResult(QBenchmarkMeasurerBase::Measurement m, bool setByMacro = true);
QBenchmarkResult result;
bool resultAccepted = false;
@ -155,7 +155,7 @@ namespace QTest
void setIterationCount(int count);
void beginBenchmarkMeasurement();
quint64 endBenchmarkMeasurement();
QBenchmarkMeasurerBase::Measurement endBenchmarkMeasurement();
}
QT_END_NAMESPACE

View File

@ -18,16 +18,16 @@ void QBenchmarkEvent::start()
QAbstractEventDispatcher::instance()->installNativeEventFilter(this);
}
qint64 QBenchmarkEvent::stop()
QBenchmarkMeasurerBase::Measurement QBenchmarkEvent::stop()
{
QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
return eventCounter;
return { qreal(eventCounter), QTest::Events };
}
// It's very tempting to simply reject a measurement if 0 events
// where counted, however that is a possible situation and returning
// false here will create a infinite loop. Do not change this.
bool QBenchmarkEvent::isMeasurementAccepted(qint64 measurement)
bool QBenchmarkEvent::isMeasurementAccepted(QBenchmarkMeasurerBase::Measurement measurement)
{
Q_UNUSED(measurement);
return true;
@ -44,11 +44,6 @@ int QBenchmarkEvent::adjustMedianCount(int suggestion)
return 1;
}
QTest::QBenchmarkMetric QBenchmarkEvent::metricType()
{
return QTest::Events;
}
// This could be done in a much better way, this is just the beginning.
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool QBenchmarkEvent::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result)

View File

@ -28,11 +28,10 @@ public:
QBenchmarkEvent();
~QBenchmarkEvent();
void start() override;
qint64 stop() override;
bool isMeasurementAccepted(qint64 measurement) override;
Measurement stop() override;
bool isMeasurementAccepted(Measurement measurement) override;
int adjustIterationCount(int suggestion) override;
int adjustMedianCount(int suggestion) override;
QTest::QBenchmarkMetric metricType() override;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override;
#else

View File

@ -16,14 +16,14 @@ void QBenchmarkTimeMeasurer::start()
time.start();
}
qint64 QBenchmarkTimeMeasurer::stop()
QBenchmarkMeasurerBase::Measurement QBenchmarkTimeMeasurer::stop()
{
return time.elapsed();
return { qreal(time.elapsed()), QTest::WalltimeMilliseconds };
}
bool QBenchmarkTimeMeasurer::isMeasurementAccepted(qint64 measurement)
bool QBenchmarkTimeMeasurer::isMeasurementAccepted(Measurement measurement)
{
return (measurement > 50);
return (measurement.value > 50);
}
int QBenchmarkTimeMeasurer::adjustIterationCount(int suggestion)
@ -41,11 +41,6 @@ int QBenchmarkTimeMeasurer::adjustMedianCount(int)
return 1;
}
QTest::QBenchmarkMetric QBenchmarkTimeMeasurer::metricType()
{
return QTest::WalltimeMilliseconds;
}
#ifdef HAVE_TICK_COUNTER // defined in 3rdparty/cycle_p.h
void QBenchmarkTickMeasurer::start()
@ -53,13 +48,13 @@ void QBenchmarkTickMeasurer::start()
startTicks = getticks();
}
qint64 QBenchmarkTickMeasurer::stop()
QBenchmarkMeasurerBase::Measurement QBenchmarkTickMeasurer::stop()
{
CycleCounterTicks now = getticks();
return qRound64(elapsed(now, startTicks));
return { elapsed(now, startTicks), QTest::CPUTicks };
}
bool QBenchmarkTickMeasurer::isMeasurementAccepted(qint64)
bool QBenchmarkTickMeasurer::isMeasurementAccepted(QBenchmarkMeasurerBase::Measurement)
{
return true;
}
@ -79,11 +74,6 @@ bool QBenchmarkTickMeasurer::needsWarmupIteration()
return true;
}
QTest::QBenchmarkMetric QBenchmarkTickMeasurer::metricType()
{
return QTest::CPUTicks;
}
#endif

View File

@ -23,15 +23,19 @@ QT_BEGIN_NAMESPACE
class QBenchmarkMeasurerBase
{
public:
struct Measurement
{
qreal value;
QTest::QBenchmarkMetric metric;
};
virtual ~QBenchmarkMeasurerBase() = default;
virtual void init() {}
virtual void start() = 0;
virtual qint64 stop() = 0;
virtual bool isMeasurementAccepted(qint64 measurement) = 0;
virtual Measurement stop() = 0;
virtual bool isMeasurementAccepted(Measurement m) = 0;
virtual int adjustIterationCount(int suggestion) = 0;
virtual int adjustMedianCount(int suggestion) = 0;
virtual bool needsWarmupIteration() { return false; }
virtual QTest::QBenchmarkMetric metricType() = 0;
};
QT_END_NAMESPACE

View File

@ -474,14 +474,14 @@ void QBenchmarkPerfEventsMeasurer::start()
::ioctl(fd, PERF_EVENT_IOC_ENABLE);
}
qint64 QBenchmarkPerfEventsMeasurer::stop()
QBenchmarkMeasurerBase::Measurement QBenchmarkPerfEventsMeasurer::stop()
{
// disable the counter
::ioctl(fd, PERF_EVENT_IOC_DISABLE);
return readValue();
}
bool QBenchmarkPerfEventsMeasurer::isMeasurementAccepted(qint64)
bool QBenchmarkPerfEventsMeasurer::isMeasurementAccepted(Measurement)
{
return true;
}
@ -496,11 +496,6 @@ int QBenchmarkPerfEventsMeasurer::adjustMedianCount(int)
return 1;
}
QTest::QBenchmarkMetric QBenchmarkPerfEventsMeasurer::metricType()
{
return metricForEvent(attr.type, attr.config);
}
static quint64 rawReadValue(int fd)
{
/* from the kernel docs:
@ -536,10 +531,10 @@ static quint64 rawReadValue(int fd)
return results.value * (double(results.time_running) / double(results.time_enabled));
}
qint64 QBenchmarkPerfEventsMeasurer::readValue()
QBenchmarkMeasurerBase::Measurement QBenchmarkPerfEventsMeasurer::readValue()
{
quint64 raw = rawReadValue(fd);
return raw;
return { qreal(qint64(raw)), metricForEvent(attr.type, attr.config) };
}
QT_END_NAMESPACE

View File

@ -26,12 +26,11 @@ public:
~QBenchmarkPerfEventsMeasurer();
void init() override;
void start() override;
qint64 stop() override;
bool isMeasurementAccepted(qint64 measurement) override;
Measurement stop() override;
bool isMeasurementAccepted(Measurement measurement) override;
int adjustIterationCount(int suggestion) override;
int adjustMedianCount(int suggestion) override;
bool needsWarmupIteration() override { return true; }
QTest::QBenchmarkMetric metricType() override;
static bool isAvailable();
static QTest::QBenchmarkMetric metricForEvent(quint32 type, quint64 event_id);
@ -40,7 +39,7 @@ public:
private:
int fd = -1;
qint64 readValue();
Measurement readValue();
};
QT_END_NAMESPACE

View File

@ -25,12 +25,11 @@ class QBenchmarkTimeMeasurer : public QBenchmarkMeasurerBase
{
public:
void start() override;
qint64 stop() override;
bool isMeasurementAccepted(qint64 measurement) override;
Measurement stop() override;
bool isMeasurementAccepted(Measurement measurement) override;
int adjustIterationCount(int sugestion) override;
int adjustMedianCount(int suggestion) override;
bool needsWarmupIteration() override;
QTest::QBenchmarkMetric metricType() override;
private:
QElapsedTimer time;
};
@ -41,12 +40,11 @@ class QBenchmarkTickMeasurer : public QBenchmarkMeasurerBase
{
public:
void start() override;
qint64 stop() override;
bool isMeasurementAccepted(qint64 measurement) override;
Measurement stop() override;
bool isMeasurementAccepted(Measurement measurement) override;
int adjustIterationCount(int) override;
int adjustMedianCount(int suggestion) override;
bool needsWarmupIteration() override;
QTest::QBenchmarkMetric metricType() override;
private:
CycleCounterTicks startTicks;
};

View File

@ -170,14 +170,14 @@ void QBenchmarkCallgrindMeasurer::start()
CALLGRIND_ZERO_STATS;
}
qint64 QBenchmarkCallgrindMeasurer::stop()
QBenchmarkMeasurerBase::Measurement QBenchmarkCallgrindMeasurer::stop()
{
CALLGRIND_DUMP_STATS;
const qint64 result = QBenchmarkValgrindUtils::extractLastResult();
return result;
return { qreal(result), QTest::InstructionReads };
}
bool QBenchmarkCallgrindMeasurer::isMeasurementAccepted(qint64 measurement)
bool QBenchmarkCallgrindMeasurer::isMeasurementAccepted(Measurement measurement)
{
Q_UNUSED(measurement);
return true;
@ -198,9 +198,4 @@ bool QBenchmarkCallgrindMeasurer::needsWarmupIteration()
return true;
}
QTest::QBenchmarkMetric QBenchmarkCallgrindMeasurer::metricType()
{
return QTest::InstructionReads;
}
QT_END_NAMESPACE

View File

@ -41,12 +41,11 @@ class QBenchmarkCallgrindMeasurer : public QBenchmarkMeasurerBase
{
public:
void start() override;
qint64 stop() override;
bool isMeasurementAccepted(qint64 measurement) override;
Measurement stop() override;
bool isMeasurementAccepted(Measurement measurement) override;
int adjustIterationCount(int) override;
int adjustMedianCount(int) override;
bool needsWarmupIteration() override;
QTest::QBenchmarkMetric metricType() override;
};
QT_END_NAMESPACE