-
Notifications
You must be signed in to change notification settings - Fork 5
Multithreading Implementation #45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
9ed543b
ab0ac82
e6777c0
71f9962
c57ed72
1a65cc6
e1ef0a1
10ab31f
723a411
f518f6c
66e52d1
6594a08
2e44d29
3afde6a
ccf8cfd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| #include "config/Config.h" | ||
| #include "testharness/ResultManager.h" | ||
| #include "tests/TestParser.h" | ||
| #include "tests/TestResult.h" | ||
| #include "toolchain/ToolChain.h" | ||
|
|
||
| #include <filesystem> | ||
|
|
@@ -17,7 +18,8 @@ namespace fs = std::filesystem; | |
| namespace tester { | ||
|
|
||
| // Test hierarchy types | ||
| typedef std::vector<std::unique_ptr<TestFile>> SubPackage; | ||
| typedef std::pair<std::unique_ptr<TestFile>, std::optional<TestResult>> TestPair; | ||
| typedef std::vector<TestPair> SubPackage; | ||
| typedef std::map<std::string, SubPackage> Package; | ||
| typedef std::map<std::string, Package> TestSet; | ||
|
|
||
|
|
@@ -49,19 +51,33 @@ class TestHarness { | |
| // A separate subpackage, just for invalid tests. | ||
| SubPackage invalidTests; | ||
|
|
||
| protected: | ||
| // let derived classes find tests. | ||
| void findTests(); | ||
|
|
||
| private: | ||
| // The results of the tests. | ||
| // NOTE we keep both a result manager and | ||
| // the result in the TestSet to ensure in-ordre | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ordre -> order |
||
| // printing | ||
| ResultManager results; | ||
|
|
||
| private: | ||
| // thread control | ||
| void spawnThreads(); | ||
|
|
||
| // test running | ||
| bool runTestsForToolChain(std::string tcId, std::string exeName); | ||
| void threadRunTestBatch(std::reference_wrapper<std::vector<std::string>> toolchains, | ||
| std::reference_wrapper<std::vector<std::string>> executables, | ||
| std::reference_wrapper<std::vector<std::reference_wrapper<TestPair>>> tests, | ||
| std::reference_wrapper<size_t> currentIndex, std::reference_wrapper<std::mutex> lock); | ||
| void threadRunTestsForToolChain(std::reference_wrapper<std::vector<std::string>> tcIds, | ||
| std::reference_wrapper<std::vector<std::string>> exeNames, | ||
| std::reference_wrapper<std::vector<std::reference_wrapper<TestPair>>> tests, size_t begin, size_t end); | ||
|
|
||
| // helper for formatting tester output | ||
| void printTestResult(const TestFile *test, TestResult result); | ||
| bool aggregateTestResultsForToolChain(std::string tcName, std::string exeName); | ||
|
|
||
| // test finding and filling methods | ||
| void addTestFileToSubPackage(SubPackage& subPackage, const fs::path& file); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,12 +17,21 @@ struct TestResult { | |
| : name(in.stem()), pass(pass), error(error), diff(diff) {} | ||
|
|
||
| // Info about result. | ||
| const fs::path name; | ||
| const bool pass; | ||
| const bool error; | ||
| const std::string diff; | ||
| }; | ||
| fs::path name; | ||
| bool pass; | ||
| bool error; | ||
| std::string diff; | ||
|
|
||
| TestResult clone() { return TestResult(this->name, this->pass, this->error, this->diff); } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a copy constructor in TestResult, namely
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looking further, I'm not sure this is ever necessary. But if it were, it should be the copy constructor or possibly |
||
|
|
||
| void swap(TestResult &other) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any reason that this can't just be |
||
| std::swap(name, other.name); | ||
| std::swap(pass, other.pass); | ||
| std::swap(error, other.error); | ||
| std::swap(diff, other.diff); | ||
| } | ||
|
|
||
| }; | ||
| } // End namespace tester | ||
|
|
||
| #endif // TESTER_TEST_RESULT_H | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| #include "analysis/Grader.h" | ||
| #include <algorithm> | ||
| #include <iostream> | ||
| #include <thread> | ||
|
|
||
| namespace { | ||
|
|
||
|
|
@@ -125,10 +126,16 @@ void Grader::fillToolchainResultsJSON() { | |
| // attacker, tracking pass count. | ||
| size_t passCount = 0, testCount = 0; | ||
| for (const auto& subpackages : testSet[attacker]) { | ||
| for (const std::unique_ptr<TestFile>& test : subpackages.second) { | ||
| for (const TestPair& testpair : subpackages.second) { | ||
| const std::unique_ptr<TestFile>& test = testpair.first; | ||
| // Poll while we wait for the result | ||
| // TODO this could probably be replaced with some sort of interrupt, | ||
| // (and probably should be), but better this than no threads | ||
| while (!testpair.second.has_value()) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Technically, I think option is probably not thread safe, so |
||
| std::this_thread::sleep_for(std::chrono::milliseconds(100)); | ||
|
|
||
| TestResult result = testpair.second.value(); | ||
|
|
||
| TestResult result = runTest(test.get(), tc, cfg); | ||
|
|
||
| if (!result.pass && defender == solutionExecutable) { | ||
| if ( attacker == solutionExecutable ) { | ||
| // A testcase just failed the solution executable | ||
|
|
@@ -178,4 +185,4 @@ void Grader::buildResults() { | |
| fillToolchainResultsJSON(); | ||
| } | ||
|
|
||
| } // End namespace tester | ||
| } // End namespace tester | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize these feel like much the same thing, but this shouldn't be
std::option, it should be using the promise/future mechanism(std::promise, std::future). It has the same sort of mechanism asstd::optionfor being in a limbo state with no value, but the outward appearance is immediately apparent to those familiar with the terms. "Option" should be for a value that may or may not have a value, "promise" is for a promised value that will arrive, just in the future, "future" is for getting that promised value.std::futurealso comes with the busy wait mechanism built in atstd::future::wait.In particular,
std::optionalshould be replaced here withstd::promise.