summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjasplin <qt-info@nokia.com>2010-05-11 14:42:17 +0200
committerjasplin <qt-info@nokia.com>2010-05-11 14:42:17 +0200
commit89893576179000aab90d683a43fabf2b2fb2c3b2 (patch)
tree74013ff3c354b2b416905cf9cb33cf69278702de
parent1c43dc0ff9fdea20688c0921f367b6c2e60c7491 (diff)
Added result history details to ASF Stats page.
-rw-r--r--src/bm/asfstats.cpp33
-rw-r--r--src/bm/asfstats.h21
-rw-r--r--src/bm/bmrequest.cpp508
-rw-r--r--src/bm/bmrequest.h6
-rw-r--r--src/bmclient/main.cpp19
5 files changed, 388 insertions, 199 deletions
diff --git a/src/bm/asfstats.cpp b/src/bm/asfstats.cpp
index 960e1c2..4074a77 100644
--- a/src/bm/asfstats.cpp
+++ b/src/bm/asfstats.cpp
@@ -124,9 +124,7 @@ Step 2: Sample the stable and smoothed RHs at fromTimestamp and toTimestamp and
// ### 2 B DOCUMENTED!
-void ASFStats::compute(
- const QList<ResultHistoryInfo *> &rhInfos, UnstableStats *usStats, int *regressed,
- int *unchanged, int *improved)
+void ASFStats::compute(const QList<ResultHistoryInfo *> &rhInfos, StatsInfo *statsInfo)
{
Q_ASSERT((fromTimestamp >= 0) && (fromTimestamp <= toTimestamp));
Q_ASSERT((diffTolerance >= 0.0) && (diffTolerance <= 100.0));
@@ -134,8 +132,15 @@ void ASFStats::compute(
Q_ASSERT((sfTolerance >= 0.0) && (sfTolerance <= 100.0));
Q_ASSERT((lfTolerance >= 0.0) && (lfTolerance <= 100.0));
- usStats->unstable.fill(false, rhInfos.size());
- *regressed = *unchanged = *improved = 0;
+ statsInfo->regressed.fill(false, rhInfos.size());
+ statsInfo->unchanged.fill(false, rhInfos.size());
+ statsInfo->improved.fill(false, rhInfos.size());
+ statsInfo->unstable.fill(false, rhInfos.size());
+ statsInfo->usZero.fill(false, rhInfos.size());
+ statsInfo->usLowFromPos.fill(false, rhInfos.size());
+ statsInfo->usLowSF.fill(false, rhInfos.size());
+ statsInfo->usLowLF.fill(false, rhInfos.size());
+ statsInfo->usHighMaxLD.fill(false, rhInfos.size());
for (int i = 0; i < rhInfos.size(); ++i) {
bool zerosFound = false;
@@ -162,29 +167,29 @@ void ASFStats::compute(
bool unstable = false;
if (zerosFound) {
unstable = true;
- ++(usStats->zeroCount);
+ statsInfo->usZero.setBit(i);
}
if (fromPos == -1) {
unstable = true;
- ++(usStats->lowFromPosCount);
+ statsInfo->usLowFromPos.setBit(i);
}
if (sf < sfTolerance) {
unstable = true;
- ++(usStats->lowSFCount);
+ statsInfo->usLowSF.setBit(i);
}
if (lf < lfTolerance) {
unstable = true;
- ++(usStats->lowLFCount);
+ statsInfo->usLowLF.setBit(i);
}
if (maxLD > maxLDTolerance) {
unstable = true;
- ++(usStats->highMaxLDCount);
+ statsInfo->usHighMaxLD.setBit(i);
}
if (unstable) {
// RH is unstable, so mark it as such ...
- usStats->unstable.setBit(i);
+ statsInfo->unstable.setBit(i);
} else {
// RH is stable, so sample the smoothed values at fromTimestamp and toTimestamp and
@@ -197,14 +202,14 @@ void ASFStats::compute(
const qreal v1 = rhInfos.at(i)->value(fromPos);
const qreal v2 = rhInfos.at(i)->value(toPos);
if ((100 * (qMax(v1, v2) / qMin(v1, v2) - 1)) <= diffTolerance) {
- ++(*unchanged);
+ statsInfo->unchanged.setBit(i);
} else {
const qreal diff =
BMMisc::lowerIsBetter(rhInfos.at(i)->metric()) ? (v1 - v2) : (v2 - v1);
if (diff < 0)
- ++(*regressed);
+ statsInfo->regressed.setBit(i);
else
- ++(*improved);
+ statsInfo->improved.setBit(i);
}
}
}
diff --git a/src/bm/asfstats.h b/src/bm/asfstats.h
index c153376..83bbc65 100644
--- a/src/bm/asfstats.h
+++ b/src/bm/asfstats.h
@@ -43,20 +43,19 @@ public:
, toTimestamp(toTimestamp)
{}
- struct UnstableStats {
+ struct StatsInfo {
+ QBitArray regressed;
+ QBitArray unchanged;
+ QBitArray improved;
QBitArray unstable;
- int zeroCount;
- int lowFromPosCount;
- int lowSFCount;
- int lowLFCount;
- int highMaxLDCount;
- UnstableStats()
- : zeroCount(0), lowFromPosCount(), lowSFCount(0), lowLFCount(0), highMaxLDCount(0) {}
+ QBitArray usZero;
+ QBitArray usLowFromPos;
+ QBitArray usLowSF;
+ QBitArray usLowLF;
+ QBitArray usHighMaxLD;
};
- void compute(
- const QList<ResultHistoryInfo *> &rhInfos, UnstableStats *usStats, int *regressed,
- int *unchanged, int *improved);
+ void compute(const QList<ResultHistoryInfo *> &rhInfos, StatsInfo *statsInfo);
private:
// Tolerances:
diff --git a/src/bm/bmrequest.cpp b/src/bm/bmrequest.cpp
index 46539b8..33769a5 100644
--- a/src/bm/bmrequest.cpp
+++ b/src/bm/bmrequest.cpp
@@ -1686,6 +1686,123 @@ struct BenchmarkStats2 {
};
};
+// ### 2 B DOCUMENTED!
+static bool extractBMAndContextFromRH(
+ int bmcontextId, const QString &reqName, QSqlDatabase *database,
+ QString *testCase, QString *testFunction, QString *dataTag, QString *metric,
+ QString *platform, QString *host, QString *gitRepo, QString *gitBranch, QString *error)
+{
+ QSqlQuery query(*database);
+
+ // Get benchmark ID and context ID ...
+ if (!query.exec(
+ QString("SELECT benchmarkId, contextId FROM bmcontext WHERE id=%1;")
+ .arg(bmcontextId))) {
+ *error = errorReply(
+ query, reqName, QString("failed to get IDs for benchmark and context"));
+ return false;
+ }
+ int benchmarkId;
+ int contextId;
+ if (query.next()) {
+ benchmarkId = query.value(0).toInt();
+ contextId = query.value(1).toInt();
+ } else {
+ *error = errorReply(
+ query, reqName, QString("no such benchmark and context (programming error?)"));
+ return false;
+ }
+
+ // Get benchmark ...
+ if (!query.exec(
+ QString("SELECT testCase, testFunction, dataTag FROM benchmark WHERE id=%1;")
+ .arg(benchmarkId))) {
+ *error = errorReply(query, reqName, QString("failed to get benchmark"));
+ return false;
+ }
+ if (query.next()) {
+ *testCase = query.value(0).toString();
+ *testFunction = query.value(1).toString();
+ *dataTag = query.value(2).toString();
+ } else {
+ *error = errorReply(query, reqName, QString("no such benchmark (programming error?)"));
+ return false;
+ }
+
+ // Get metric ID, platform ID, host ID, and branch ID ...
+ if (!query.exec(
+ QString("SELECT metricId, platformId, hostId, branchId FROM context WHERE id=%1;")
+ .arg(contextId))) {
+ *error = errorReply(
+ query, reqName, QString("failed to get IDs for metrid, platform, host, and branch"));
+ return false;
+ }
+ int metricId;
+ int platformId;
+ int hostId;
+ int branchId;
+ if (query.next()) {
+ metricId = query.value(0).toInt();
+ platformId = query.value(1).toInt();
+ hostId = query.value(2).toInt();
+ branchId = query.value(3).toInt();
+ } else {
+ *error = errorReply(query, reqName, QString("no such context (programming error?)"));
+ return false;
+ }
+
+ // Get metric ...
+ if (!query.exec(QString("SELECT name FROM metric WHERE id=%1;").arg(metricId))) {
+ *error = errorReply(query, reqName, QString("failed to get metric"));
+ return false;
+ }
+ if (query.next()) {
+ *metric = query.value(0).toString();
+ } else {
+ *error = errorReply(query, reqName, QString("no such metric (programming error?)"));
+ return false;
+ }
+
+ // Get platform ...
+ if (!query.exec(QString("SELECT name FROM platform WHERE id=%1;").arg(platformId))) {
+ *error = errorReply(query, reqName, QString("failed to get platform"));
+ return false;
+ }
+ if (query.next()) {
+ *platform = query.value(0).toString();
+ } else {
+ *error = errorReply(query, reqName, QString("no such platform (programming error?)"));
+ return false;
+ }
+
+ // Get host ...
+ if (!query.exec(QString("SELECT name FROM host WHERE id=%1;").arg(hostId))) {
+ *error = errorReply(query, reqName, QString("failed to get host"));
+ return false;
+ }
+ if (query.next()) {
+ *host = query.value(0).toString();
+ } else {
+ *error = errorReply(query, reqName, QString("no such host (programming error?)"));
+ return false;
+ }
+
+ // Get branch ...
+ if (!query.exec(QString("SELECT gitRepo, gitBranch FROM branch WHERE id=%1;").arg(branchId))) {
+ *error = errorReply(query, reqName, QString("failed to get branch"));
+ return false;
+ }
+ if (query.next()) {
+ *gitRepo = query.value(0).toString();
+ *gitBranch = query.value(1).toString();
+ } else {
+ *error = errorReply(query, reqName, QString("no such branch (programming error?)"));
+ return false;
+ }
+
+ return true;
+}
+
// --- GetHistory ---
QByteArray BMRequest_GetHistory::toRequestBuffer(QString *)
{
@@ -1694,10 +1811,10 @@ QByteArray BMRequest_GetHistory::toRequestBuffer(QString *)
"testCase=\"%2\" testFunction=\"%3\" dataTag=\"%4\" metric=\"%5\" platform=\"%6\" "
"host=\"%7\" gitRepo=\"%8\" gitBranch=\"%9\" timestamp1=\"%10\" "
"timestamp2=\"%11\" diffTolerance=\"%12\" stabTolerance=\"%13\" "
- "maxSize=\"%14\" /></request>")
+ "maxSize=\"%14\" explicitBMContextId=\"%15\" /></request>")
.arg(name()).arg(testCase).arg(testFunction).arg(dataTag).arg(metric).arg(platform)
.arg(host).arg(gitRepo).arg(gitBranch).arg(timestamp1).arg(timestamp2)
- .arg(diffTolerance).arg(stabTolerance).arg(maxSize);
+ .arg(diffTolerance).arg(stabTolerance).arg(maxSize).arg(explicitBMContextId);
return xmlConvert(request);
}
@@ -1721,22 +1838,44 @@ QByteArray BMRequest_GetHistory::toReplyBuffer()
Q_ASSERT(ok);
maxSize = contextElem.attributeNode("maxSize").value().toInt(&ok);
Q_ASSERT(ok);
+ explicitBMContextId = contextElem.attributeNode("explicitBMContextId").value().toInt(&ok);
+ Q_ASSERT(ok);
- QString reply = QString("<reply type=\"%1\">").arg(name());
+ if (explicitBMContextId >= 0) {
- int benchmarkId;
- if (!getBenchmarkId(&reply, &benchmarkId, testCase, testFunction, dataTag))
- return xmlConvert(reply);
+ QString error;
+ if (!extractBMAndContextFromRH(
+ explicitBMContextId, name(), database, &testCase, &testFunction, &dataTag,
+ &metric, &platform, &host, &gitRepo, &gitBranch, &error)) {
+ return xmlConvert(error);
+ }
+ }
+
+ QString reply = QString("<reply type=\"%1\">").arg(name());
int bmcontextId;
- if (!getBMContextId(
- &reply, &bmcontextId, benchmarkId, metric, platform, host, gitRepo, gitBranch))
- return xmlConvert(reply);
+ if (explicitBMContextId >= 0) {
+ bmcontextId = explicitBMContextId;
+ } else {
+ int benchmarkId;
+ if (!getBenchmarkId(&reply, &benchmarkId, testCase, testFunction, dataTag))
+ return xmlConvert(reply);
+ if (!getBMContextId(
+ &reply, &bmcontextId, benchmarkId, metric, platform, host, gitRepo, gitBranch))
+ return xmlConvert(reply);
+ }
if (!appendBranchHistoryToReply(
&reply, bmcontextId, "", timestamp1, timestamp2, diffTolerance, stabTolerance, maxSize))
return xmlConvert(reply);
+ reply.append(
+ QString(
+ "<bmcontext testCase=\"%1\" testFunction=\"%2\" dataTag=\"%3\" metric=\"%4\" "
+ "platform=\"%5\" host=\"%6\" gitRepo=\"%7\" gitBranch=\"%8\" />")
+ .arg(testCase).arg(testFunction).arg(dataTag).arg(metric).arg(platform)
+ .arg(host).arg(gitRepo).arg(gitBranch));
+
reply.append("</reply>");
return xmlConvert(reply);
@@ -1881,16 +2020,19 @@ void BMRequest_GetHistory::handleReply_HTML(const QStringList &args) const
offset = args.indexOf("get");
Q_ASSERT(offset >= 0);
- Q_ASSERT(args.size() == offset + 18);
+ Q_ASSERT(args.size() >= offset + 18);
const QString type = args.at(offset + 1);
- testCase = args.at(offset + 2);
- testFunction = args.at(offset + 3);
- dataTag = args.at(offset + 4);
- metric = args.at(offset + 5);
- platform = args.at(offset + 6);
- host = args.at(offset + 7);
- gitRepo = args.at(offset + 8);
- gitBranch = args.at(offset + 9);
+
+ QDomNodeList bmContextNodes = doc.elementsByTagName("bmcontext");
+ QDomElement bmContextElem = bmContextNodes.at(0).toElement();
+ testCase = bmContextElem.attributeNode("testCase").value();
+ testFunction = bmContextElem.attributeNode("testFunction").value();
+ dataTag = bmContextElem.attributeNode("dataTag").value();
+ metric = bmContextElem.attributeNode("metric").value();
+ platform = bmContextElem.attributeNode("platform").value();
+ host = bmContextElem.attributeNode("host").value();
+ gitRepo = bmContextElem.attributeNode("gitRepo").value();
+ gitBranch = bmContextElem.attributeNode("gitBranch").value();
bool ok;
ok = BMMisc::getTimestamp(args, offset + 11, &timestamp1);
@@ -4534,145 +4676,23 @@ QByteArray BMRequest_GetResult::toReplyBuffer()
}
deleteQuery(query);
- // Get benchmark ID and context ID ...
- query = createQuery();
- if (!query->exec(
- QString("SELECT benchmarkId, contextId FROM bmcontext WHERE id=%1;")
- .arg(bmcontextId))) {
- reply = errorReply(*query, name(), QString("failed to get result (exec() failed (3))"));
- deleteQuery(query);
- return xmlConvert(reply);
- }
- int benchmarkId;
- int contextId;
- if (query->next()) {
- benchmarkId = query->value(0).toInt();
- contextId = query->value(1).toInt();
- } else {
- reply = errorReply(
- *query, name(), QString("no such benchmark and context (programming error?)"));
- deleteQuery(query);
- return xmlConvert(reply);
- }
- deleteQuery(query);
- // Get benchmark ...
- query = createQuery();
- if (!query->exec(
- QString("SELECT testCase, testFunction, dataTag FROM benchmark WHERE id=%1;")
- .arg(benchmarkId))) {
- reply = errorReply(*query, name(), QString("failed to get result (exec() failed (4))"));
- deleteQuery(query);
- return xmlConvert(reply);
- }
+ QString error;
+
QString testCase;
QString testFunction;
QString dataTag;
- if (query->next()) {
- testCase = query->value(0).toString();
- testFunction = query->value(1).toString();
- dataTag = query->value(2).toString();
- } else {
- reply = errorReply(*query, name(), QString("no such benchmark (programming error?)"));
- deleteQuery(query);
- return xmlConvert(reply);
- }
- deleteQuery(query);
-
- // Get metric ID, platform ID, host ID, and branch ID ...
- query = createQuery();
- if (!query->exec(
- QString("SELECT metricId, platformId, hostId, branchId FROM context WHERE id=%1;")
- .arg(contextId))) {
- reply = errorReply(*query, name(), QString("failed to get result (exec() failed (5))"));
- deleteQuery(query);
- return xmlConvert(reply);
- }
- int metricId;
- int platformId;
- int hostId;
- int branchId;
- if (query->next()) {
- metricId = query->value(0).toInt();
- platformId = query->value(1).toInt();
- hostId = query->value(2).toInt();
- branchId = query->value(3).toInt();
- } else {
- reply = errorReply(*query, name(), QString("no such context (programming error?)"));
- deleteQuery(query);
- return xmlConvert(reply);
- }
- deleteQuery(query);
-
- // Get metric ...
- query = createQuery();
- if (!query->exec(QString("SELECT name FROM metric WHERE id=%1;").arg(metricId))) {
- reply = errorReply(*query, name(), QString("failed to get result (exec() failed (6))"));
- deleteQuery(query);
- return xmlConvert(reply);
- }
QString metric;
- if (query->next()) {
- metric = query->value(0).toString();
- } else {
- reply = errorReply(*query, name(), QString("no such metric (programming error?)"));
- deleteQuery(query);
- return xmlConvert(reply);
- }
- deleteQuery(query);
-
- // Get platform ...
- query = createQuery();
- if (!query->exec(QString("SELECT name FROM platform WHERE id=%1;").arg(platformId))) {
- reply = errorReply(*query, name(), QString("failed to get result (exec() failed (7))"));
- deleteQuery(query);
- return xmlConvert(reply);
- }
QString platform;
- if (query->next()) {
- platform = query->value(0).toString();
- } else {
- reply = errorReply(*query, name(), QString("no such platform (programming error?)"));
- deleteQuery(query);
- return xmlConvert(reply);
- }
- deleteQuery(query);
-
- // Get host ...
- query = createQuery();
- if (!query->exec(QString("SELECT name FROM host WHERE id=%1;").arg(hostId))) {
- reply = errorReply(*query, name(), QString("failed to get result (exec() failed (8))"));
- deleteQuery(query);
- return xmlConvert(reply);
- }
QString host;
- if (query->next()) {
- host = query->value(0).toString();
- } else {
- reply = errorReply(*query, name(), QString("no such host (programming error?)"));
- deleteQuery(query);
- return xmlConvert(reply);
- }
- deleteQuery(query);
-
- // Get branch ...
- query = createQuery();
- if (!query->exec(QString("SELECT gitRepo, gitBranch FROM branch WHERE id=%1;").arg(branchId))) {
- reply = errorReply(*query, name(), QString("failed to get result (exec() failed (9))"));
- deleteQuery(query);
- return xmlConvert(reply);
- }
QString gitRepo;
QString gitBranch;
- if (query->next()) {
- gitRepo = query->value(0).toString();
- gitBranch = query->value(1).toString();
- } else {
- reply = errorReply(*query, name(), QString("no such branch (programming error?)"));
- deleteQuery(query);
- return xmlConvert(reply);
+ if (!extractBMAndContextFromRH(
+ bmcontextId, name(), database, &testCase, &testFunction, &dataTag, &metric, &platform,
+ &host, &gitRepo, &gitBranch, &error)) {
+ return xmlConvert(error);
}
- deleteQuery(query);
+
// Get values ...
query = createQuery();
@@ -7356,31 +7376,39 @@ QByteArray BMRequest_ASFStatsGetValues::toReplyBuffer()
reply = QString("<reply type=\"%1\" >").arg(name());
ASFStats asfStats(diffTol, stabTol, sfTol, lfTol, maxLDTol, fromTimestamp, toTimestamp);
- ASFStats::UnstableStats usStats;
- int regressed = 0;
- int unchanged = 0;
- int improved = 0;
- asfStats.compute(rhInfos, &usStats, &regressed, &unchanged, &improved);
+ ASFStats::StatsInfo statsInfo;
+ asfStats.compute(rhInfos, &statsInfo);
// Add stats to reply ...
reply += QString(
"<stats regressed=\"%1\" unchanged=\"%2\" improved=\"%3\" unstable=\"%4\" "
"usZeroCount=\"%5\" usLowFromPosCount=\"%6\" usLowSFCount=\"%7\" usLowLFCount=\"%8\" "
"usHighMaxLDCount=\"%9\" />")
- .arg(regressed).arg(unchanged).arg(improved)
- .arg(usStats.unstable.count(true))
- .arg(usStats.zeroCount)
- .arg(usStats.lowFromPosCount)
- .arg(usStats.lowSFCount)
- .arg(usStats.lowLFCount)
- .arg(usStats.highMaxLDCount);
-
- // Add IDs of unstable result histories to reply ...
- reply += "<unstableIDs>";
- for (int i = 0; i < usStats.unstable.size(); ++i)
- if (usStats.unstable.testBit(i))
- reply += QString("%1 ").arg(rhInfos.at(i)->bmcontextId());
- reply += "</unstableIDs>";
+ .arg(statsInfo.regressed.count(true))
+ .arg(statsInfo.unchanged.count(true))
+ .arg(statsInfo.improved.count(true))
+ .arg(statsInfo.unstable.count(true))
+ .arg(statsInfo.usZero.count(true))
+ .arg(statsInfo.usLowFromPos.count(true))
+ .arg(statsInfo.usLowSF.count(true))
+ .arg(statsInfo.usLowLF.count(true))
+ .arg(statsInfo.usHighMaxLD.count(true));
+
+ // Add result history stats to reply ...
+ for (int i = 0; i < rhInfos.size(); ++i) {
+ reply += QString(
+ "<rh id=\"%1\" rg=\"%2\" uc=\"%3\" im=\"%4\" zr=\"%5\" fp=\"%6\" "
+ "sf=\"%7\" lf=\"%8\" ld=\"%9\" />")
+ .arg(rhInfos.at(i)->bmcontextId())
+ .arg(statsInfo.regressed.testBit(i))
+ .arg(statsInfo.unchanged.testBit(i))
+ .arg(statsInfo.improved.testBit(i))
+ .arg(statsInfo.usZero.testBit(i))
+ .arg(statsInfo.usLowFromPos.testBit(i))
+ .arg(statsInfo.usLowSF.testBit(i))
+ .arg(statsInfo.usLowLF.testBit(i))
+ .arg(statsInfo.usHighMaxLD.testBit(i));
+ }
//----------------------------------------------------------------------------------------
@@ -7416,6 +7444,75 @@ QByteArray BMRequest_ASFStatsGetValues::toReplyBuffer()
return xmlConvert(reply);
}
+// ### 2 B DOCUMENTED!
+struct RHStats {
+ int id; // BM context ID
+ bool rg; // regressed
+ bool uc; // unchanged
+ bool im; // improved
+
+ // Conditions for being unstable:
+ bool zr; // zero existence
+ bool fp; // 'from' position to low (i.e. no data before the 'from' time)
+ bool sf; // stability fraction too low
+ bool lf; // unique level fraction too low
+ bool ld; // max level difference to high
+
+ RHStats(
+ const int id, const bool rg, const bool uc, const bool im, const bool zr, const bool fp,
+ const bool sf, const bool lf, const bool ld)
+ : id(id), rg(rg), uc(uc), im(im), zr(zr), fp(fp), sf(sf), lf(lf), ld(ld) {}
+
+ struct LessThan {
+ LessThan() {}
+ bool operator()(const RHStats *s1, const RHStats *s2) {
+
+ // Ranking priority:
+ // 1: Regressed (ranked first)
+ // 2: Unchanged
+ // 3: Improved
+ // 4: All others (ranked last)
+
+ if (s1->rg && !s2->rg)
+ return true;
+ if (!s1->rg && s2->rg)
+ return false;
+
+ if (s1->uc && !s2->uc)
+ return true;
+ if (!s1->uc && s2->uc)
+ return false;
+
+ if (s1->im && !s2->im)
+ return true;
+ if (!s1->im && s2->im)
+ return false;
+
+ return false;
+ }
+ };
+};
+
+// ### 2 B DOCUMENTED!
+static QString createRHDetailsLink(
+ const QString &webServer, const QString &server, const QString &styleSheet, int bmcontextId)
+{
+ QString url;
+ url = QString("%1/cgi-bin/bmclientwrapper").arg(webServer);
+ url += QString("?command=-server %1").arg(server);
+ url +=
+ " get detailspage dummyTestCase dummyTestFunction dummyDataTag dummyMetric dummyPlatform"
+ " dummyHost dummyGitRepo dummyGitBranch"; // ### this is a bit silly, so fix it by making
+ // the bmclient independent of argument positions
+ QDateTime dateTime = QDateTime::currentDateTime();
+ url += QString(" -timerange first last 0.00 0 -1 %1 %2 -bmcontextid %3")
+ .arg(styleSheet)
+ .arg(dateTime.toTime_t())
+ .arg(bmcontextId);
+
+ return QString("<a href=\"%1\">details</a>").arg(url);
+}
+
void BMRequest_ASFStatsGetValues::handleReply_HTML(const QStringList &args) const
{
QString error;
@@ -7447,6 +7544,14 @@ void BMRequest_ASFStatsGetValues::handleReply_HTML(const QStringList &args) cons
return;
}
+ // Extract the web server from the style sheet ...
+ QRegExp rx("^(\\S+:\\d+)\\D+$");
+ if (rx.indexIn(styleSheet) == -1) {
+ BMMisc::printHTMLErrorPage(QString("failed to extract web server from style sheet"));
+ return;
+ }
+ const QString webServer = rx.cap(1);
+
// *** Header ***
QString reply = QString("<html>\n<head>\n");
reply += QString("<link rel=\"stylesheet\" type=\"text/css\" href=\"%1\" />\n").arg(styleSheet);
@@ -7628,6 +7733,77 @@ void BMRequest_ASFStatsGetValues::handleReply_HTML(const QStringList &args) cons
reply += "</tr>\n";
reply += "<table>\n";
+
+ // Result history details table ...
+
+ reply += "<br /><br />";
+
+ reply += "<table style=\"background-color:#eeeeee\">\n";
+ reply += "<tr><td style=\"text-align:right\">RG:</td><td>Regressed</td></tr>";
+ reply += "<tr><td style=\"text-align:right\">UC:</td><td>Unchanged</td></tr>";
+ reply += "<tr><td style=\"text-align:right\">IM:</td><td>Improved</td></tr>";
+ reply += "<tr><td style=\"text-align:right\">ZR:</td><td>Zero existence</td></tr>";
+ reply += "<tr><td style=\"text-align:right\">FP:</td>"
+ "<td>'From' position to low (i.e. no data before the 'from' time)</td></tr>";
+ reply += "<tr><td style=\"text-align:right\">SF:</td><td>Stability fraction too low</td></tr>";
+ reply += "<tr><td style=\"text-align:right\">LF:</td>"
+ "<td>Unique level fraction too high</td></tr>";
+ reply += "<tr><td style=\"text-align:right\">LD:</td>"
+ "<td>Max level difference to high</td></tr>";
+ reply += "</table>\n";
+
+ reply += "<br /><table style=\"text-align:right\">\n";
+
+ QList<RHStats *> rhStats;
+ QDomNodeList rhNodes = doc.elementsByTagName("rh");
+ for (int i = 0; i < rhNodes.size(); ++i) {
+ QDomElement rhElem = rhNodes.at(i).toElement();
+ rhStats.append(
+ new RHStats(
+ rhElem.attributeNode("id").value().toInt(),
+ rhElem.attributeNode("rg").value().toInt(),
+ rhElem.attributeNode("uc").value().toInt(),
+ rhElem.attributeNode("im").value().toInt(),
+ rhElem.attributeNode("zr").value().toInt(),
+ rhElem.attributeNode("fp").value().toInt(),
+ rhElem.attributeNode("sf").value().toInt(),
+ rhElem.attributeNode("lf").value().toInt(),
+ rhElem.attributeNode("ld").value().toInt()
+ )
+ );
+ }
+
+ qSort(rhStats.begin(), rhStats.end(), RHStats::LessThan());
+
+ for (int i = 0; i < rhStats.size(); ++i) {
+ reply += QString(
+ "<tr>"
+ "<td>%1</td>"
+ "<td>%2</td>"
+ "<td>%3</td>"
+ "<td>%4</td>"
+ "<td>%5</td>"
+ "<td>%6</td>"
+ "<td>%7</td>"
+ "<td>%8</td>"
+ "<td>%9</td>"
+ "<td>%10</td>"
+ "</tr>\n")
+ .arg(i)
+ .arg(createRHDetailsLink(webServer, server, styleSheet, rhStats.at(i)->id))
+ .arg(rhStats.at(i)->rg ? "RG" : "")
+ .arg(rhStats.at(i)->uc ? "UC" : "")
+ .arg(rhStats.at(i)->im ? "IM" : "")
+ .arg(rhStats.at(i)->zr ? "ZR" : "")
+ .arg(rhStats.at(i)->fp ? "FP" : "")
+ .arg(rhStats.at(i)->sf ? "SF" : "")
+ .arg(rhStats.at(i)->lf ? "LF" : "")
+ .arg(rhStats.at(i)->ld ? "LD" : "");
+ }
+
+ reply += "</table>";
+
+
reply += "</body></html>";
BMMisc::printHTMLOutput(reply);
diff --git a/src/bm/bmrequest.h b/src/bm/bmrequest.h
index 8d90d88..12d61a1 100644
--- a/src/bm/bmrequest.h
+++ b/src/bm/bmrequest.h
@@ -308,12 +308,13 @@ public:
const QString &gitRepo, const QString &gitBranch,
const QString &timestamp1, const QString &timestamp2,
const qreal diffTolerance, const int stabTolerance, const int maxSize,
- const QString &styleSheet, const int currTimestamp)
+ const QString &styleSheet, const int currTimestamp, const int explicitBMContextId = -1)
: testCase(testCase), testFunction(testFunction), dataTag(dataTag), metric(metric)
, platform(platform), host(host), gitRepo(gitRepo), gitBranch(gitBranch)
, timestamp1(timestamp1), timestamp2(timestamp2)
, diffTolerance(diffTolerance), stabTolerance(stabTolerance)
- , maxSize(maxSize), styleSheet(styleSheet), currTimestamp(currTimestamp) {}
+ , maxSize(maxSize), styleSheet(styleSheet), currTimestamp(currTimestamp)
+ , explicitBMContextId(explicitBMContextId) {}
BMRequest_GetHistory(const QDomDocument &doc) : BMRequest(doc) {}
private:
mutable QString testCase;
@@ -331,6 +332,7 @@ private:
mutable int maxSize;
mutable QString styleSheet;
mutable int currTimestamp;
+ mutable int explicitBMContextId;
QString name() const { return "GetHistory"; }
QByteArray toRequestBuffer(QString *error);
diff --git a/src/bmclient/main.cpp b/src/bmclient/main.cpp
index ca890d5..0823d20 100644
--- a/src/bmclient/main.cpp
+++ b/src/bmclient/main.cpp
@@ -911,18 +911,25 @@ BMRequest * Executor::createGetHistoryRequest(const QStringList &args, QString *
// Extract current timestamp ...
int currTimestamp = args.at(17).toInt(&ok);
- if (!ok) {
- *error = QString(
- "failed to extract current timestamp as an integer for 'get history' command");
- return 0;
- } else if (currTimestamp < 0) {
+ if ((!ok) || (currTimestamp < 0)) {
currTimestamp = -1;
}
+ // Extract BM context ID (which overrides other values if specified) ...
+ int explicitBMContextId = -1;
+ if (BMMisc::getOption(args, "-bmcontextid", &values, 1, 0, error)) {
+ bool ok;
+ explicitBMContextId = values.at(0).toInt(&ok);
+ if ((!ok) || (explicitBMContextId < 0)) {
+ *error = "failed to extract stability tolerance as non-negative integer";
+ return 0;
+ }
+ }
+
return new BMRequest_GetHistory(
args.at(2), args.at(3), args.at(4), args.at(5), args.at(6), args.at(7),
args.at(8), args.at(9), timeRange.first, timeRange.second, diffTolerance,
- stabTolerance, maxSize, args.at(16), currTimestamp);
+ stabTolerance, maxSize, args.at(16), currTimestamp, explicitBMContextId);
}
BMRequest * Executor::createGetHistory2Request(const QStringList &args, QString *error) const