diff options
| author | jasplin <qt-info@nokia.com> | 2010-05-06 09:52:57 +0200 |
|---|---|---|
| committer | jasplin <qt-info@nokia.com> | 2010-05-06 09:52:57 +0200 |
| commit | 856f10686aaebe984ccc4befdd1fdb08422472dd (patch) | |
| tree | 3fa2c3c475bb2d219685944ce8939d313ec2c39d | |
| parent | ea257f657659a1baf6a282c5f725f82bdb7856fa (diff) | |
Highlight outliers in index contributor graphs.
| -rw-r--r-- | src/bm/bmrequest.cpp | 70 | ||||
| -rw-r--r-- | src/bm/bmrequest.h | 8 | ||||
| -rw-r--r-- | src/bm/plotter.cpp | 25 | ||||
| -rw-r--r-- | src/bm/plotter.h | 3 | ||||
| -rw-r--r-- | src/bm/resulthistoryinfo.cpp | 15 | ||||
| -rw-r--r-- | src/bm/resulthistoryinfo.h | 2 | ||||
| -rw-r--r-- | src/bmclient/main.cpp | 16 |
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" |
