add --race to FM

Try to uncover races by running parallel replicas.

The default --race 0 should keep FM working as before, but now with
--race ≥2 we'll actively try to race replicas, syncing between tests.
--race 1 is almost pointless, just changing the thread tests run on but
without any interesting concurrency.

Rearrange a bit how fm_driver decides what flags to pass to which
invocations of FM, so individual runs can easily override defaults (e.g.
--nativeFonts overriding the usual --nonativeFonts).  Use that here to
set --race 0 for unit tests; many unit tests are not reentrant.

Change-Id: Ida451626c093793b0805d3036beb185e7d54f27e
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/376761
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Eric Boren <borenet@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
This commit is contained in:
Mike Klein 2021-03-01 10:57:01 -06:00
parent b7b9a23281
commit bc4a36af7c
2 changed files with 39 additions and 17 deletions

View File

@ -397,10 +397,15 @@ func main() {
parts := strings.Split(*bot, "-")
OS, model, CPU_or_GPU := parts[1], parts[3], parts[4]
commonFlags := []string{}
// Bots use portable fonts except where we explicitly opt-in to native fonts.
defaultFlags := []string{"--nonativeFonts"}
run := func(sources []string, extraFlags string) {
kickoff(sources, append(strings.Fields(extraFlags), commonFlags...))
// Default then extra to allow overriding the defaults.
flags := []string{}
flags = append(flags, defaultFlags...)
flags = append(flags, strings.Fields(extraFlags)...)
kickoff(sources, flags)
}
gms := shorthands["gms"]
@ -423,19 +428,21 @@ func main() {
imgs = filter(imgs, func(s string) bool { return !rawExts[normalizedExt(s)] })
}
if CPU_or_GPU == "CPU" {
commonFlags = append(commonFlags, "-b", "cpu")
if strings.Contains(*bot, "TSAN") {
// Run each test a few times in parallel to uncover races.
defaultFlags = append(defaultFlags, "--race", "4")
}
// Run GMs once using native fonts, then switch to portable fonts for everything else.
run(gms, "--nativeFonts true")
commonFlags = append(commonFlags, "--nativeFonts", "false")
if CPU_or_GPU == "CPU" {
defaultFlags = append(defaultFlags, "-b", "cpu")
// FM's default ct/gamut/tf flags are equivalent to --config srgb in DM.
run(gms, "")
run(gms, "--nativeFonts")
run(imgs, "")
run(svgs, "")
run(skps, "--clipW 1000 --clipH 1000")
run(tests, "")
run(tests, "--race 0") // Several unit tests are not reentrant.
if model == "GCE" {
run(gms, "--ct g8 --legacy") // --config g8

View File

@ -16,6 +16,7 @@
#include "src/core/SkColorSpacePriv.h"
#include "src/core/SkMD5.h"
#include "src/core/SkOSFile.h"
#include "src/core/SkTaskGroup.h"
#include "src/gpu/GrDirectContextPriv.h"
#include "src/gpu/GrGpu.h"
#include "src/utils/SkOSPath.h"
@ -82,6 +83,7 @@ static DEFINE_int(clipH, INT_MAX, "Limit source height.");
static DEFINE_bool (cpuDetect, true, "Detect CPU features for runtime optimizations?");
static DEFINE_string2(writePath, w, "", "Write .pngs to this directory if set.");
static DEFINE_bool (quick, false, "Skip image hashing and encoding?");
static DEFINE_int (race, 0, "If >0, use threads to induce race conditions?");
static DEFINE_string(writeShaders, "", "Write GLSL shaders to this directory if set.");
@ -372,6 +374,7 @@ extern bool gSkVMJITViaDylib;
int main(int argc, char** argv) {
CommandLineFlags::Parse(argc, argv);
SetupCrashHandler();
SkTaskGroup::Enabler enabled(FLAGS_race);
if (FLAGS_cpuDetect) {
SkGraphics::Init();
@ -423,8 +426,11 @@ int main(int argc, char** argv) {
return 1;
}
const int replicas = std::max(1, FLAGS_race);
SkTArray<Source> sources;
for (const SkString& name : FLAGS_sources) {
for (const SkString& name : FLAGS_sources)
for (int replica = 0; replica < replicas; replica++) {
Source* source = &sources.push_back();
source->name = name;
@ -549,7 +555,10 @@ int main(int argc, char** argv) {
: SkColorSpace::MakeRGB(tf,gamut);
const SkColorInfo color_info{ct,at,cs};
for (auto source : sources) {
for (int i = 0; i < sources.count(); i += replicas)
SkTaskGroup{}.batch(replicas, [=](int replica) {
Source source = sources[i+replica];
AutoreleasePool pool;
const auto start = std::chrono::steady_clock::now();
@ -593,12 +602,6 @@ int main(int argc, char** argv) {
break;
}
if (!image && !blob) {
fprintf(stdout, "%50s skipped\n", source.name.c_str());
fflush(stdout);
continue;
}
// We read back a bitmap even when --quick is set and we won't use it,
// to keep us honest about deferred work, flushing pipelines, etc.
SkBitmap bitmap;
@ -606,6 +609,17 @@ int main(int argc, char** argv) {
SK_ABORT("SkImage::asLegacyBitmap() failed.");
}
// Our --race replicas have done their job by now if they're going to catch anything.
if (replica != 0) {
return;
}
if (!image && !blob) {
fprintf(stdout, "%50s skipped\n", source.name.c_str());
fflush(stdout);
return;
}
SkString md5;
if (!FLAGS_quick) {
HashAndEncode hashAndEncode{bitmap};
@ -646,7 +660,8 @@ int main(int argc, char** argv) {
md5.c_str(),
(int)std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count());
fflush(stdout);
}
});
if (!FLAGS_writeShaders.isEmpty()) {
sk_mkdir(FLAGS_writeShaders[0]);