summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjasplin <qt-info@nokia.com>2010-05-06 09:52:57 +0200
committerjasplin <qt-info@nokia.com>2010-05-06 09:52:57 +0200
commit856f10686aaebe984ccc4befdd1fdb08422472dd (patch)
tree3fa2c3c475bb2d219685944ce8939d313ec2c39d
parentea257f657659a1baf6a282c5f725f82bdb7856fa (diff)
Highlight outliers in index contributor graphs.
-rw-r--r--src/bm/bmrequest.cpp70
-rw-r--r--src/bm/bmrequest.h8
-rw-r--r--src/bm/plotter.cpp25
-rw-r--r--src/bm/plotter.h3
-rw-r--r--src/bm/resulthistoryinfo.cpp15
-rw-r--r--src/bm/resulthistoryinfo.h2
-rw-r--r--src/bmclient/main.cpp16
7 files changed, 103 insertions, 36 deletions
diff --git a/src/bm/bmrequest.cpp b/src/bm/bmrequest.cpp
index 95bb7cb..50c05a4 100644
--- a/src/bm/bmrequest.cpp
+++ b/src/bm/bmrequest.cpp
@@ -5265,6 +5265,12 @@ void BMRequest_IndexGetValues::handleReply_HTML(const QStringList &args) const
QDomElement argsElem = doc.elementsByTagName("args").at(0).toElement();
+ bool ok;
+
+ // Get median window size ...
+ medianWinSize = argsElem.attributeNode("medianWinSize").value().toInt(&ok);
+ Q_ASSERT(ok);
+
// *** Plot ***
@@ -5287,7 +5293,6 @@ void BMRequest_IndexGetValues::handleReply_HTML(const QStringList &args) const
// Image map ...
reply += "<br />\n<map name=\"plotmap\">\n";
- bool ok;
// ... get timestamps, index values, and contributions ...
QList<int> timestamps;
@@ -5330,6 +5335,7 @@ void BMRequest_IndexGetValues::handleReply_HTML(const QStringList &args) const
}
const QString webServer = rx.cap(1);
+
// ... add <area> tags for valid points ...
for (int i = 0; i < pointInfos.size(); ++i) {
@@ -5345,7 +5351,8 @@ void BMRequest_IndexGetValues::handleReply_HTML(const QStringList &args) const
url = QString("%1/cgi-bin/bmclientwrapper").arg(webServer);
url += QString("?command=-server %1").arg(server);
url += QString(" get ixhistories detailspage -stylesheet %1").arg(styleSheet);
- url += QString(" -evaltimestamp %1").arg(timestamps.at(i));
+ url += QString(" -evaltimestamp %1 -medianwinsize %2")
+ .arg(timestamps.at(i)).arg(medianWinSize);
for (int j = 0; j < rankedInfoNodes.size(); ++j) {
QDomElement rankedInfoElem = rankedInfoNodes.at(j).toElement();
@@ -5394,9 +5401,7 @@ void BMRequest_IndexGetValues::handleReply_HTML(const QStringList &args) const
reply += QString("<tr><td>Base time:</td><td>%1 (%2)</td></tr>\n")
.arg(baseTimestamp)
.arg(dateTime.toString());
- reply += QString(
- "<tr><td>Median window size:</td><td>%1</td></tr>\n")
- .arg(argsElem.attributeNode("medianWinSize").value());
+ reply += QString("<tr><td>Median window size:</td><td>%1</td></tr>\n").arg(medianWinSize);
reply += "</table>\n";
// Get filters ...
@@ -6808,28 +6813,27 @@ void BMRequest_GetIXHistories::handleReply_HTML(const QStringList &args) const
}
QStringList optValues;
-
- // Get server ...
- QString server;
- if (BMMisc::getOption(args, "-server", &optValues, 1, 0, &error)) {
- server = optValues.first().trimmed();
- } else {
- BMMisc::printHTMLErrorPage("-server option not found");
- return;
- }
+ bool ok;
// Get style sheet ...
QString styleSheet;
- if (BMMisc::getOption(args, "-stylesheet", &optValues, 1, 0, &error)) {
+ if (BMMisc::getOption(args, "-stylesheet", &optValues, 1, 0)) {
styleSheet = optValues.first().trimmed();
} else {
BMMisc::printHTMLErrorPage("-stylesheet option not found");
return;
}
- QDomElement argsElem = doc.elementsByTagName("args").at(0).toElement();
+ // Get median window size ...
+ if (BMMisc::getOption(args, "-medianwinsize", &optValues, 1, 0)) {
+ medianWinSize = optValues.first().toInt(&ok);
+ Q_ASSERT(ok);
+ } else {
+ BMMisc::printHTMLErrorPage("-medianwinsize option not found");
+ return;
+ }
- bool ok;
+ QDomElement argsElem = doc.elementsByTagName("args").at(0).toElement();
// Get eval timestamp ...
evalTimestamp = argsElem.attributeNode("evalTimestamp").value().toInt(&ok);
@@ -6854,6 +6858,13 @@ void BMRequest_GetIXHistories::handleReply_HTML(const QStringList &args) const
reply += "<br /><br />";
+ reply += QString(
+ "Normal data points are indicated in black, whereas potential outliers "
+ "(filtered out by median of %1 smoothing) are indicated in red.")
+ .arg(medianWinSize);
+
+ reply += "<br /><br />";
+
reply += "The result histories are ranked according to the following steps:<br /><ol>";
reply += "<li>Let <i>baseVal</i> be the first median smoothed value found.</li>";
@@ -6879,8 +6890,8 @@ void BMRequest_GetIXHistories::handleReply_HTML(const QStringList &args) const
reply += "</ol>";
reply += "The data points used for <i>baseVal</i>, <i>val</i><sub>1</sub>, and ";
- reply += "<i>val</i><sub>2</sub> are indicated in the graph as a blue circle, a red ";
- reply += "square, and a red circle respectively.";
+ reply += "<i>val</i><sub>2</sub> are indicated in the graph as a blue circle, an orange ";
+ reply += "square, and an orange circle respectively.";
reply += "<br /><br />";
reply += "The selected evaluation time is indicated by a blue vertical line ";
@@ -6922,9 +6933,19 @@ void BMRequest_GetIXHistories::handleReply_Image(const QStringList &args) const
return;
}
- QDomElement argsElem = doc.elementsByTagName("args").at(0).toElement();
-
bool ok;
+ QStringList optValues;
+
+ // Get median window size ...
+ if (BMMisc::getOption(args, "-medianwinsize", &optValues, 1, 0)) {
+ medianWinSize = optValues.first().toInt(&ok);
+ Q_ASSERT(ok);
+ } else {
+ BMMisc::printHTMLErrorPage("-medianwinsize option not found");
+ return;
+ }
+
+ QDomElement argsElem = doc.elementsByTagName("args").at(0).toElement();
// Get eval timestamp ...
evalTimestamp = argsElem.attributeNode("evalTimestamp").value().toInt(&ok);
@@ -6967,8 +6988,8 @@ void BMRequest_GetIXHistories::handleReply_Image(const QStringList &args) const
rhInfos.append(
new ResultHistoryInfo(
- -1, timestamps, values, -1, metric, platform, host, gitRepo, gitBranch, testCase,
- testFunction, dataTag));
+ -1, timestamps, values, medianWinSize, metric, platform, host, gitRepo, gitBranch,
+ testCase, testFunction, dataTag));
// Get the base- and diff positions and description ...
const int basePos_ = rhElem.attributeNode("basePos").value().toInt(&ok);
@@ -6987,7 +7008,8 @@ void BMRequest_GetIXHistories::handleReply_Image(const QStringList &args) const
// Create image ...
QString error_;
Plotter *plotter =
- new HistoriesPlotter(rhInfos, true, evalTimestamp, &basePos, &extraPos, &descr, false);
+ new HistoriesPlotter(
+ rhInfos, true, evalTimestamp, &basePos, &extraPos, &descr, false, true);
const QImage image = plotter->createImage(&error_);
// Free dynamic memory ...
diff --git a/src/bm/bmrequest.h b/src/bm/bmrequest.h
index 43accf9..2b97b65 100644
--- a/src/bm/bmrequest.h
+++ b/src/bm/bmrequest.h
@@ -727,12 +727,14 @@ class BMRequest_GetIXHistories : public BMRequest
{
public:
BMRequest_GetIXHistories(
- const int evalTimestamp, const QList<Index::RankedInfo> &rankedInfos,
- const QString &cacheKey)
- : evalTimestamp(evalTimestamp), rankedInfos(rankedInfos), cacheKey(cacheKey) {}
+ const int evalTimestamp, const int medianWinSize,
+ const QList<Index::RankedInfo> &rankedInfos, const QString &cacheKey)
+ : evalTimestamp(evalTimestamp), medianWinSize(medianWinSize), rankedInfos(rankedInfos)
+ , cacheKey(cacheKey) {}
BMRequest_GetIXHistories(const QDomDocument &doc) : BMRequest(doc) {}
private:
mutable int evalTimestamp;
+ mutable int medianWinSize;
QList<Index::RankedInfo> rankedInfos;
QString cacheKey;
diff --git a/src/bm/plotter.cpp b/src/bm/plotter.cpp
index a0e5d73..8d3592e 100644
--- a/src/bm/plotter.cpp
+++ b/src/bm/plotter.cpp
@@ -697,7 +697,7 @@ bool IndexPlotter::drawScenes(
HistoriesPlotter::HistoriesPlotter(
const QList<ResultHistoryInfo *> &rhInfos, const bool showBenchmark, const int baseTimestamp,
const QList<int> *basePos, const QList<QList<int> > *extraPos, const QStringList *extraDescr,
- const bool commonValueRange)
+ const bool commonValueRange, const bool showOutliers)
: rhInfos(rhInfos)
, showBenchmark(showBenchmark)
, baseTimestamp(baseTimestamp)
@@ -705,6 +705,7 @@ HistoriesPlotter::HistoriesPlotter(
, extraPos(extraPos)
, extraDescr(extraDescr)
, commonValueRange(commonValueRange)
+ , showOutliers(showOutliers)
, width(1200)
, rhHeight(
qMin(showBenchmark ? 220 : 170, qMax(showBenchmark ? 170 : 120, 800 / rhInfos.size())))
@@ -924,13 +925,25 @@ bool HistoriesPlotter::drawScenes(
// Draw data points ...
{
QPainterPath path;
+ QPainterPath outlierPath;
path.setFillRule(Qt::WindingFill);
const qreal dpSize_2 = 0.5 * dpSize;
- for (int i = 0; i < x.size(); ++i)
- path.addRect(x.at(i) - dpSize_2, y.at(i) - dpSize_2, dpSize, dpSize);
+ for (int i = 0; i < x.size(); ++i) {
+ const QRect rect(x.at(i) - dpSize_2, y.at(i) - dpSize_2, dpSize, dpSize);
+ if (showOutliers && rhInfo->isOutlier(i))
+ outlierPath.addRect(rect);
+ else
+ path.addRect(rect);
+ }
const QColor color(50, 50, 50, 255);
scene_near->addPath(path, QPen(color), QBrush(color));
+ if (!outlierPath.isEmpty()) {
+ const QColor outlierColor(255, 0, 0, 255);
+ QGraphicsItem *item =
+ scene_near->addPath(outlierPath, QPen(outlierColor), QBrush(outlierColor));
+ item->setZValue(-1);
+ }
}
if (basePos) {
@@ -952,8 +965,8 @@ bool HistoriesPlotter::drawScenes(
}
if (extraPos) {
- // Highlight extra positions - the first one as a red square and the others
- // as red circles (for now) ...
+ // Highlight extra positions - the first one as a brown square and the others
+ // as brown circles (for now) ...
QList<int> exPos = extraPos->at(rh);
@@ -976,7 +989,7 @@ bool HistoriesPlotter::drawScenes(
}
QGraphicsItem *extraPosItem = scene_far->addPath(
- path, QPen(QColor(255, 0, 0, 255)), QBrush(QColor(255, 200, 200, 255)));
+ path, QPen(QColor("#803300")), QBrush(QColor("#ff944d")));
// Ensure the circle is above the square ...
if (i > 1)
diff --git a/src/bm/plotter.h b/src/bm/plotter.h
index ca15d72..8bf5056 100644
--- a/src/bm/plotter.h
+++ b/src/bm/plotter.h
@@ -103,7 +103,7 @@ public:
const QList<ResultHistoryInfo *> &rhInfos, const bool showBenchmark = false,
const int baseTimestamp = -1, const QList<int> *basePos = 0,
const QList<QList<int> > *extraPos = 0, const QStringList *extraDescr = 0,
- const bool commonValueRange = true);
+ const bool commonValueRange = true, const bool showOutliers = false);
private:
QList<ResultHistoryInfo *> rhInfos;
@@ -113,6 +113,7 @@ private:
const QList<QList<int> > *extraPos;
const QStringList *extraDescr;
bool commonValueRange;
+ bool showOutliers;
qreal width;
qreal rhHeight;
qreal pad_top;
diff --git a/src/bm/resulthistoryinfo.cpp b/src/bm/resulthistoryinfo.cpp
index be5b571..ad13c2c 100644
--- a/src/bm/resulthistoryinfo.cpp
+++ b/src/bm/resulthistoryinfo.cpp
@@ -75,12 +75,27 @@ qreal ResultHistoryInfo::maxValue() const
}
// ### 2 B DOCUMENTED!
+bool ResultHistoryInfo::isOutlier(int i) const
+{
+ if ((i < 0) || (i >= values.size()))
+ return false;
+
+ if (!outliersMarked)
+ markOutliers();
+
+ return outliers.testBit(i);
+}
+
+// ### 2 B DOCUMENTED!
void ResultHistoryInfo::markOutliers() const
{
// Initially mark all values as outliers ...
const bool ok = outliers.fill(true, values.size());
Q_ASSERT(ok); // hm ... can this really fail in this case?
+ if (medianWinSize <= 0)
+ return; // invalid window size => impossible to smooth away any outlier!
+
// Slide the median window across the list of values and mark
// the median positions as non-outliers ...
Q_ASSERT(medianWinSize > 0);
diff --git a/src/bm/resulthistoryinfo.h b/src/bm/resulthistoryinfo.h
index 3da942a..6cb7366 100644
--- a/src/bm/resulthistoryinfo.h
+++ b/src/bm/resulthistoryinfo.h
@@ -57,6 +57,8 @@ public:
qreal minValue() const;
qreal maxValue() const;
+ bool isOutlier(int i) const;
+
int bmcontextId() const { return bmcontextId_; }
QString metric() const { return metric_; }
QString platform() const { return platform_; }
diff --git a/src/bmclient/main.cpp b/src/bmclient/main.cpp
index da99f3c..238d0f4 100644
--- a/src/bmclient/main.cpp
+++ b/src/bmclient/main.cpp
@@ -1215,6 +1215,18 @@ BMRequest * Executor::createGetIXHistoriesRequest(const QStringList &args, QStri
return 0;
}
+ // Get median window size ...
+ if (!BMMisc::getOption(args, "-medianwinsize", &values, 1, 0, error)) {
+ if (error->isEmpty())
+ *error = "-medianwinsize option not found";
+ return 0;
+ }
+ const int medianWinSize = values.first().toInt(&ok);
+ if ((!ok) || (medianWinSize < 1)) {
+ *error = "failed to extract median window size as a positive integer";
+ return 0;
+ }
+
// Get ranked infos ...
QList<QStringList> rankedStrings;
if (!BMMisc::getMultiOption2(args, "-rankedinfo", &rankedStrings, 5, error))
@@ -1254,7 +1266,7 @@ BMRequest * Executor::createGetIXHistoriesRequest(const QStringList &args, QStri
return 0;
}
- return new BMRequest_GetIXHistories(evalTimestamp, rankedInfos, cacheKey);
+ return new BMRequest_GetIXHistories(evalTimestamp, medianWinSize, rankedInfos, cacheKey);
}
// ### 2 B DOCUMENTED!
@@ -1664,7 +1676,7 @@ class DirectExecutor : public Executor
"get bmtree\n"
<<
- "get ixhistories -evaltimestamp <...> \\\n"
+ "get ixhistories -evaltimestamp <...> -medianwinsize <...> \\\n"
" -rankedinfo <BM context ID> <base pos> <diff pos 1> <diff pos 2> \\\n"
" <descr> ...\n"