123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- /*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include <atomic>
- #include "include/core/SkGraphics.h"
- #include "include/core/SkTime.h"
- #include "include/gpu/GrContext.h"
- #include "include/private/SkTArray.h"
- #include "include/private/SkTemplates.h"
- #include "src/core/SkOSFile.h"
- #include "src/core/SkTaskGroup.h"
- #include "src/pathops/SkPathOpsDebug.h"
- #include "tests/PathOpsDebug.h"
- #include "tests/Test.h"
- #include "tools/CrashHandler.h"
- #include "tools/OverwriteLine.h"
- #include "tools/Resources.h"
- #include "tools/flags/CommandLineFlags.h"
- #include "tools/gpu/GrContextFactory.h"
- using namespace skiatest;
- using namespace sk_gpu_test;
- static DEFINE_bool2(dumpOp, d, false, "dump the pathOps to a file to recover mid-crash.");
- static DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
- static DEFINE_bool2(runFail, f, false, "check for success on tests known to fail.");
- static DEFINE_bool2(verifyOp, y, false, "compare the pathOps result against a region.");
- static DEFINE_string2(json, J, "", "write json version of tests.");
- static DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver.");
- static DEFINE_bool2(veryVerbose, V, false, "tell individual tests to be verbose.");
- static DEFINE_bool(cpu, true, "master switch for running CPU-bound work.");
- static DEFINE_bool(gpu, true, "master switch for running GPU-bound work.");
- static DEFINE_string2(match, m, nullptr,
- "[~][^]substring[$] [...] of name to run.\n"
- "Multiple matches may be separated by spaces.\n"
- "~ causes a matching name to always be skipped\n"
- "^ requires the start of the name to match\n"
- "$ requires the end of the name to match\n"
- "^ and $ requires an exact match\n"
- "If a name does not match any list entry,\n"
- "it is skipped unless some list entry starts with ~");
- static DEFINE_int_2(threads, j, -1,
- "Run threadsafe tests on a threadpool with this many extra threads, "
- "defaulting to one extra thread per core.");
- #if DEBUG_COIN
- static DEFINE_bool2(coinTest, c, false, "detect unused coincidence algorithms.");
- #endif
- // need to explicitly declare this, or we get some weird infinite loop llist
- template TestRegistry* TestRegistry::gHead;
- void (*gVerboseFinalize)() = nullptr;
- // The threads report back to this object when they are done.
- class Status {
- public:
- explicit Status(int total)
- : fDone(0), fTestCount(0), fFailCount(0), fTotal(total) {}
- // Threadsafe.
- void endTest(const char* testName,
- bool success,
- SkMSec elapsed,
- int testCount) {
- const int done = ++fDone;
- fTestCount += testCount;
- if (!success) {
- SkDebugf("\n---- %s FAILED", testName);
- }
- SkString prefix(kSkOverwriteLine);
- SkString time;
- if (FLAGS_verbose) {
- prefix.printf("\n");
- time.printf("%5dms ", elapsed);
- }
- SkDebugf("%s[%3d/%3d] %s%s", prefix.c_str(), done, fTotal, time.c_str(),
- testName);
- }
- void reportFailure() { fFailCount++; }
- int32_t testCount() { return fTestCount; }
- int32_t failCount() { return fFailCount; }
- private:
- std::atomic<int32_t> fDone;
- std::atomic<int32_t> fTestCount;
- std::atomic<int32_t> fFailCount;
- const int fTotal;
- };
- class SkTestRunnable {
- public:
- SkTestRunnable(const Test& test, Status* status) : fTest(test), fStatus(status) {}
- void operator()() {
- struct TestReporter : public skiatest::Reporter {
- public:
- TestReporter() : fStats(nullptr), fError(false), fTestCount(0) {}
- void bumpTestCount() override { ++fTestCount; }
- bool allowExtendedTest() const override { return FLAGS_extendedTest; }
- bool verbose() const override { return FLAGS_veryVerbose; }
- void reportFailed(const skiatest::Failure& failure) override {
- SkDebugf("\nFAILED: %s", failure.toString().c_str());
- fError = true;
- }
- void* stats() const override { return fStats; }
- void* fStats;
- bool fError;
- int fTestCount;
- } reporter;
- const Timer timer;
- fTest.proc(&reporter, GrContextOptions());
- SkMSec elapsed = timer.elapsedMsInt();
- if (reporter.fError) {
- fStatus->reportFailure();
- }
- fStatus->endTest(fTest.name, !reporter.fError, elapsed, reporter.fTestCount);
- }
- private:
- Test fTest;
- Status* fStatus;
- };
- static bool should_run(const char* testName, bool isGPUTest) {
- if (CommandLineFlags::ShouldSkip(FLAGS_match, testName)) {
- return false;
- }
- if (!FLAGS_cpu && !isGPUTest) {
- return false;
- }
- if (!FLAGS_gpu && isGPUTest) {
- return false;
- }
- return true;
- }
- int main(int argc, char** argv) {
- CommandLineFlags::Parse(argc, argv);
- #if DEBUG_DUMP_VERIFY
- SkPathOpsDebug::gDumpOp = FLAGS_dumpOp;
- SkPathOpsDebug::gVerifyOp = FLAGS_verifyOp;
- #endif
- SkPathOpsDebug::gRunFail = FLAGS_runFail;
- SkPathOpsDebug::gVeryVerbose = FLAGS_veryVerbose;
- PathOpsDebug::gOutFirst = true;
- PathOpsDebug::gCheckForDuplicateNames = false;
- PathOpsDebug::gOutputSVG = false;
- if ((PathOpsDebug::gJson = !FLAGS_json.isEmpty())) {
- PathOpsDebug::gOut = fopen(FLAGS_json[0], "wb");
- fprintf(PathOpsDebug::gOut, "{\n");
- FLAGS_threads = 0;
- PathOpsDebug::gMarkJsonFlaky = false;
- }
- SetupCrashHandler();
- SkAutoGraphics ag;
- {
- SkString header("Skia UnitTests:");
- if (!FLAGS_match.isEmpty()) {
- header.appendf(" --match");
- for (int index = 0; index < FLAGS_match.count(); ++index) {
- header.appendf(" %s", FLAGS_match[index]);
- }
- }
- SkString tmpDir = skiatest::GetTmpDir();
- if (!tmpDir.isEmpty()) {
- header.appendf(" --tmpDir %s", tmpDir.c_str());
- }
- SkString resourcePath = GetResourcePath();
- if (!resourcePath.isEmpty()) {
- header.appendf(" --resourcePath %s", resourcePath.c_str());
- }
- #if DEBUG_COIN
- if (FLAGS_coinTest) {
- header.appendf(" -c");
- }
- #endif
- if (FLAGS_dumpOp) {
- header.appendf(" -d");
- }
- #ifdef SK_DEBUG
- if (FLAGS_runFail) {
- header.appendf(" -f");
- }
- #endif
- if (FLAGS_verbose) {
- header.appendf(" -v");
- }
- if (FLAGS_veryVerbose) {
- header.appendf(" -V");
- }
- if (FLAGS_extendedTest) {
- header.appendf(" -x");
- }
- if (FLAGS_verifyOp) {
- header.appendf(" -y");
- }
- #ifdef SK_DEBUG
- header.append(" SK_DEBUG");
- #else
- header.append(" SK_RELEASE");
- #endif
- if (FLAGS_veryVerbose) {
- header.appendf("\n");
- }
- SkDebugf("%s", header.c_str());
- }
- // Count tests first.
- int total = 0;
- int toRun = 0;
- for (const Test& test : TestRegistry::Range()) {
- if (should_run(test.name, test.needsGpu)) {
- toRun++;
- }
- total++;
- }
- // Now run them.
- int skipCount = 0;
- SkTaskGroup::Enabler enabled(FLAGS_threads);
- SkTaskGroup cpuTests;
- SkTArray<const Test*> gpuTests;
- Status status(toRun);
- for (const Test& test : TestRegistry::Range()) {
- if (!should_run(test.name, test.needsGpu)) {
- ++skipCount;
- } else if (test.needsGpu) {
- gpuTests.push_back(&test);
- } else {
- cpuTests.add(SkTestRunnable(test, &status));
- }
- }
- // Run GPU tests on this thread.
- for (int i = 0; i < gpuTests.count(); i++) {
- SkTestRunnable(*gpuTests[i], &status)();
- }
- // Block until threaded tests finish.
- cpuTests.wait();
- if (FLAGS_verbose) {
- SkDebugf(
- "\nFinished %d tests, %d failures, %d skipped. "
- "(%d internal tests)",
- toRun, status.failCount(), skipCount, status.testCount());
- if (gVerboseFinalize) {
- (*gVerboseFinalize)();
- }
- }
- SkDebugf("\n");
- #if DEBUG_COIN
- if (FLAGS_coinTest) {
- SkPathOpsDebug::DumpCoinDict();
- }
- #endif
- if (PathOpsDebug::gJson) {
- fprintf(PathOpsDebug::gOut, "\n}\n");
- fclose(PathOpsDebug::gOut);
- }
- return (status.failCount() == 0) ? 0 : 1;
- }
|