"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "projects/MatrixTesting/src/matrix-status.C" between
rose-0.11.53.0.tar.gz and rose-0.11.54.0.tar.gz

About: ROSE is a compiler infrastructure to build source-to-source program transformation and analysis tools for large-scale C, C++, UPC, Fortran, OpenMP, Java, Python and PHP applications.

matrix-status.C  (rose-0.11.53.0):matrix-status.C  (rose-0.11.54.0)
skipping to change at line 12 skipping to change at line 12
static const char *gDescription = static const char *gDescription =
"To be written."; "To be written.";
#include <rose.h> #include <rose.h>
#include "matrixTools.h" #include "matrixTools.h"
#include <Rose/CommandLine.h> #include <Rose/CommandLine.h>
#include <Rose/FormattedTable.h> #include <Rose/FormattedTable.h>
#include <Sawyer/Database.h> #include <Sawyer/Database.h>
#include <Sawyer/Message.h> #include <Sawyer/Message.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/format.hpp> #include <boost/format.hpp>
#include <boost/regex.hpp> #include <boost/regex.hpp>
#include <time.h>
using namespace Rose; using namespace Rose;
using namespace Sawyer::Message::Common; using namespace Sawyer::Message::Common;
namespace DB = Sawyer::Database; namespace DB = Sawyer::Database;
struct Settings { struct Settings {
std::string databaseUri; std::string databaseUri;
std::string roseVersion; // if non-empty, use thi s version instead of latest std::string roseVersion; // if non-empty, use thi s version instead of latest
Format outputFormat = Format::PLAIN;
}; };
static Sawyer::Message::Facility mlog; static Sawyer::Message::Facility mlog;
static std::vector<std::string> static std::vector<std::string>
parseCommandLine(int argc, char *argv[], Settings &settings) { parseCommandLine(int argc, char *argv[], Settings &settings) {
using namespace Sawyer::CommandLine; using namespace Sawyer::CommandLine;
Parser parser = Rose::CommandLine::createEmptyParser(gPurpose, gDescription) ; Parser parser = Rose::CommandLine::createEmptyParser(gPurpose, gDescription) ;
parser.errorStream(mlog[FATAL]); parser.errorStream(mlog[FATAL]);
parser.doc("Symopsis", "@prop{programName} [@v{switches}]"); parser.doc("Symopsis", "@prop{programName} [@v{switches}]");
SwitchGroup sg("Tool-specific switches"); SwitchGroup sg("Tool-specific switches");
insertDatabaseSwitch(sg, settings.databaseUri); insertDatabaseSwitch(sg, settings.databaseUri);
insertOutputFormatSwitch(sg, settings.outputFormat, FormatFlags().set(Format ::PLAIN).set(Format::HTML));
sg.insert(Switch("rose", 'b') sg.insert(Switch("rose", 'b')
.argument("committish", anyParser(settings.roseVersion)) .argument("committish", anyParser(settings.roseVersion))
.doc("Query the database for the specified ROSE version rather tha n showing information for " .doc("Query the database for the specified ROSE version rather tha n showing information for "
"the latest test result. When specifying a hash, only full ha shes are supported, not " "the latest test result. When specifying a hash, only full ha shes are supported, not "
"abbreviated hashes.")); "abbreviated hashes."));
return parser return parser
.with(Rose::CommandLine::genericSwitches()) .with(Rose::CommandLine::genericSwitches())
.with(sg) .with(sg)
skipping to change at line 73 skipping to change at line 77
static bool called; static bool called;
static FormattedTable::CellProperties p; static FormattedTable::CellProperties p;
if (!called) { if (!called) {
p.foreground(Color::HSV_GREEN); p.foreground(Color::HSV_GREEN);
called = true; called = true;
} }
return p; return p;
} }
static void static void
showSectionTitle(const Settings &settings, const std::string &title, const std::
string &desc = "") {
static const size_t width = 80;
switch (settings.outputFormat) {
case Format::PLAIN:
std::cout <<std::string(width, '=') <<"\n"
<<"=== " <<StringUtility::leftJustify(title, width-8) <<"=
==\n"
<<std::string(width, '=') <<"\n";
if (!desc.empty())
std::cout <<desc <<"\n";
std::cout <<"\n";
break;
case Format::HTML:
std::cout <<"<hr/><h2>" <<title <<"</h2>\n";
if (!desc.empty())
std::cout <<"<p>" <<desc <<"</p>\n";
break;
default:
ASSERT_not_reachable("invalid output format");
}
}
static void
showSubsectionTitle(const Settings &settings, const std::string &title, const st
d::string &desc = "") {
switch (settings.outputFormat) {
case Format::PLAIN:
std::cout <<title <<"\n";
if (!desc.empty())
std::cout <<desc <<"\n";
break;
case Format::HTML:
std::cout <<"<h3>" <<title <<"</h3>\n";
if (!desc.empty())
std::cout <<"<p>" <<desc <<"</p>\n";
break;
default:
ASSERT_not_reachable("invalid output format");
}
}
static void
showNotices(const Settings &settings, DB::Connection db, const Sawyer::Container ::Map<std::string, std::string> &props) { showNotices(const Settings &settings, DB::Connection db, const Sawyer::Container ::Map<std::string, std::string> &props) {
FormattedTable table; FormattedTable table;
table.indentation(" "); table.indentation(" ");
table.format(Format::HTML == settings.outputFormat ? FormattedTable::Format: :HTML : FormattedTable::Format::PLAIN);
boost::regex noticeRe("NOTICE-(\\d+)"); boost::regex noticeRe("NOTICE_(\\d+)");
for (auto node: props.nodes()) { for (auto node: props.nodes()) {
boost::smatch found; boost::smatch found;
if (boost::regex_match(node.key(), found, noticeRe)) { if (boost::regex_match(node.key(), found, noticeRe)) {
const size_t i = table.nRows(); const size_t i = table.nRows();
table.insert(i, 0, found.str(1)); std::string name = found.str(1);
if (8 == name.size()) // yyyyddmm
name = name.substr(0, 4) + "-" + name.substr(4, 2) + "-" + name.
substr(6);
table.insert(i, 0, name);
table.insert(i, 1, node.value()); table.insert(i, 1, node.value());
} }
} }
if (table.nRows() > 0) { if (table.nRows() > 0) {
std::cout <<"=========================================================== showSectionTitle(settings, "Notices to ROSE developers", "");
=====================\n" std::cout <<table <<"\n";
<<"=== Notices to ROSE developers
===\n"
<<"===========================================================
=====================\n"
<<"\n"
<<table
<<"\n";
} }
} }
static void static void
showSlaveConfig(const Settings &settings, DB::Connection db) { showSlaveConfig(const Settings &settings, DB::Connection db) {
Sawyer::Container::Map<std::string, std::string> props; Sawyer::Container::Map<std::string, std::string> props;
auto stmt = db.stmt("select name, value from slave_settings"); auto stmt = db.stmt("select name, value from slave_settings");
for (auto row: stmt) for (auto row: stmt)
props.insert(*row.get<std::string>(0), *row.get<std::string>(1)); props.insert(*row.get<std::string>(0), *row.get<std::string>(1));
showNotices(settings, db, props); showNotices(settings, db, props);
showSectionTitle(settings, "Slave configuration",
std::cout <<"=============================================================== "This section contains information about what the slaves sh
=================\n" ould be\n"
<<"=== Slave configuration "testing, and how. This is also the information you need if
===\n" you want\n"
<<"=============================================================== "to set up your own testing. See also, rose-matrix-slave-co
=================\n" nfig.\n");
<<"This section contains information about what the testing slaves
should be\n"
<<"testing, and how.\n"
<<"\n";
FormattedTable table; FormattedTable table;
table.indentation(" "); table.indentation(" ");
table.format(tableFormat(settings.outputFormat));
table.columnHeader(0, 0, "Operational setting"); table.columnHeader(0, 0, "Operational setting");
table.columnHeader(0, 1, "Value"); table.columnHeader(0, 1, "Value");
table.columnHeader(0, 2, "Key");
int i = 0; int i = 0;
Sawyer::Optional<std::string> testRepo = props.getOptional("TEST_REPOSITORY" ); Sawyer::Optional<std::string> testRepo = props.getOptional("TEST_REPOSITORY" );
table.insert(i, 0, "ROSE repository to be tested"); table.insert(i, 0, "ROSE repository to be tested");
table.insert(i, 2, "TEST_REPOSITORY");
if (testRepo && !testRepo->empty()) { if (testRepo && !testRepo->empty()) {
table.insert(i, 1, *testRepo); table.insert(i, 1, *testRepo);
} else { } else {
table.insert(i, 1, "testing is disabled"); table.insert(i, 1, "testing is disabled");
table.cellProperties(i, 1, badCell()); table.cellProperties(i, 1, badCell());
} }
++i; ++i;
Sawyer::Optional<std::string> testCommittish = props.getOptional("TEST_COMMI TTISH"); Sawyer::Optional<std::string> testCommittish = props.getOptional("TEST_COMMI TTISH");
table.insert(i, 0, "ROSE commit or tag to be tested"); table.insert(i, 0, "ROSE commit or tag to be tested");
table.insert(i, 2, "TEST_COMMITTISH");
if (testCommittish && !testCommittish->empty()) { if (testCommittish && !testCommittish->empty()) {
table.insert(i, 1, *testCommittish); table.insert(i, 1, *testCommittish);
} else { } else {
table.insert(i, 1, "testing is disabled"); table.insert(i, 1, "testing is disabled");
table.cellProperties(i, 1, badCell()); table.cellProperties(i, 1, badCell());
} }
i += 2; i += 2;
table.insert(i, 0, "Testing tools repository to be used"); table.insert(i, 0, "Tools repository to be used");
table.insert(i, 1, props.getOptional("MATRIX_REPOSITORY").orElse("none")); table.insert(i, 1, props.getOptional("MATRIX_REPOSITORY").orElse("none"));
table.insert(i, 2, "MATRIX_REPOSITORY");
++i; ++i;
table.insert(i, 0, "Testing tools commit or tag"); table.insert(i, 0, "Tools commit or tag");
table.insert(i, 1, props.getOptional("MATRIX_COMMITTISH").orElse("none")); table.insert(i, 1, props.getOptional("MATRIX_COMMITTISH").orElse("none"));
table.insert(i, 2, "MATRIX_COMMITTISH");
++i; ++i;
table.insert(i, 0, "Testing environment version"); table.insert(i, 0, "Tools environment version");
table.insert(i, 1, props.getOptional("TEST_ENVIRONMENT_VERSION").orElse("non e")); table.insert(i, 1, props.getOptional("TEST_ENVIRONMENT_VERSION").orElse("non e"));
table.insert(i, 2, "TEST_ENVIRONMENT_VERSION");
++i; ++i;
table.insert(i, 0, "Testing operational flags"); table.insert(i, 0, "Tools operational flags");
table.insert(i, 1, props.getOptional("TEST_FLAGS").orElse("none")); table.insert(i, 1, props.getOptional("TEST_FLAGS").orElse("none"));
table.insert(i, 2, "TEST_FLAGS");
i += 2; i += 2;
table.insert(i, 0, "Operating systems to be tested"); table.insert(i, 0, "Operating systems to be tested");
table.insert(i, 1, props.getOptional("TEST_OS").orElse("none")); table.insert(i, 1, props.getOptional("TEST_OS").orElse("none"));
table.insert(i, 2, "TEST_OS");
std::cout <<table <<"\n\n"; std::cout <<table <<"\n\n";
} }
static void static void
showSlaveHealth(const Settings &settings, DB::Connection db) { showSlaveHealth(const Settings &settings, DB::Connection db) {
std::cout <<"=============================================================== showSectionTitle(settings, "Slave health",
=================\n" "This section contains information about what slaves have r
<<"=== Slave health un in the last week.\n"
===\n" "Each slave typically reports many test results. See also,
<<"=============================================================== rose-matrix-slave-health.");
=================\n"
<<"This section contains information about what testing slaves hav const time_t since = time(NULL) - 7 * 86400;
e run in the last\n"
<<"week.\n"
<<"\n";
// 0 1 2 3 4 // 0 1 2 3 4 5
5 auto stmt = db.stmt("select name, timestamp, load_ave, free_space, event, te
auto stmt = db.stmt("select name, timestamp, load_ave, free_space, test_id, st_id"
event"
" from slave_health" " from slave_health"
" where timestamp >= ?since" " where timestamp >= ?since"
" order by timestamp desc, name") " order by timestamp desc, name")
.bind("since", time(NULL) - 7*86400); .bind("since", since);
FormattedTable table; FormattedTable table;
table.indentation(" "); table.indentation(" ");
table.format(tableFormat(settings.outputFormat));
table.columnHeader(0, 0, "Slave Name"); table.columnHeader(0, 0, "Slave Name");
table.columnHeader(0, 1, "Latest Report from Slave"); table.columnHeader(0, 1, "Latest Report from Slave");
table.columnHeader(0, 2, "Load\nAverage"); table.columnHeader(0, 2, "Load\nAverage");
table.columnHeader(0, 3, "Free\nSpace"); table.columnHeader(0, 3, "Free\nSpace");
table.columnHeader(0, 4, "Latest\nTest ID"); table.columnHeader(0, 4, "Latest\nEvent");
table.columnHeader(0, 5, "Latest\nEvent"); table.columnHeader(0, 5, "Latest\nTest ID");
table.columnHeader(0, 6, "Tests");
for (auto row: stmt) { for (auto row: stmt) {
const size_t i = table.nRows(); const size_t i = table.nRows();
table.insert(i, 0, row.get<std::string>(0).orElse("none")); const std::string slaveName = row.get<std::string>(0).orElse("none");
table.insert(i, 0, slaveName);
time_t whenReported = row.get<time_t>(1).orElse(0); time_t whenReported = row.get<time_t>(1).orElse(0);
table.insert(i, 1, timeToLocal(whenReported) + ", " + approximateAge(whe nReported)); table.insert(i, 1, timeToLocal(whenReported) + ", " + approximateAge(whe nReported));
table.insert(i, 2, (boost::format("%6.2f%%") % row.get<double>(2).orElse table.insert(i, 2, (boost::format("%6.2f%%") % (100.0*row.get<double>(2)
(0)).str()); .orElse(0))).str());
table.insert(i, 3, (boost::format("%.0f GB") % (row.get<size_t>(3).orEls table.insert(i, 3, (boost::format("%.0f GiB") % (row.get<size_t>(3).orEl
e(0) / 1024.0)).str()); se(0) / 1024.0)).str());
table.insert(i, 4, row.get<std::string>(4).orElse("none")); table.insert(i, 4, row.get<std::string>(4).orElse("none"));
table.insert(i, 5, row.get<std::string>(5).orElse("none")); table.insert(i, 5, row.get<std::string>(5).orElse("none"));
// This might be a little slow... The number of tests completed by this
slave in the same time interval as above.
size_t nTests = db.stmt("select count(*) from test_results where tester
= ?tester and reporting_time > ?since")
.bind("tester", slaveName)
.bind("since", since)
.get<size_t>().orElse(0);
if (nTests > 0) {
table.insert(i, 6, boost::lexical_cast<std::string>(nTests));
} else {
table.insert(i, 6, "");
}
} }
std::cout <<table <<"\n\n"; std::cout <<table <<"\n\n";
} }
// Show latest tested ROSE versions and return their commits, starting with the most recent // Subsection: versions of rose tested in the last month and return their versio ns
static std::vector<std::string> static std::vector<std::string>
showLatestTestedRoseVersions(const Settings &settings, DB::Connection db) { showLatestVersions(const Settings &settings, DB::Connection db) {
std::cout <<"=============================================================== const time_t since = time(NULL) - 30 * 86400;
=================\n" const std::string sinceHuman = timeToGmt(since).substr(0, 10);
<<"=== ROSE versions tested recently
===\n" showSubsectionTitle(settings, "ROSE version tested recently",
<<"=============================================================== "These are the ROSE versions that have test results in t
=================\n" he last month.\n"
<<"These are the ROSE versions that have test results in the last "This is similar to the command \"rose-matrix-query rose
week.\n" _date+" + sinceHuman +
<<"\n"; " rose.d reporting_time.min reporting_time.max\"");
// 0 1 2 3 4
auto stmt = db.stmt("select rose, rose_date, count(*), min(reporting_time), max(reporting_time)" auto stmt = db.stmt("select rose, rose_date, count(*), min(reporting_time), max(reporting_time)"
" from test_results" " from test_results"
" where reporting_time >= ?since" " where reporting_time >= ?since"
" group by rose, rose_date" " group by rose, rose_date"
" order by rose_date desc") " order by rose_date desc")
.bind("since", time(NULL) - 7 * 86400); .bind("since", since);
FormattedTable table; FormattedTable table;
table.indentation(" "); table.indentation(" ");
table.format(tableFormat(settings.outputFormat));
table.columnHeader(0, 0, "ROSE version"); table.columnHeader(0, 0, "ROSE version");
table.columnHeader(0, 1, "Commit date"); table.columnHeader(0, 1, "Commit date");
table.columnHeader(0, 2, "Test\nCount"); table.columnHeader(0, 2, "Tests");
table.columnHeader(0, 3, "Earliest\nTest"); table.columnHeader(0, 3, "Earliest\nTest");
table.columnHeader(0, 4, "Latest\nTest"); table.columnHeader(0, 4, "Latest\nTest");
std::vector<std::string> retval; std::vector<std::string> retval;
for (auto row: stmt) { for (auto row: stmt) {
const size_t i = table.nRows(); const size_t i = table.nRows();
retval.push_back(row.get<std::string>(0).orElse("unknown")); retval.push_back(row.get<std::string>(0).orElse("unknown"));
table.insert(i, 0, retval.back()); table.insert(i, 0, retval.back());
table.insert(i, 1, timeToLocal(row.get<time_t>(1).orElse(0))); table.insert(i, 1, timeToLocal(row.get<time_t>(1).orElse(0)));
table.insert(i, 2, row.get<std::string>(2).orElse("unknown")); table.insert(i, 2, row.get<std::string>(2).orElse("unknown"));
table.insert(i, 3, timeToLocal(row.get<time_t>(3).orElse(0))); if (auto earliest = row.get<time_t>(3))
table.insert(i, 4, timeToLocal(row.get<time_t>(4).orElse(0))); table.insert(i, 3, timeToLocal(*earliest) + ", " + approximateAge(*e
arliest));
if (auto latest = row.get<time_t>(4))
table.insert(i, 4, timeToLocal(*latest) + ", " + approximateAge(*lat
est));
}
std::cout <<table <<"\n\n";
return retval;
}
static void
showLatestTests(const Settings &settings, DB::Connection db) {
const time_t since = time(NULL) - 24 * 3600;
const std::string sinceHuman = timeToGmt(since);
showSubsectionTitle(settings, "Tests recently completed",
"These are the tests that completed in the last 24 hours
. This is similar to the command\n"
"\"rose-matrix-query reporting_time+" + StringUtility::b
ourneEscape(sinceHuman) + " rose reporting_time.d"
" slave id os compiler languages build boost status\"");
// 0 1 2 3 4 5
6 7 8 9
auto stmt = db.stmt("select rose, reporting_time, tester, id, os, rmc_compil
er, rmc_languages, rmc_build, rmc_boost, status"
" from test_results"
" where reporting_time > ?since"
" order by reporting_time desc"
" limit 100")
.bind("since", since);
FormattedTable table;
table.indentation(" ");
table.format(tableFormat(settings.outputFormat));
table.columnHeader(0, 0, "Rose\nVersion");
table.columnHeader(0, 1, "When Reported");
table.columnHeader(0, 2, "Slave Name");
table.columnHeader(0, 3, "Test\nID");
table.columnHeader(0, 4, "Operating\nSystem");
table.columnHeader(0, 5, "Compiler");
table.columnHeader(0, 6, "Analysis\nLanguages");
table.columnHeader(0, 7, "Build\nSystem");
table.columnHeader(0, 8, "Boost\nVersion");
table.columnHeader(0, 9, "Status");
for (auto row: stmt) {
const size_t i = table.nRows();
table.insert(i, 0, row.get<std::string>(0).orElse("unknown"));
const time_t reportingTime = *row.get<time_t>(1);
table.insert(i, 1, timeToLocal(reportingTime) + ", " + approximateAge(re
portingTime));
table.insert(i, 2, row.get<std::string>(2).orElse("unknown"));
table.insert(i, 3, row.get<std::string>(3).orElse("unknown"));
table.insert(i, 4, row.get<std::string>(4).orElse("unknown"));
table.insert(i, 5, row.get<std::string>(5).orElse("unknown"));
table.insert(i, 6, row.get<std::string>(6).orElse("unknown"));
table.insert(i, 7, row.get<std::string>(7).orElse("unknown"));
table.insert(i, 8, row.get<std::string>(8).orElse("unknown"));
const std::string status = row.get<std::string>(9).orElse("unknown");
table.insert(i, 9, row.get<std::string>(9).orElse("unknown"));
table.cellProperties(i, 9, "end" == status ? goodCell() : badCell());
} }
std::cout <<table <<"\n\n"; std::cout <<table <<"\n\n";
}
// Show latest tested ROSE versions and return their commits, starting with the
most recent
static std::vector<std::string>
showLatestTestSummaries(const Settings &settings, DB::Connection db) {
showSectionTitle(settings, "Recent tests");
std::vector<std::string> retval = showLatestVersions(settings, db);
showLatestTests(settings, db);
return retval; return retval;
} }
// Print some general information about a ROSE version and return true if it exi sts in the database // Print some general information about a ROSE version and return true if it exi sts in the database
static bool static bool
showRoseVersion(const Settings &settings, DB::Connection db, const std::string & roseVersion) { showRoseVersion(const Settings &settings, DB::Connection db, const std::string & roseVersion) {
auto commitTime = db.stmt("select rose_date from test_results where rose = ? rose limit 1") auto commitTime = db.stmt("select rose_date from test_results where rose = ? rose limit 1")
.bind("rose", roseVersion) .bind("rose", roseVersion)
.get<time_t>(); .get<time_t>();
skipping to change at line 263 skipping to change at line 395
return true; return true;
} else { } else {
mlog[ERROR] <<"ROSE version " <<roseVersion <<" does not exist in the da tabase\n"; mlog[ERROR] <<"ROSE version " <<roseVersion <<" does not exist in the da tabase\n";
return false; return false;
} }
} }
static void static void
showTestPhases(const Settings &settings, DB::Connection db) { showTestPhases(const Settings &settings, DB::Connection db) {
std::cout <<"=============================================================== showSectionTitle(settings, "Test phases",
=================\n" "These are the phases performed by each test. If a phase fa
<<"=== Test phases ils, the status for\n"
===\n" "the test is the name of the failed phase. The name \"end\"
<<"=============================================================== means that all\n"
=================\n" "phases of the test passed. The phases are executed in orde
<<"These are the phases performed by each test. If a phase fails, r until one fails\n"
the status for\n" "or the end is reached.");
<<"the test is the name of the failed phase. The name \"end\" mean
s that all\n"
<<"phases of the test passed. The phases are executed in order unt
il one fails\n"
<<"or the end is reached.\n"
<<"\n";
auto stmt = db.stmt("select name, purpose" auto stmt = db.stmt("select name, purpose"
" from test_names" " from test_names"
" where purpose is not null and purpose <> ''" " where purpose is not null and purpose <> ''"
" order by position"); " order by position");
FormattedTable table; FormattedTable table;
table.indentation(" "); table.indentation(" ");
table.format(tableFormat(settings.outputFormat));
table.columnHeader(0, 0, "Status"); table.columnHeader(0, 0, "Status");
table.columnHeader(0, 1, "Purpose"); table.columnHeader(0, 1, "Purpose");
for (auto row: stmt) { for (auto row: stmt) {
const std::string name = row.get<std::string>(0).orDefault(); const std::string name = row.get<std::string>(0).orDefault();
const size_t i = table.nRows(); const size_t i = table.nRows();
table.insert(i, 0, name); table.insert(i, 0, name);
table.cellProperties(i, 0, "end" == name ? goodCell() : badCell()); table.cellProperties(i, 0, "end" == name ? goodCell() : badCell());
table.insert(i, 1, *row.get<std::string>(1)); table.insert(i, 1, *row.get<std::string>(1));
} }
std::cout <<table <<"\n"; std::cout <<table <<"\n";
skipping to change at line 304 skipping to change at line 434
auto stmt = db.stmt("select " + fieldName + ", status, count(*)" auto stmt = db.stmt("select " + fieldName + ", status, count(*)"
" from test_results" " from test_results"
" left outer join test_names on (test_results.status = t est_names.name)" " left outer join test_names on (test_results.status = t est_names.name)"
" where rose = ?rose" " where rose = ?rose"
" group by " + fieldName + ", status, test_names.positio n" " group by " + fieldName + ", status, test_names.positio n"
" order by " + fieldName + ", test_names.position") " order by " + fieldName + ", test_names.position")
.bind("rose", roseVersion); .bind("rose", roseVersion);
FormattedTable table; FormattedTable table;
table.indentation(" "); table.indentation(" ");
table.format(tableFormat(settings.outputFormat));
table.columnHeader(0, 0, fieldTitle); table.columnHeader(0, 0, fieldTitle);
table.columnHeader(0, 1, "Reported\nStatus"); table.columnHeader(0, 1, "Reported\nStatus");
table.columnHeader(0, 2, "Test\nCount"); table.columnHeader(0, 2, "Tests");
std::string prevFieldValue; std::string prevFieldValue;
for (auto row: stmt) { for (auto row: stmt) {
const size_t i = table.nRows(); const size_t i = table.nRows();
const std::string fieldValue = row.get<std::string>(0).orElse("unknown") ; const std::string fieldValue = row.get<std::string>(0).orElse("unknown") ;
table.insert(i, 0, fieldValue == prevFieldValue ? "" : fieldValue); table.insert(i, 0, fieldValue == prevFieldValue ? "" : fieldValue);
const std::string status = row.get<std::string>(1).orElse("unknown"); const std::string status = row.get<std::string>(1).orElse("unknown");
table.insert(i, 1, status); table.insert(i, 1, status);
table.cellProperties(i, 1, "end" == status ? goodCell() : badCell()); table.cellProperties(i, 1, "end" == status ? goodCell() : badCell());
table.insert(i, 2, row.get<std::string>(2).orElse("unknwon")); table.insert(i, 2, row.get<std::string>(2).orElse("unknwon"));
prevFieldValue = fieldValue; prevFieldValue = fieldValue;
} }
std::cout <<table <<"\n"; std::cout <<table <<"\n";
} }
// Show test results sorted in various ways // Show test results sorted in various ways
static void static void
showTestResults(const Settings &settings, DB::Connection db, const std::string & roseVersion) { showTestResults(const Settings &settings, DB::Connection db, const std::string & roseVersion) {
std::cout <<"=============================================================== showSectionTitle(settings, "Test results",
=================\n" "These are the test results for ROSE version " + roseVersio
<<"=== Test results n);
===\n"
<<"===============================================================
=================\n"
<<"These are the test results for ROSE version " <<roseVersion <<"
\n"
<<"\n";
std::cout <<"Test results by analysis language:\n"; showSubsectionTitle(settings, "Test results by analysis language",
"Similar to \"rose-matrix-query rose=" + roseVersion + "
languages.a status count\"\n");
showTestResultsByField(settings, db, roseVersion, "rmc_languages", "Analysis \nLanguages"); showTestResultsByField(settings, db, roseVersion, "rmc_languages", "Analysis \nLanguages");
std::cout <<"Test results by operating system:\n"; showSubsectionTitle(settings, "Test results by operating system",
"Similar to \"rose-matrix-query rose=" + roseVersion + "
os.a status count\"\n");
showTestResultsByField(settings, db, roseVersion, "os", "Operating\nSystem") ; showTestResultsByField(settings, db, roseVersion, "os", "Operating\nSystem") ;
std::cout <<"Test results by host compiler:\n"; showSubsectionTitle(settings, "Test results by host compiler",
"Similar to \"rose-matrix-query rose=" + roseVersion + "
compiler.a status count\"\n");
showTestResultsByField(settings, db, roseVersion, "rmc_compiler", "Compiler" ); showTestResultsByField(settings, db, roseVersion, "rmc_compiler", "Compiler" );
std::cout <<"Test results by Boost version:\n"; showSubsectionTitle(settings, "Test results by Boost version",
"Similar to \"rose-matrix-query rose=" + roseVersion + "
boost.a status count\"\n");
showTestResultsByField(settings, db, roseVersion, "rmc_boost", "Boost\nVersi on"); showTestResultsByField(settings, db, roseVersion, "rmc_boost", "Boost\nVersi on");
} }
// Show error messages // Show error messages
static void static void
showErrorsByField(const Settings &settings, DB::Connection db, const std::string &roseVersion, showErrorsByField(const Settings &settings, DB::Connection db, const std::string &roseVersion,
const std::string &fieldName, const std::string &fieldT itle) { const std::string &fieldName, const std::string &fieldT itle) {
auto stmt = db.stmt("select " + fieldName + ", status, count(*) as count, fi rst_error" auto stmt = db.stmt("select " + fieldName + ", status, count(*) as count, fi rst_error"
" from test_results" " from test_results"
" left outer join test_names on (test_results.status = t est_names.name)" " left outer join test_names on (test_results.status = t est_names.name)"
" where rose = ?rose and status <> 'end' and first_error is not null and first_error <> ''" " where rose = ?rose and status <> 'end' and first_error is not null and first_error <> ''"
" group by " + fieldName + ", status, test_names.positio n, first_error" " group by " + fieldName + ", status, test_names.positio n, first_error"
" order by " + fieldName + ", test_names.position, count desc" " order by " + fieldName + ", test_names.position, count desc"
" limit 20") " limit 20")
.bind("rose", roseVersion); .bind("rose", roseVersion);
FormattedTable table; FormattedTable table;
table.indentation(" "); table.indentation(" ");
table.format(tableFormat(settings.outputFormat));
table.columnHeader(0, 0, fieldTitle); table.columnHeader(0, 0, fieldTitle);
table.columnHeader(0, 1, "Test\nStatus"); table.columnHeader(0, 1, "Test\nStatus");
table.columnHeader(0, 2, "Error\nCount"); table.columnHeader(0, 2, "Tests");
table.columnHeader(0, 3, "Error Message"); table.columnHeader(0, 3, "Error Message");
std::string prevFieldValue, prevStatus; std::string prevFieldValue, prevStatus;
for (auto row: stmt) { for (auto row: stmt) {
const size_t i = table.nRows(); const size_t i = table.nRows();
const std::string fieldValue = row.get<std::string>(0).orElse("unknown") ; const std::string fieldValue = row.get<std::string>(0).orElse("unknown") ;
table.insert(i, 0, fieldValue == prevFieldValue ? "" : fieldValue); table.insert(i, 0, fieldValue == prevFieldValue ? "" : fieldValue);
if (prevFieldValue != fieldValue) { if (prevFieldValue != fieldValue) {
prevFieldValue = fieldValue; prevFieldValue = fieldValue;
prevStatus = ""; prevStatus = "";
} }
skipping to change at line 385 skipping to change at line 518
prevStatus = status; prevStatus = status;
table.insert(i, 2, *row.get<std::string>(2)); table.insert(i, 2, *row.get<std::string>(2));
table.insert(i, 3, *row.get<std::string>(3)); table.insert(i, 3, *row.get<std::string>(3));
} }
std::cout <<table <<"\n"; std::cout <<table <<"\n";
} }
static void static void
showErrors(const Settings &settings, DB::Connection db, const std::string &roseV ersion) { showErrors(const Settings &settings, DB::Connection db, const std::string &roseV ersion) {
std::cout <<"=============================================================== showSectionTitle(settings, "Error messages",
=================\n" "These are the heuristically determined first error message
<<"=== Error messages s from testing\n"
===\n" "ROSE version " + roseVersion);
<<"===============================================================
=================\n"
<<"These are the heuristically determined first error messages fro
m testing\n"
<<"ROSE version " <<roseVersion <<"\n"
<<"\n";
std::cout <<"Errors by analysis language:\n"; showSubsectionTitle(settings, "Errors by analysis language",
"Similar to \"rose-matrix-query rose=" + roseVersion + "
languages.a status count first_error\"\n");
showErrorsByField(settings, db, roseVersion, "rmc_languages", "Analysis\nLan guages"); showErrorsByField(settings, db, roseVersion, "rmc_languages", "Analysis\nLan guages");
std::cout <<"Errors by operating system:\n"; showSubsectionTitle(settings, "Errors by operating system",
"Similar to \"rose-matrix-query rose=" + roseVersion + "
os.a status count first_error\"\n");
showErrorsByField(settings, db, roseVersion, "os", "Operation\nSystem"); showErrorsByField(settings, db, roseVersion, "os", "Operation\nSystem");
std::cout <<"Errors by host compiler:\n"; showSubsectionTitle(settings, "Errors by host compiler",
"Similar to \"rose-matrix-query rose=" + roseVersion + "
compiler.a status count first_error\"\n");
showErrorsByField(settings, db, roseVersion, "rmc_compiler", "Compiler"); showErrorsByField(settings, db, roseVersion, "rmc_compiler", "Compiler");
std::cout <<"Errors by boost version:\n"; showSubsectionTitle(settings, "Errors by boost version",
"Similar to \"rose-matrix-query rose=" + roseVersion + "
boost.a status count first_error\"\n");
showErrorsByField(settings, db, roseVersion, "rmc_boost", "Boost\nVersion"); showErrorsByField(settings, db, roseVersion, "rmc_boost", "Boost\nVersion");
} }
static void static void
showDependencies(const Settings &settings, DB::Connection db, const std::string
&roseVersion) {
showSectionTitle(settings, "Dependencies",
"These are the dependencies being tested at this time. The
Pass, Fail, and Grade\n"
"columns are for ROSE " + roseVersion + ".");
auto stmt = db.stmt("select name, value, restrictions, comment"
" from dependencies"
" where enabled > 0"
" order by name, value");
FormattedTable table;
table.indentation(" ");
table.format(tableFormat(settings.outputFormat));
table.columnHeader(0, 0, "Dependency\nName");
table.columnHeader(0, 1, "Dependency\nValue");
table.columnHeader(0, 2, "Restrictions");
table.columnHeader(0, 3, "Pass");
table.columnHeader(0, 4, "Fail");
table.columnHeader(0, 5, "Grade");
table.columnHeader(0, 6, "Comment");
Color::Gradient pfColors;
pfColors.insert(0.0, lighten(Color::HSV_RED, 0.4));
pfColors.insert(0.7, lighten(Color::HSV_RED, 0.4));
pfColors.insert(1.0, Color::HSV_GREEN);
std::string prevName;
for (auto row: stmt) {
const size_t i = table.nRows();
const std::string name = *row.get<std::string>(0);
const std::string value = *row.get<std::string>(1);
const std::string restrictions = row.get<std::string>(2).orElse("");
const std::string comment = row.get<std::string>(3).orElse("");
if (name != prevName) {
table.insert(i, 0, name);
prevName = name;
}
table.insert(i, 1, value);
table.insert(i, 2, restrictions);
size_t passFail[2] = {0, 0};
auto stmt2 = db.stmt("select"
" case when status = 'end' then 0 else 1 end as p
assed,"
" count(*)"
" from test_results"
" where rose = ?rose and rmc_" + name + " = ?value"
" group by passed")
.bind("rose", roseVersion)
.bind("value", value);
for (auto cr: stmt2)
passFail[*cr.get<size_t>(0)] = *cr.get<size_t>(1);
table.insert(i, 3, passFail[0]);
table.insert(i, 4, passFail[1]);
if (passFail[0] + passFail[1] > 0) {
double passRate = (double)passFail[0] / (passFail[0] + passFail[1]);
int percent = (int)::round(100.0 * passRate);
table.insert(i, 5, boost::lexical_cast<std::string>(percent) + "%");
FormattedTable::CellProperties props;
props.foreground(Color::HSV_BLACK);
props.background(pfColors(passRate));
table.cellProperties(i, 5, props);
}
table.insert(i, 6, comment);
}
std::cout <<table <<"\n";
}
static void
showAdditionalCommands(const Settings &settings, DB::Connection db, const std::s tring &roseVersion) { showAdditionalCommands(const Settings &settings, DB::Connection db, const std::s tring &roseVersion) {
std::cout <<"=============================================================== const std::string moreInfoUrl = "https://lep.is/w/index.php/ROSE:Portability
=================\n" _testing_results";
<<"=== Additional information const std::string moreInfoLink = Format::HTML == settings.outputFormat ?
===\n" "<a href=\"" + moreInfoUrl + "\">documentat
<<"=============================================================== ion</a>" :
=================\n" moreInfoUrl;
<<"This section lists some useful information for showing addition
al results.\n" showSectionTitle(settings, "Additional information",
<<"\n"; "The data above is only the tip of the iceburg.\n"
"See " + moreInfoLink + " for the rest of the iceburg.\n");
std::cout <<"1. Get test IDs having a certain error.\n\n" }
<<" To get a list of test IDs that had a certain error message,
use rose-matrix-query\n" static std::string
<<" and constrain the ROSE version, match (with the \"~\" operat timestamp() {
or) part of an error\n" time_t now = time(NULL);
<<" message, and display the operating system (\"os\"), test sta struct tm tm;
tus (\"status\"), and\n" gmtime_r(&now, &tm);
<<" test identification (\"id\").\n" return (boost::format("%04d-%02d-%02d %02d:%02d:%02d GMT")
<<"\n" % (tm.tm_year+1900) % (tm.tm_mon+1) % tm.tm_mday
<<" $ rose-matrix-query rose=" <<abbreviatedVersion(roseVersion) % tm.tm_hour % tm.tm_min % tm.tm_sec).str();
<<" \\\n"
<<" first_error~'undefined reference' os status id\n"
<<"\n"
<<" Use `rose-matrix-query --help` and `rose-matrix-query list`
to get information\n"
<<" about how to use this tool.\n"
<<"\n";
std::cout <<"2. Get the output from a test.\n\n"
<<" To get the final few hundred lines of output from a test, yo
u need to know the\n"
<<" test identification number, which you can get from `rose-mat
rix-query`, such as\n"
<<" the previous example. Then run `rose-matrix-output` with tha
t ID number. Example:\n"
<<"\n"
<<" $ rose-matrix-output 331483 |less\n"
<<"\n";
std::cout <<"3. View test attachments.\n\n"
<<" The `rose-matrix-output` shell script in the previous exampl
e simply runs the\n"
<<" `rose-matrix-attachments` tool to print the test output atta
chments. There are\n"
<<" often additional attachments for a test, such as a summary o
f each step that was\n"
<<" run during the test.\n"
<<"\n"
<<" To get the list of attachments for a test, give just a test
ID, as in:\n"
<<"\n"
<<" $ rose-matrix-attachments 331483\n"
<<" [440904] \"Commands\"\n"
<<" [440905] \"Final output\"\n"
<<"\n"
<<" To view the attachment called \"Commands\", run:\n"
<<"\n"
<<" $ rose-matrix-attachments 331483 440904\n"
<<"\n"
<<" Among other things, this has the list of ROSE dependencies a
nd versions that were\n"
<<" employed by the test, the complete ROSE configure command-li
ne, and the locations\n"
<<" of the most frequent compiler warning messages from compilin
g the ROSE library.\n"
<<"\n";
std::cout <<"4. See what dependencies are configured for testing.\n\n"
<<" Portability tests have two kinds of dependencies: (1) depend
encies that are installed\n"
<<" system-wide on the operating system in which the test runs,
such as bash, grep, perl,\n"
<<" the system C++ compiler, etc., and (2) dependencies that are
installed per test, such as\n"
<<" Boost, Z3, Python, Doxygen, and non-system C++ compilers. Th
e latter are managed by\n"
<<" RMC/Spock -- the Rose Meta-Configuration System. The `rose-
matrix-dependencies` tool\n"
<<" can show you what dependencies are being tested. A dependenc
y that's \"enabled\" is\n"
<<" one for which tests are being requested. Some dependencies a
re marked as being\n"
<<" supported, which means errors with these dependencies are of
particular interest to\n"
<<" the ROSE development team.\n"
<<"\n"
<<" $ rose-matrix-dependencies names # Show all the depende
ncy categories\n"
<<" $ rose-matrix-dependencies list boost # Show information for
one category\n"
<<"\n";
std::cout <<"5. Reproduce a build environment for debugging.\n\n"
<<" Users can easliy install RMC/Spock in their home directories
in order to mostly replicate\n"
<<" the environment in which a test was run. You'll still have t
o install any system dependencies\n"
<<" manually, but any ROSE developer should already have these a
nyway. RMC/Spock is available\n"
<<" from https://github.com/matzke1/rmc-spock. Install or upgrad
e it with:\n"
<<"\n"
<<" $ git clone https://github.com/matzke1/rmc-spock\n"
<<" $ (cd rmc-spock && ./scripts/bootstrap.sh)\n"
<<" $ rm -rf rmc-spock\n"
<<" $ export PATH=\"$HOME/.spock/bin\"\n"
<<" $ rm -rf ~/.spock # If you ever want to totally remove it\n"
<<"\n"
<<" To reproduce a build environment, create a \"_build\" subdir
ectory at the top of your\n"
<<" ROSE source tree, then use the `rose-matrix-attachments` com
mand mentioned earlier to\n"
<<" download the \".rmc-main.cfg\" file for the test whose build
environment you want to\n"
<<" recreate. Then, run these commands:\n"
<<"\n"
<<" $ cd _build\n"
<<" $ rmc # this installs dependencies and puts you in a subshel
l\n"
<<" $ rmc build # this runs ROSE's \"build\" script\n"
<<" $ rmc config # run ROSE's \"configure\" script; use -n to se
e the command without running it\n"
<<" $ rmc make # or run \"make\" or \"tup\" (depending on teh bu
ild system) manually\n"
<<"\n";
} }
int int
main(int argc, char *argv[]) { main(int argc, char *argv[]) {
ROSE_INITIALIZE; ROSE_INITIALIZE;
Diagnostics::initAndRegister(&mlog, "tool"); Diagnostics::initAndRegister(&mlog, "tool");
if (boost::starts_with(Rose::CommandLine::versionString, "ROSE "))
Rose::CommandLine::versionString = Rose::CommandLine::versionString.subs
tr(5);
Settings settings; Settings settings;
const std::vector<std::string> args = parseCommandLine(argc, argv, settings) ; const std::vector<std::string> args = parseCommandLine(argc, argv, settings) ;
if (settings.databaseUri.empty()) { DB::Connection db = connectToDatabase(settings.databaseUri, mlog);
mlog[FATAL] <<"no database specified\n";
mlog[INFO] <<"You need to use the --database switch, or set your ROSE_MA if (Format::HTML == settings.outputFormat) {
TRIX_DATABASE environment\n" std::cout <<"<!DOCTYPE html>\n"
<<"variable. See the \"Testing\" section of https://toc.rosec <<"<html>\n"
ompiler.org for the proper\n" <<"<head>\n"
<<"setting.\n"; <<" <title>ROSE Portability Testing</title>\n"
exit(1); <<"</head>\n"
<<"<body>\n"
<<"<h1>ROSE Portability Testing</h1>\n"
<<"Updated at " <<timestamp() <<" from the <tt>rose-matrix-sta
tus</tt> version "
<<Rose::CommandLine::versionString <<".<br/>\n";
} }
auto db = DB::Connection::fromUri(settings.databaseUri);
showSlaveConfig(settings, db); showSlaveConfig(settings, db);
showSlaveHealth(settings, db); showSlaveHealth(settings, db);
std::vector<std::string> roseCommits = showLatestTestedRoseVersions(settings , db); std::vector<std::string> roseCommits = showLatestTestSummaries(settings, db) ;
showTestPhases(settings, db); showTestPhases(settings, db);
if (!settings.roseVersion.empty()) { if (!settings.roseVersion.empty()) {
roseCommits.clear(); roseCommits.clear();
roseCommits.push_back(settings.roseVersion); roseCommits.push_back(settings.roseVersion);
std::cerr <<"The following output is limited to the version selected fro m the command line, namely\n"; std::cerr <<"The following output is limited to the version selected fro m the command line, namely\n";
if (!showRoseVersion(settings, db, roseCommits.back())) if (!showRoseVersion(settings, db, roseCommits.back()))
exit(1); // user requested a version, but we can't show it; error wa s already printed exit(1); // user requested a version, but we can't show it; error wa s already printed
std::cerr <<"\n\n"; std::cerr <<"\n\n";
} }
if (roseCommits.empty()) if (roseCommits.empty())
exit(0); exit(0);
showTestResults(settings, db, roseCommits.front()); showTestResults(settings, db, roseCommits.front());
showErrors(settings, db, roseCommits.front()); showErrors(settings, db, roseCommits.front());
showDependencies(settings, db, roseCommits.front());
showAdditionalCommands(settings, db, roseCommits.front()); showAdditionalCommands(settings, db, roseCommits.front());
if (Format::HTML == settings.outputFormat)
std::cout <<"</body></html>\n";
} }
 End of changes. 63 change blocks. 
241 lines changed or deleted 357 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)