2014-07-18 16:08:14 +04:00
|
|
|
#include "CrashHandler.h"
|
|
|
|
// #include "OverwriteLine.h"
|
|
|
|
#include "Resources.h"
|
2013-05-08 11:01:40 +04:00
|
|
|
#include "SkBitmap.h"
|
2013-11-01 21:36:03 +04:00
|
|
|
#include "SkCanvas.h"
|
2013-10-02 18:49:34 +04:00
|
|
|
#include "SkColor.h"
|
2013-11-01 21:36:03 +04:00
|
|
|
#include "SkColorPriv.h"
|
2014-07-18 16:08:14 +04:00
|
|
|
#include "SkCommandLineFlags.h"
|
2013-05-08 11:01:40 +04:00
|
|
|
#include "SkDevice.h"
|
2014-07-18 16:08:14 +04:00
|
|
|
#include "SkForceLinking.h"
|
2013-11-01 21:36:03 +04:00
|
|
|
#include "SkGraphics.h"
|
2013-06-04 21:59:42 +04:00
|
|
|
#include "SkImageDecoder.h"
|
2013-05-08 11:01:40 +04:00
|
|
|
#include "SkImageEncoder.h"
|
|
|
|
#include "SkOSFile.h"
|
2013-11-01 21:36:03 +04:00
|
|
|
#include "SkPathOpsDebug.h"
|
2013-05-08 11:01:40 +04:00
|
|
|
#include "SkPicture.h"
|
2013-11-01 21:36:03 +04:00
|
|
|
#include "SkRTConf.h"
|
2014-10-29 22:36:45 +03:00
|
|
|
#include "SkRunnable.h"
|
2014-04-14 21:08:59 +04:00
|
|
|
#include "SkTSort.h"
|
2013-11-01 21:36:03 +04:00
|
|
|
#include "SkStream.h"
|
2013-05-08 11:01:40 +04:00
|
|
|
#include "SkString.h"
|
2013-11-01 21:36:03 +04:00
|
|
|
#include "SkTArray.h"
|
|
|
|
#include "SkTDArray.h"
|
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in
one global pool. Each SkTaskGroup itself is tiny (4 bytes)
and its wait() method applies only to tasks add()ed to that
instance, not the whole thread pool.
This means we don't need to bring up new thread pools when
tests themselves want to use multithreading (e.g. pathops,
quilt). We just create a new SkTaskGroup and wait for that
to complete. This should be more efficient, and allow us
to expand where we use threads to really latency sensitive
places. E.g. we can probably now use these in nanobench
for CPU .skp rendering.
Now that all threads are sharing the same pool, I think we
can remove most of the custom mechanism pathops tests use
to control threading. They'll just ride on the global pool
with all other tests now.
This (temporarily?) removes the GPU multithreading feature
from DM, which we don't use.
On my desktop, DM runs a little faster (57s -> 55s) in
Debug, and a lot faster in Release (36s -> 24s). The bots
show speedups of similar proportions, cutting more than a
minute off the N4/Release and Win7/Debug runtimes.
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f
R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/531653002
2014-09-04 02:34:37 +04:00
|
|
|
#include "SkTaskGroup.h"
|
2014-07-18 16:08:14 +04:00
|
|
|
#include "SkTemplates.h"
|
2013-11-01 21:36:03 +04:00
|
|
|
#include "SkTime.h"
|
2014-07-18 16:08:14 +04:00
|
|
|
|
|
|
|
__SK_FORCE_IMAGE_DECODER_LINKING;
|
|
|
|
|
|
|
|
/* add local exceptions here */
|
|
|
|
/* TODO : add command flag interface */
|
|
|
|
const struct SkipOverTest {
|
|
|
|
int directory;
|
|
|
|
const char* filename;
|
|
|
|
bool blamePathOps;
|
|
|
|
} skipOver[] = {
|
|
|
|
{ 2, "http___www_groupon_sg_.skp", false}, // SkAAClip::Builder::addRun SkASSERT(fBounds.contains(x, y));
|
|
|
|
{ 6, "http___www_googleventures_com_.skp", true}, // addTCoincident SkASSERT(test->fT < 1);
|
|
|
|
{ 7, "http___www_foxsports_nl_.skp", true}, // (no repro on mac) addT SkASSERT(this != other || fVerb == SkPath::kCubic_Verb)
|
|
|
|
{13, "http___www_modernqigong_com_.skp", false}, // SkAAClip::Builder::addRun SkASSERT(fBounds.contains(x, y));
|
|
|
|
{14, "http___www_devbridge_com_.skp", true}, // checkSmallCoincidence SkASSERT(!next->fSmall || checkMultiple);
|
2014-08-12 18:46:33 +04:00
|
|
|
{16, "http___www_1023world_net_.skp", false}, // bitmap decode assert (corrupt skp?)
|
2014-07-18 16:08:14 +04:00
|
|
|
{19, "http___www_alamdi_com_.skp", true}, // cubic/quad intersection
|
|
|
|
{26, "http___www_liveencounters_net_.skp", true}, // (no repro on mac) checkSmall addT:549 (line, expects cubic)
|
|
|
|
{28, "http___www_encros_fr_.skp", false}, // SkAAClip::Builder::addRun SkASSERT(fBounds.contains(x, y));
|
|
|
|
{37, "http___www_familysurvivalprotocol_wordpress_com_.skp", true}, // bumpSpan SkASSERT(span->fOppValue >= 0);
|
|
|
|
{39, "http___sufeinet_com_.skp", false}, // bitmap decode assert (corrupt skp?)
|
|
|
|
{41, "http___www_rano360_com_.skp", true}, // checkSmallCoincidence SkASSERT(!next->fSmall || checkMultiple);
|
|
|
|
{44, "http___www_firstunitedbank_com_.skp", true}, // addTCancel SkASSERT(oIndex > 0);
|
|
|
|
{46, "http___www_shinydemos_com_.skp", true}, // addSimpleAngle SkASSERT(index == count() - 2);
|
|
|
|
{48, "http___www_familysurvivalprotocol_com_.skp", true}, // bumpSpan SkASSERT "span->fOppValue >= 0"
|
|
|
|
{57, "http___www_lptemp_com_.skp", true}, // addTCoincident oPeek = &other->fTs[++oPeekIndex];
|
|
|
|
{71, "http___www_1milyonkahraman_org_.skp", true}, // addTCoincident SkASSERT(test->fT < 1);
|
|
|
|
{88, "http___www_apuntesdelechuza_wordpress_com_.skp", true}, // bumpSpan SkASSERT "span->fOppValue >= 0"
|
|
|
|
{89, "http___www_mobilizedconsulting_com_.skp", true}, // addTCancel SkASSERT(oIndex > 0);
|
|
|
|
{93, "http___www_simple_living_in_suffolk_co_uk_.skp", true}, // bumpSpan SkASSERT "span->fOppValue >= 0"
|
|
|
|
};
|
|
|
|
|
|
|
|
size_t skipOverCount = sizeof(skipOver) / sizeof(skipOver[0]);
|
|
|
|
|
|
|
|
|
|
|
|
/* customize file in/out here */
|
|
|
|
/* TODO : add command flag interface */
|
|
|
|
#define CHROME_VERSION "1e5dfa4-4a995df"
|
|
|
|
#define SUMMARY_RUN 1
|
2013-07-08 21:17:02 +04:00
|
|
|
|
|
|
|
#ifdef SK_BUILD_FOR_WIN
|
2014-07-18 16:08:14 +04:00
|
|
|
#define DRIVE_SPEC "D:"
|
2013-10-02 18:49:34 +04:00
|
|
|
#define PATH_SLASH "\\"
|
2013-07-08 21:17:02 +04:00
|
|
|
#else
|
2014-07-18 16:08:14 +04:00
|
|
|
#define DRIVE_SPEC ""
|
2013-10-02 18:49:34 +04:00
|
|
|
#define PATH_SLASH "/"
|
2013-07-08 21:17:02 +04:00
|
|
|
#endif
|
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
#define IN_DIR_PRE DRIVE_SPEC PATH_SLASH "skps" PATH_SLASH "slave"
|
|
|
|
#define OUT_DIR_PRE DRIVE_SPEC PATH_SLASH "skpOut" PATH_SLASH "slave"
|
|
|
|
#define OUT_DIR_SUM DRIVE_SPEC PATH_SLASH "skpOut" PATH_SLASH "summary"
|
|
|
|
#define DIR_POST PATH_SLASH "All" PATH_SLASH CHROME_VERSION
|
|
|
|
|
|
|
|
static const char outOpDir[] = "opClip";
|
|
|
|
static const char outOldDir[] = "oldClip";
|
|
|
|
static const char outStatusDir[] = "statusTest";
|
|
|
|
|
|
|
|
static SkString get_in_path(int dirNo, const char* filename) {
|
|
|
|
SkString path;
|
|
|
|
SkASSERT(dirNo);
|
|
|
|
path.appendf("%s%d%s", IN_DIR_PRE, dirNo, DIR_POST);
|
|
|
|
if (!sk_exists(path.c_str())) {
|
|
|
|
SkDebugf("could not read %s\n", path.c_str());
|
|
|
|
return SkString();
|
|
|
|
}
|
|
|
|
if (filename) {
|
|
|
|
path.appendf("%s%s", PATH_SLASH, filename);
|
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in
one global pool. Each SkTaskGroup itself is tiny (4 bytes)
and its wait() method applies only to tasks add()ed to that
instance, not the whole thread pool.
This means we don't need to bring up new thread pools when
tests themselves want to use multithreading (e.g. pathops,
quilt). We just create a new SkTaskGroup and wait for that
to complete. This should be more efficient, and allow us
to expand where we use threads to really latency sensitive
places. E.g. we can probably now use these in nanobench
for CPU .skp rendering.
Now that all threads are sharing the same pool, I think we
can remove most of the custom mechanism pathops tests use
to control threading. They'll just ride on the global pool
with all other tests now.
This (temporarily?) removes the GPU multithreading feature
from DM, which we don't use.
On my desktop, DM runs a little faster (57s -> 55s) in
Debug, and a lot faster in Release (36s -> 24s). The bots
show speedups of similar proportions, cutting more than a
minute off the N4/Release and Win7/Debug runtimes.
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f
R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/531653002
2014-09-04 02:34:37 +04:00
|
|
|
if (!sk_exists(path.c_str())) {
|
2014-07-18 16:08:14 +04:00
|
|
|
SkDebugf("could not read %s\n", path.c_str());
|
|
|
|
return SkString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in
one global pool. Each SkTaskGroup itself is tiny (4 bytes)
and its wait() method applies only to tasks add()ed to that
instance, not the whole thread pool.
This means we don't need to bring up new thread pools when
tests themselves want to use multithreading (e.g. pathops,
quilt). We just create a new SkTaskGroup and wait for that
to complete. This should be more efficient, and allow us
to expand where we use threads to really latency sensitive
places. E.g. we can probably now use these in nanobench
for CPU .skp rendering.
Now that all threads are sharing the same pool, I think we
can remove most of the custom mechanism pathops tests use
to control threading. They'll just ride on the global pool
with all other tests now.
This (temporarily?) removes the GPU multithreading feature
from DM, which we don't use.
On my desktop, DM runs a little faster (57s -> 55s) in
Debug, and a lot faster in Release (36s -> 24s). The bots
show speedups of similar proportions, cutting more than a
minute off the N4/Release and Win7/Debug runtimes.
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f
R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/531653002
2014-09-04 02:34:37 +04:00
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
static void make_recursive_dir(const SkString& path) {
|
|
|
|
if (sk_exists(path.c_str())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const char* pathStr = path.c_str();
|
|
|
|
int last = (int) path.size();
|
|
|
|
do {
|
|
|
|
while (last > 0 && pathStr[--last] != PATH_SLASH[0])
|
|
|
|
;
|
|
|
|
SkASSERT(last > 0);
|
|
|
|
SkString shorter(pathStr, last);
|
|
|
|
if (sk_mkdir(shorter.c_str())) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (true);
|
|
|
|
do {
|
|
|
|
while (last < (int) path.size() && pathStr[++last] != PATH_SLASH[0])
|
|
|
|
;
|
|
|
|
SkString shorter(pathStr, last);
|
|
|
|
SkAssertResult(sk_mkdir(shorter.c_str()));
|
|
|
|
} while (last < (int) path.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
static SkString get_out_path(int dirNo, const char* dirName) {
|
|
|
|
SkString path;
|
|
|
|
SkASSERT(dirNo);
|
|
|
|
SkASSERT(dirName);
|
|
|
|
path.appendf("%s%d%s%s%s", OUT_DIR_PRE, dirNo, DIR_POST, PATH_SLASH, dirName);
|
|
|
|
make_recursive_dir(path);
|
|
|
|
return path;
|
|
|
|
}
|
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in
one global pool. Each SkTaskGroup itself is tiny (4 bytes)
and its wait() method applies only to tasks add()ed to that
instance, not the whole thread pool.
This means we don't need to bring up new thread pools when
tests themselves want to use multithreading (e.g. pathops,
quilt). We just create a new SkTaskGroup and wait for that
to complete. This should be more efficient, and allow us
to expand where we use threads to really latency sensitive
places. E.g. we can probably now use these in nanobench
for CPU .skp rendering.
Now that all threads are sharing the same pool, I think we
can remove most of the custom mechanism pathops tests use
to control threading. They'll just ride on the global pool
with all other tests now.
This (temporarily?) removes the GPU multithreading feature
from DM, which we don't use.
On my desktop, DM runs a little faster (57s -> 55s) in
Debug, and a lot faster in Release (36s -> 24s). The bots
show speedups of similar proportions, cutting more than a
minute off the N4/Release and Win7/Debug runtimes.
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f
R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/531653002
2014-09-04 02:34:37 +04:00
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
static SkString get_sum_path(const char* dirName) {
|
|
|
|
SkString path;
|
|
|
|
SkASSERT(dirName);
|
|
|
|
path.appendf("%s%d%s%s", OUT_DIR_SUM, SUMMARY_RUN, PATH_SLASH, dirName);
|
|
|
|
SkDebugf("%s\n", path.c_str());
|
|
|
|
make_recursive_dir(path);
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SkString make_png_name(const char* filename) {
|
|
|
|
SkString pngName = SkString(filename);
|
|
|
|
pngName.remove(pngName.size() - 3, 3);
|
|
|
|
pngName.append("png");
|
|
|
|
return pngName;
|
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
////////////////////////////////////////////////////////
|
2013-11-01 21:36:03 +04:00
|
|
|
|
|
|
|
enum TestStep {
|
|
|
|
kCompareBits,
|
|
|
|
kEncodeFiles,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
2014-06-17 16:15:38 +04:00
|
|
|
kMaxLength = 256,
|
2013-11-01 21:36:03 +04:00
|
|
|
kMaxFiles = 128,
|
|
|
|
kSmallLimit = 1000,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct TestResult {
|
|
|
|
void init(int dirNo) {
|
|
|
|
fDirNo = dirNo;
|
|
|
|
sk_bzero(fFilename, sizeof(fFilename));
|
|
|
|
fTestStep = kCompareBits;
|
2014-04-14 21:08:59 +04:00
|
|
|
fScale = 1;
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in
one global pool. Each SkTaskGroup itself is tiny (4 bytes)
and its wait() method applies only to tasks add()ed to that
instance, not the whole thread pool.
This means we don't need to bring up new thread pools when
tests themselves want to use multithreading (e.g. pathops,
quilt). We just create a new SkTaskGroup and wait for that
to complete. This should be more efficient, and allow us
to expand where we use threads to really latency sensitive
places. E.g. we can probably now use these in nanobench
for CPU .skp rendering.
Now that all threads are sharing the same pool, I think we
can remove most of the custom mechanism pathops tests use
to control threading. They'll just ride on the global pool
with all other tests now.
This (temporarily?) removes the GPU multithreading feature
from DM, which we don't use.
On my desktop, DM runs a little faster (57s -> 55s) in
Debug, and a lot faster in Release (36s -> 24s). The bots
show speedups of similar proportions, cutting more than a
minute off the N4/Release and Win7/Debug runtimes.
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f
R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/531653002
2014-09-04 02:34:37 +04:00
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
void init(int dirNo, const SkString& filename) {
|
|
|
|
fDirNo = dirNo;
|
|
|
|
strcpy(fFilename, filename.c_str());
|
|
|
|
fTestStep = kCompareBits;
|
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in
one global pool. Each SkTaskGroup itself is tiny (4 bytes)
and its wait() method applies only to tasks add()ed to that
instance, not the whole thread pool.
This means we don't need to bring up new thread pools when
tests themselves want to use multithreading (e.g. pathops,
quilt). We just create a new SkTaskGroup and wait for that
to complete. This should be more efficient, and allow us
to expand where we use threads to really latency sensitive
places. E.g. we can probably now use these in nanobench
for CPU .skp rendering.
Now that all threads are sharing the same pool, I think we
can remove most of the custom mechanism pathops tests use
to control threading. They'll just ride on the global pool
with all other tests now.
This (temporarily?) removes the GPU multithreading feature
from DM, which we don't use.
On my desktop, DM runs a little faster (57s -> 55s) in
Debug, and a lot faster in Release (36s -> 24s). The bots
show speedups of similar proportions, cutting more than a
minute off the N4/Release and Win7/Debug runtimes.
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f
R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/531653002
2014-09-04 02:34:37 +04:00
|
|
|
fScale = 1;
|
2014-07-18 16:08:14 +04:00
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
|
|
|
|
SkString status() {
|
|
|
|
SkString outStr;
|
|
|
|
outStr.printf("%s %d %d\n", fFilename, fPixelError, fTime);
|
|
|
|
return outStr;
|
|
|
|
}
|
|
|
|
|
2014-04-14 21:08:59 +04:00
|
|
|
SkString progress() {
|
|
|
|
SkString outStr;
|
|
|
|
outStr.printf("dir=%d %s ", fDirNo, fFilename);
|
|
|
|
if (fPixelError) {
|
|
|
|
outStr.appendf(" err=%d", fPixelError);
|
|
|
|
}
|
|
|
|
if (fTime) {
|
|
|
|
outStr.appendf(" time=%d", fTime);
|
|
|
|
}
|
|
|
|
if (fScale != 1) {
|
|
|
|
outStr.appendf(" scale=%d", fScale);
|
|
|
|
}
|
|
|
|
outStr.appendf("\n");
|
|
|
|
return outStr;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-11-01 21:36:03 +04:00
|
|
|
void test(int dirNo, const SkString& filename) {
|
|
|
|
init(dirNo);
|
|
|
|
strcpy(fFilename, filename.c_str());
|
|
|
|
testOne();
|
|
|
|
}
|
|
|
|
|
|
|
|
void testOne();
|
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in
one global pool. Each SkTaskGroup itself is tiny (4 bytes)
and its wait() method applies only to tasks add()ed to that
instance, not the whole thread pool.
This means we don't need to bring up new thread pools when
tests themselves want to use multithreading (e.g. pathops,
quilt). We just create a new SkTaskGroup and wait for that
to complete. This should be more efficient, and allow us
to expand where we use threads to really latency sensitive
places. E.g. we can probably now use these in nanobench
for CPU .skp rendering.
Now that all threads are sharing the same pool, I think we
can remove most of the custom mechanism pathops tests use
to control threading. They'll just ride on the global pool
with all other tests now.
This (temporarily?) removes the GPU multithreading feature
from DM, which we don't use.
On my desktop, DM runs a little faster (57s -> 55s) in
Debug, and a lot faster in Release (36s -> 24s). The bots
show speedups of similar proportions, cutting more than a
minute off the N4/Release and Win7/Debug runtimes.
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f
R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/531653002
2014-09-04 02:34:37 +04:00
|
|
|
|
2013-11-01 21:36:03 +04:00
|
|
|
char fFilename[kMaxLength];
|
|
|
|
TestStep fTestStep;
|
|
|
|
int fDirNo;
|
|
|
|
int fPixelError;
|
|
|
|
int fTime;
|
2014-04-14 21:08:59 +04:00
|
|
|
int fScale;
|
2013-11-01 21:36:03 +04:00
|
|
|
};
|
|
|
|
|
2014-04-14 21:08:59 +04:00
|
|
|
class SortByPixel : public TestResult {
|
|
|
|
public:
|
|
|
|
bool operator<(const SortByPixel& rh) const {
|
|
|
|
return fPixelError < rh.fPixelError;
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
2014-04-14 21:08:59 +04:00
|
|
|
};
|
2013-11-01 21:36:03 +04:00
|
|
|
|
2014-04-14 21:08:59 +04:00
|
|
|
class SortByTime : public TestResult {
|
|
|
|
public:
|
|
|
|
bool operator<(const SortByTime& rh) const {
|
|
|
|
return fTime < rh.fTime;
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
2014-04-14 21:08:59 +04:00
|
|
|
};
|
2013-11-01 21:36:03 +04:00
|
|
|
|
2014-06-17 16:15:38 +04:00
|
|
|
class SortByName : public TestResult {
|
|
|
|
public:
|
|
|
|
bool operator<(const SortByName& rh) const {
|
|
|
|
return strcmp(fFilename, rh.fFilename) < 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-04-14 21:08:59 +04:00
|
|
|
struct TestState {
|
2014-07-18 16:08:14 +04:00
|
|
|
void init(int dirNo) {
|
2014-04-14 21:08:59 +04:00
|
|
|
fResult.init(dirNo);
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
|
|
|
|
2014-04-14 21:08:59 +04:00
|
|
|
SkTDArray<SortByPixel> fPixelWorst;
|
|
|
|
SkTDArray<SortByTime> fSlowest;
|
2013-11-01 21:36:03 +04:00
|
|
|
TestResult fResult;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct TestRunner {
|
|
|
|
~TestRunner();
|
|
|
|
void render();
|
|
|
|
SkTDArray<class TestRunnable*> fRunnables;
|
|
|
|
};
|
|
|
|
|
|
|
|
class TestRunnable : public SkRunnable {
|
|
|
|
public:
|
|
|
|
virtual void run() SK_OVERRIDE {
|
|
|
|
SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
|
|
|
|
(*fTestFun)(&fState);
|
|
|
|
}
|
|
|
|
|
|
|
|
TestState fState;
|
|
|
|
void (*fTestFun)(TestState*);
|
|
|
|
};
|
|
|
|
|
2014-06-17 16:15:38 +04:00
|
|
|
|
|
|
|
class TestRunnableDir : public TestRunnable {
|
|
|
|
public:
|
|
|
|
TestRunnableDir(void (*testFun)(TestState*), int dirNo, TestRunner* runner) {
|
2014-07-18 16:08:14 +04:00
|
|
|
fState.init(dirNo);
|
2014-06-17 16:15:38 +04:00
|
|
|
fTestFun = testFun;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
class TestRunnableFile : public TestRunnable {
|
|
|
|
public:
|
|
|
|
TestRunnableFile(void (*testFun)(TestState*), int dirNo, const char* name, TestRunner* runner) {
|
2014-07-18 16:08:14 +04:00
|
|
|
fState.init(dirNo);
|
2014-06-17 16:15:38 +04:00
|
|
|
strcpy(fState.fResult.fFilename, name);
|
|
|
|
fTestFun = testFun;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class TestRunnableEncode : public TestRunnableFile {
|
|
|
|
public:
|
|
|
|
TestRunnableEncode(void (*testFun)(TestState*), int dirNo, const char* name, TestRunner* runner)
|
|
|
|
: TestRunnableFile(testFun, dirNo, name, runner) {
|
|
|
|
fState.fResult.fTestStep = kEncodeFiles;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-11-01 21:36:03 +04:00
|
|
|
TestRunner::~TestRunner() {
|
|
|
|
for (int index = 0; index < fRunnables.count(); index++) {
|
|
|
|
SkDELETE(fRunnables[index]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestRunner::render() {
|
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in
one global pool. Each SkTaskGroup itself is tiny (4 bytes)
and its wait() method applies only to tasks add()ed to that
instance, not the whole thread pool.
This means we don't need to bring up new thread pools when
tests themselves want to use multithreading (e.g. pathops,
quilt). We just create a new SkTaskGroup and wait for that
to complete. This should be more efficient, and allow us
to expand where we use threads to really latency sensitive
places. E.g. we can probably now use these in nanobench
for CPU .skp rendering.
Now that all threads are sharing the same pool, I think we
can remove most of the custom mechanism pathops tests use
to control threading. They'll just ride on the global pool
with all other tests now.
This (temporarily?) removes the GPU multithreading feature
from DM, which we don't use.
On my desktop, DM runs a little faster (57s -> 55s) in
Debug, and a lot faster in Release (36s -> 24s). The bots
show speedups of similar proportions, cutting more than a
minute off the N4/Release and Win7/Debug runtimes.
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f
R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/531653002
2014-09-04 02:34:37 +04:00
|
|
|
SkTaskGroup tg;
|
2013-11-01 21:36:03 +04:00
|
|
|
for (int index = 0; index < fRunnables.count(); ++ index) {
|
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in
one global pool. Each SkTaskGroup itself is tiny (4 bytes)
and its wait() method applies only to tasks add()ed to that
instance, not the whole thread pool.
This means we don't need to bring up new thread pools when
tests themselves want to use multithreading (e.g. pathops,
quilt). We just create a new SkTaskGroup and wait for that
to complete. This should be more efficient, and allow us
to expand where we use threads to really latency sensitive
places. E.g. we can probably now use these in nanobench
for CPU .skp rendering.
Now that all threads are sharing the same pool, I think we
can remove most of the custom mechanism pathops tests use
to control threading. They'll just ride on the global pool
with all other tests now.
This (temporarily?) removes the GPU multithreading feature
from DM, which we don't use.
On my desktop, DM runs a little faster (57s -> 55s) in
Debug, and a lot faster in Release (36s -> 24s). The bots
show speedups of similar proportions, cutting more than a
minute off the N4/Release and Win7/Debug runtimes.
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f
R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/531653002
2014-09-04 02:34:37 +04:00
|
|
|
tg.add(fRunnables[index]);
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
|
|
|
2013-05-08 11:01:40 +04:00
|
|
|
|
2013-11-01 21:36:03 +04:00
|
|
|
static int similarBits(const SkBitmap& gr, const SkBitmap& sk) {
|
|
|
|
const int kRowCount = 3;
|
|
|
|
const int kThreshold = 3;
|
|
|
|
int width = SkTMin(gr.width(), sk.width());
|
|
|
|
if (width < kRowCount) {
|
|
|
|
return true;
|
2013-10-02 18:49:34 +04:00
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
int height = SkTMin(gr.height(), sk.height());
|
|
|
|
if (height < kRowCount) {
|
|
|
|
return true;
|
2013-07-08 21:17:02 +04:00
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
int errorTotal = 0;
|
|
|
|
SkTArray<int, true> errorRows;
|
|
|
|
errorRows.push_back_n(width * kRowCount);
|
|
|
|
SkAutoLockPixels autoGr(gr);
|
|
|
|
SkAutoLockPixels autoSk(sk);
|
|
|
|
for (int y = 0; y < height; ++y) {
|
|
|
|
SkPMColor* grRow = gr.getAddr32(0, y);
|
|
|
|
SkPMColor* skRow = sk.getAddr32(0, y);
|
|
|
|
int* base = &errorRows[0];
|
|
|
|
int* cOut = &errorRows[y % kRowCount];
|
|
|
|
for (int x = 0; x < width; ++x) {
|
|
|
|
SkPMColor grColor = grRow[x];
|
|
|
|
SkPMColor skColor = skRow[x];
|
|
|
|
int dr = SkGetPackedR32(grColor) - SkGetPackedR32(skColor);
|
|
|
|
int dg = SkGetPackedG32(grColor) - SkGetPackedG32(skColor);
|
|
|
|
int db = SkGetPackedB32(grColor) - SkGetPackedB32(skColor);
|
|
|
|
int error = cOut[x] = SkTMax(SkAbs32(dr), SkTMax(SkAbs32(dg), SkAbs32(db)));
|
|
|
|
if (error < kThreshold || x < 2) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (base[x - 2] < kThreshold
|
|
|
|
|| base[width + x - 2] < kThreshold
|
|
|
|
|| base[width * 2 + x - 2] < kThreshold
|
|
|
|
|| base[x - 1] < kThreshold
|
|
|
|
|| base[width + x - 1] < kThreshold
|
|
|
|
|| base[width * 2 + x - 1] < kThreshold
|
|
|
|
|| base[x] < kThreshold
|
|
|
|
|| base[width + x] < kThreshold
|
|
|
|
|| base[width * 2 + x] < kThreshold) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
errorTotal += error;
|
|
|
|
}
|
2013-07-08 21:17:02 +04:00
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
return errorTotal;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool addError(TestState* data, const TestResult& testResult) {
|
2014-04-14 21:08:59 +04:00
|
|
|
if (testResult.fPixelError <= 0 && testResult.fTime <= 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
int worstCount = data->fPixelWorst.count();
|
2013-11-01 21:36:03 +04:00
|
|
|
int pixelError = testResult.fPixelError;
|
2014-04-14 21:08:59 +04:00
|
|
|
if (pixelError > 0) {
|
|
|
|
for (int index = 0; index < worstCount; ++index) {
|
|
|
|
if (pixelError > data->fPixelWorst[index].fPixelError) {
|
|
|
|
data->fPixelWorst[index] = *(SortByPixel*) &testResult;
|
|
|
|
return true;
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
|
|
|
}
|
2014-04-14 21:08:59 +04:00
|
|
|
}
|
|
|
|
int slowCount = data->fSlowest.count();
|
|
|
|
int time = testResult.fTime;
|
|
|
|
if (time > 0) {
|
|
|
|
for (int index = 0; index < slowCount; ++index) {
|
|
|
|
if (time > data->fSlowest[index].fTime) {
|
|
|
|
data->fSlowest[index] = *(SortByTime*) &testResult;
|
|
|
|
return true;
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
|
|
|
}
|
2013-07-08 21:17:02 +04:00
|
|
|
}
|
2014-04-14 21:08:59 +04:00
|
|
|
if (pixelError > 0 && worstCount < kMaxFiles) {
|
|
|
|
*data->fPixelWorst.append() = *(SortByPixel*) &testResult;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (time > 0 && slowCount < kMaxFiles) {
|
|
|
|
*data->fSlowest.append() = *(SortByTime*) &testResult;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static SkMSec timePict(SkPicture* pic, SkCanvas* canvas) {
|
|
|
|
canvas->save();
|
2014-08-29 19:03:56 +04:00
|
|
|
SkScalar pWidth = pic->cullRect().width();
|
|
|
|
SkScalar pHeight = pic->cullRect().height();
|
|
|
|
const SkScalar maxDimension = 1000.0f;
|
2013-11-01 21:36:03 +04:00
|
|
|
const int slices = 3;
|
2014-08-29 19:03:56 +04:00
|
|
|
SkScalar xInterval = SkTMax(pWidth - maxDimension, 0.0f) / (slices - 1);
|
|
|
|
SkScalar yInterval = SkTMax(pHeight - maxDimension, 0.0f) / (slices - 1);
|
|
|
|
SkRect rect = {0, 0, SkTMin(maxDimension, pWidth), SkTMin(maxDimension, pHeight) };
|
2013-11-01 21:36:03 +04:00
|
|
|
canvas->clipRect(rect);
|
|
|
|
SkMSec start = SkTime::GetMSecs();
|
|
|
|
for (int x = 0; x < slices; ++x) {
|
|
|
|
for (int y = 0; y < slices; ++y) {
|
2014-09-04 19:42:50 +04:00
|
|
|
pic->playback(canvas);
|
2014-08-29 19:03:56 +04:00
|
|
|
canvas->translate(0, yInterval);
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
2014-08-29 19:03:56 +04:00
|
|
|
canvas->translate(xInterval, -yInterval * slices);
|
2013-07-08 21:17:02 +04:00
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
SkMSec end = SkTime::GetMSecs();
|
|
|
|
canvas->restore();
|
|
|
|
return end - start;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void drawPict(SkPicture* pic, SkCanvas* canvas, int scale) {
|
|
|
|
canvas->clear(SK_ColorWHITE);
|
|
|
|
if (scale != 1) {
|
|
|
|
canvas->save();
|
|
|
|
canvas->scale(1.0f / scale, 1.0f / scale);
|
2013-07-08 21:17:02 +04:00
|
|
|
}
|
2014-09-04 19:42:50 +04:00
|
|
|
pic->playback(canvas);
|
2013-11-01 21:36:03 +04:00
|
|
|
if (scale != 1) {
|
|
|
|
canvas->restore();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void writePict(const SkBitmap& bitmap, const char* outDir, const char* pngName) {
|
2014-07-18 16:08:14 +04:00
|
|
|
SkString outFile = get_sum_path(outDir);
|
|
|
|
outFile.appendf("%s%s", PATH_SLASH, pngName);
|
|
|
|
if (!SkImageEncoder::EncodeFile(outFile.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100)) {
|
2013-11-01 21:36:03 +04:00
|
|
|
SkDebugf("unable to encode gr %s (width=%d height=%d)\n", pngName,
|
|
|
|
bitmap.width(), bitmap.height());
|
2013-07-08 21:17:02 +04:00
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void TestResult::testOne() {
|
|
|
|
SkPicture* pic = NULL;
|
|
|
|
{
|
|
|
|
#if DEBUG_SHOW_TEST_NAME
|
|
|
|
if (fTestStep == kCompareBits) {
|
|
|
|
SkString testName(fFilename);
|
|
|
|
const char http[] = "http";
|
|
|
|
if (testName.startsWith(http)) {
|
|
|
|
testName.remove(0, sizeof(http) - 1);
|
|
|
|
}
|
|
|
|
while (testName.startsWith("_")) {
|
|
|
|
testName.remove(0, 1);
|
|
|
|
}
|
|
|
|
const char dotSkp[] = ".skp";
|
|
|
|
if (testName.endsWith(dotSkp)) {
|
|
|
|
size_t len = testName.size();
|
|
|
|
testName.remove(len - (sizeof(dotSkp) - 1), sizeof(dotSkp) - 1);
|
|
|
|
}
|
|
|
|
testName.prepend("skp");
|
|
|
|
testName.append("1");
|
|
|
|
strncpy(DEBUG_FILENAME_STRING, testName.c_str(), DEBUG_FILENAME_STRING_LENGTH);
|
|
|
|
} else if (fTestStep == kEncodeFiles) {
|
|
|
|
strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
|
|
|
|
}
|
|
|
|
#endif
|
2014-07-18 16:08:14 +04:00
|
|
|
SkString path = get_in_path(fDirNo, fFilename);
|
2013-11-01 21:36:03 +04:00
|
|
|
SkFILEStream stream(path.c_str());
|
|
|
|
if (!stream.isValid()) {
|
|
|
|
SkDebugf("invalid stream %s\n", path.c_str());
|
|
|
|
goto finish;
|
|
|
|
}
|
2014-04-14 21:08:59 +04:00
|
|
|
pic = SkPicture::CreateFromStream(&stream, &SkImageDecoder::DecodeMemory);
|
2013-11-01 21:36:03 +04:00
|
|
|
if (!pic) {
|
|
|
|
SkDebugf("unable to decode %s\n", fFilename);
|
|
|
|
goto finish;
|
|
|
|
}
|
2014-08-29 19:03:56 +04:00
|
|
|
SkScalar width = pic->cullRect().width();
|
|
|
|
SkScalar height = pic->cullRect().height();
|
2013-11-01 21:36:03 +04:00
|
|
|
SkBitmap oldBitmap, opBitmap;
|
2014-04-14 21:08:59 +04:00
|
|
|
fScale = 1;
|
2014-04-25 16:59:11 +04:00
|
|
|
while (width / fScale > 32767 || height / fScale > 32767) {
|
|
|
|
++fScale;
|
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
do {
|
2014-08-29 19:03:56 +04:00
|
|
|
int dimX = SkScalarCeilToInt(width / fScale);
|
|
|
|
int dimY = SkScalarCeilToInt(height / fScale);
|
2014-09-02 23:50:45 +04:00
|
|
|
if (oldBitmap.tryAllocN32Pixels(dimX, dimY) && opBitmap.tryAllocN32Pixels(dimX, dimY)) {
|
2013-11-01 21:36:03 +04:00
|
|
|
break;
|
|
|
|
}
|
2014-04-14 21:08:59 +04:00
|
|
|
SkDebugf("-%d-", fScale);
|
2014-04-25 16:59:11 +04:00
|
|
|
} while (++fScale < 256);
|
2014-04-14 21:08:59 +04:00
|
|
|
if (fScale >= 256) {
|
2014-08-29 19:03:56 +04:00
|
|
|
SkDebugf("unable to allocate bitmap for %s (w=%f h=%f)\n", fFilename,
|
2013-11-01 21:36:03 +04:00
|
|
|
width, height);
|
2014-04-14 21:08:59 +04:00
|
|
|
goto finish;
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
|
|
|
oldBitmap.eraseColor(SK_ColorWHITE);
|
|
|
|
SkCanvas oldCanvas(oldBitmap);
|
|
|
|
oldCanvas.setAllowSimplifyClip(false);
|
|
|
|
opBitmap.eraseColor(SK_ColorWHITE);
|
|
|
|
SkCanvas opCanvas(opBitmap);
|
|
|
|
opCanvas.setAllowSimplifyClip(true);
|
2014-04-14 21:08:59 +04:00
|
|
|
drawPict(pic, &oldCanvas, fScale);
|
|
|
|
drawPict(pic, &opCanvas, fScale);
|
2013-11-01 21:36:03 +04:00
|
|
|
if (fTestStep == kCompareBits) {
|
|
|
|
fPixelError = similarBits(oldBitmap, opBitmap);
|
|
|
|
int oldTime = timePict(pic, &oldCanvas);
|
|
|
|
int opTime = timePict(pic, &opCanvas);
|
2014-04-14 21:08:59 +04:00
|
|
|
fTime = SkTMax(0, oldTime - opTime);
|
2013-11-01 21:36:03 +04:00
|
|
|
} else if (fTestStep == kEncodeFiles) {
|
|
|
|
SkString pngStr = make_png_name(fFilename);
|
|
|
|
const char* pngName = pngStr.c_str();
|
|
|
|
writePict(oldBitmap, outOldDir, pngName);
|
|
|
|
writePict(opBitmap, outOpDir, pngName);
|
2013-10-02 18:49:34 +04:00
|
|
|
}
|
2013-07-08 21:17:02 +04:00
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
finish:
|
2014-04-14 21:08:59 +04:00
|
|
|
if (pic) {
|
|
|
|
pic->unref();
|
|
|
|
}
|
2013-07-08 21:17:02 +04:00
|
|
|
}
|
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
DEFINE_string2(match, m, "PathOpsSkpClipThreaded",
|
|
|
|
"[~][^]substring[$] [...] of test name to run.\n"
|
|
|
|
"Multiple matches may be separated by spaces.\n"
|
|
|
|
"~ causes a matching test to always be skipped\n"
|
|
|
|
"^ requires the start of the test to match\n"
|
|
|
|
"$ requires the end of the test to match\n"
|
|
|
|
"^ and $ requires an exact match\n"
|
|
|
|
"If a test does not match any list entry,\n"
|
|
|
|
"it is skipped unless some list entry starts with ~");
|
|
|
|
DEFINE_string2(dir, d, NULL, "range of directories (e.g., 1-100)");
|
|
|
|
DEFINE_string2(skp, s, NULL, "skp to test");
|
|
|
|
DEFINE_bool2(single, z, false, "run tests on a single thread internally.");
|
|
|
|
DEFINE_int32(testIndex, 0, "override local test index (PathOpsSkpClipOneOff only).");
|
|
|
|
DEFINE_bool2(verbose, v, false, "enable verbose output.");
|
|
|
|
|
|
|
|
static bool verbose() {
|
|
|
|
return FLAGS_verbose;
|
|
|
|
}
|
|
|
|
|
|
|
|
class Dirs {
|
2013-11-01 21:36:03 +04:00
|
|
|
public:
|
2014-07-18 16:08:14 +04:00
|
|
|
Dirs() {
|
|
|
|
reset();
|
|
|
|
sk_bzero(fRun, sizeof(fRun));
|
|
|
|
fSet = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int first() const {
|
|
|
|
int index = 0;
|
|
|
|
while (++index < kMaxDir) {
|
|
|
|
if (fRun[index]) {
|
|
|
|
return index;
|
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
2014-07-18 16:08:14 +04:00
|
|
|
SkASSERT(0);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int last() const {
|
|
|
|
int index = kMaxDir;
|
|
|
|
while (--index > 0 && !fRun[index])
|
2013-11-01 21:36:03 +04:00
|
|
|
;
|
2014-07-18 16:08:14 +04:00
|
|
|
return index;
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
int next() {
|
|
|
|
while (++fIndex < kMaxDir) {
|
|
|
|
if (fRun[fIndex]) {
|
|
|
|
return fIndex;
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
|
|
|
}
|
2014-07-18 16:08:14 +04:00
|
|
|
return -1;
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
2013-10-02 18:49:34 +04:00
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
void reset() {
|
|
|
|
fIndex = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set(int start, int end) {
|
|
|
|
while (start < end) {
|
|
|
|
fRun[start++] = 1;
|
|
|
|
}
|
|
|
|
fSet = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setDefault() {
|
|
|
|
if (!fSet) {
|
|
|
|
set(1, 100);
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
|
|
|
}
|
2013-07-08 21:17:02 +04:00
|
|
|
|
2013-11-01 21:36:03 +04:00
|
|
|
private:
|
2014-07-18 16:08:14 +04:00
|
|
|
enum {
|
|
|
|
kMaxDir = 101
|
|
|
|
};
|
|
|
|
char fRun[kMaxDir];
|
2013-11-01 21:36:03 +04:00
|
|
|
int fIndex;
|
2014-07-18 16:08:14 +04:00
|
|
|
bool fSet;
|
|
|
|
} gDirs;
|
|
|
|
|
|
|
|
class Filenames {
|
|
|
|
public:
|
|
|
|
Filenames()
|
|
|
|
: fIndex(-1) {
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* next() {
|
|
|
|
while (fNames && ++fIndex < fNames->count()) {
|
|
|
|
return (*fNames)[fIndex];
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in
one global pool. Each SkTaskGroup itself is tiny (4 bytes)
and its wait() method applies only to tasks add()ed to that
instance, not the whole thread pool.
This means we don't need to bring up new thread pools when
tests themselves want to use multithreading (e.g. pathops,
quilt). We just create a new SkTaskGroup and wait for that
to complete. This should be more efficient, and allow us
to expand where we use threads to really latency sensitive
places. E.g. we can probably now use these in nanobench
for CPU .skp rendering.
Now that all threads are sharing the same pool, I think we
can remove most of the custom mechanism pathops tests use
to control threading. They'll just ride on the global pool
with all other tests now.
This (temporarily?) removes the GPU multithreading feature
from DM, which we don't use.
On my desktop, DM runs a little faster (57s -> 55s) in
Debug, and a lot faster in Release (36s -> 24s). The bots
show speedups of similar proportions, cutting more than a
minute off the N4/Release and Win7/Debug runtimes.
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f
R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/531653002
2014-09-04 02:34:37 +04:00
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
void set(const SkCommandLineFlags::StringArray& names) {
|
|
|
|
fNames = &names;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
int fIndex;
|
|
|
|
const SkCommandLineFlags::StringArray* fNames;
|
|
|
|
} gNames;
|
|
|
|
|
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in
one global pool. Each SkTaskGroup itself is tiny (4 bytes)
and its wait() method applies only to tasks add()ed to that
instance, not the whole thread pool.
This means we don't need to bring up new thread pools when
tests themselves want to use multithreading (e.g. pathops,
quilt). We just create a new SkTaskGroup and wait for that
to complete. This should be more efficient, and allow us
to expand where we use threads to really latency sensitive
places. E.g. we can probably now use these in nanobench
for CPU .skp rendering.
Now that all threads are sharing the same pool, I think we
can remove most of the custom mechanism pathops tests use
to control threading. They'll just ride on the global pool
with all other tests now.
This (temporarily?) removes the GPU multithreading feature
from DM, which we don't use.
On my desktop, DM runs a little faster (57s -> 55s) in
Debug, and a lot faster in Release (36s -> 24s). The bots
show speedups of similar proportions, cutting more than a
minute off the N4/Release and Win7/Debug runtimes.
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f
R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/531653002
2014-09-04 02:34:37 +04:00
|
|
|
static bool buildTestDir(int dirNo, int firstDirNo,
|
2014-07-18 16:08:14 +04:00
|
|
|
SkTDArray<TestResult>* tests, SkTDArray<SortByName*>* sorted) {
|
|
|
|
SkString dirName = get_out_path(dirNo, outStatusDir);
|
|
|
|
if (!dirName.size()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
SkOSFile::Iter iter(dirName.c_str(), "skp");
|
|
|
|
SkString filename;
|
|
|
|
while (iter.next(&filename)) {
|
|
|
|
TestResult test;
|
|
|
|
test.init(dirNo);
|
|
|
|
SkString spaceFile(filename);
|
|
|
|
char* spaces = spaceFile.writable_str();
|
|
|
|
int spaceSize = (int) spaceFile.size();
|
|
|
|
for (int index = 0; index < spaceSize; ++index) {
|
|
|
|
if (spaces[index] == '.') {
|
|
|
|
spaces[index] = ' ';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int success = sscanf(spaces, "%s %d %d skp", test.fFilename,
|
|
|
|
&test.fPixelError, &test.fTime);
|
|
|
|
if (success < 3) {
|
|
|
|
SkDebugf("failed to scan %s matched=%d\n", filename.c_str(), success);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
*tests[dirNo - firstDirNo].append() = test;
|
|
|
|
}
|
|
|
|
if (!sorted) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
SkTDArray<TestResult>& testSet = tests[dirNo - firstDirNo];
|
|
|
|
int count = testSet.count();
|
|
|
|
for (int index = 0; index < count; ++index) {
|
|
|
|
*sorted[dirNo - firstDirNo].append() = (SortByName*) &testSet[index];
|
|
|
|
}
|
|
|
|
if (sorted[dirNo - firstDirNo].count()) {
|
|
|
|
SkTQSort<SortByName>(sorted[dirNo - firstDirNo].begin(),
|
|
|
|
sorted[dirNo - firstDirNo].end() - 1);
|
|
|
|
if (verbose()) {
|
|
|
|
SkDebugf("+");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void testSkpClip(TestState* data) {
|
|
|
|
data->fResult.testOne();
|
|
|
|
SkString statName(data->fResult.fFilename);
|
|
|
|
SkASSERT(statName.endsWith(".skp"));
|
|
|
|
statName.remove(statName.size() - 4, 4);
|
|
|
|
statName.appendf(".%d.%d.skp", data->fResult.fPixelError, data->fResult.fTime);
|
|
|
|
SkString statusFile = get_out_path(data->fResult.fDirNo, outStatusDir);
|
|
|
|
if (!statusFile.size()) {
|
|
|
|
SkDebugf("failed to create %s", statusFile.c_str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
statusFile.appendf("%s%s", PATH_SLASH, statName.c_str());
|
|
|
|
SkFILE* file = sk_fopen(statusFile.c_str(), kWrite_SkFILE_Flag);
|
|
|
|
if (!file) {
|
|
|
|
SkDebugf("failed to create %s", statusFile.c_str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sk_fclose(file);
|
|
|
|
if (verbose()) {
|
|
|
|
if (data->fResult.fPixelError || data->fResult.fTime) {
|
|
|
|
SkDebugf("%s", data->fResult.progress().c_str());
|
|
|
|
} else {
|
|
|
|
SkDebugf(".");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Less(const SortByName& a, const SortByName& b);
|
|
|
|
bool Less(const SortByName& a, const SortByName& b) {
|
|
|
|
return a < b;
|
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
|
2014-04-25 16:59:11 +04:00
|
|
|
static bool doOneDir(TestState* state, bool threaded) {
|
2013-11-01 21:36:03 +04:00
|
|
|
int dirNo = state->fResult.fDirNo;
|
2014-07-18 16:08:14 +04:00
|
|
|
SkString dirName = get_in_path(dirNo, NULL);
|
2014-04-14 21:08:59 +04:00
|
|
|
if (!dirName.size()) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-07-18 16:08:14 +04:00
|
|
|
SkTDArray<TestResult> tests[1];
|
|
|
|
SkTDArray<SortByName*> sorted[1];
|
|
|
|
if (!buildTestDir(dirNo, dirNo, tests, sorted)) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
SkOSFile::Iter iter(dirName.c_str(), "skp");
|
2013-05-08 11:01:40 +04:00
|
|
|
SkString filename;
|
|
|
|
while (iter.next(&filename)) {
|
2014-07-18 16:08:14 +04:00
|
|
|
for (size_t index = 0; index < skipOverCount; ++index) {
|
|
|
|
if (skipOver[index].directory == dirNo
|
|
|
|
&& strcmp(filename.c_str(), skipOver[index].filename) == 0) {
|
2014-04-14 21:08:59 +04:00
|
|
|
goto checkEarlyExit;
|
2013-10-02 18:49:34 +04:00
|
|
|
}
|
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
{
|
2014-07-18 16:08:14 +04:00
|
|
|
SortByName name;
|
|
|
|
name.init(dirNo);
|
|
|
|
strncpy(name.fFilename, filename.c_str(), filename.size() - 4); // drop .skp
|
|
|
|
int count = sorted[0].count();
|
|
|
|
int idx = SkTSearch<SortByName, Less>(sorted[0].begin(), count, &name, sizeof(&name));
|
|
|
|
if (idx >= 0) {
|
|
|
|
SortByName* found = sorted[0][idx];
|
|
|
|
(void) addError(state, *found);
|
|
|
|
continue;
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
2014-07-18 16:08:14 +04:00
|
|
|
TestResult test;
|
|
|
|
test.init(dirNo, filename);
|
|
|
|
state->fResult = test;
|
|
|
|
testSkpClip(state);
|
|
|
|
#if 0 // artificially limit to a few while debugging code
|
|
|
|
static int debugLimit = 0;
|
|
|
|
if (++debugLimit == 5) {
|
|
|
|
return true;
|
2013-07-08 21:17:02 +04:00
|
|
|
}
|
2014-07-18 16:08:14 +04:00
|
|
|
#endif
|
2013-05-08 11:01:40 +04:00
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
checkEarlyExit:
|
2014-07-18 16:08:14 +04:00
|
|
|
;
|
2013-07-08 21:17:02 +04:00
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
static void initTest() {
|
2013-11-01 21:36:03 +04:00
|
|
|
#if !defined SK_BUILD_FOR_WIN && !defined SK_BUILD_FOR_MAC
|
|
|
|
SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true);
|
|
|
|
SK_CONF_SET("images.png.suppressDecoderWarnings", true);
|
|
|
|
#endif
|
2013-07-08 21:17:02 +04:00
|
|
|
}
|
|
|
|
|
2014-06-17 16:15:38 +04:00
|
|
|
static void testSkpClipEncode(TestState* data) {
|
|
|
|
data->fResult.testOne();
|
2014-07-18 16:08:14 +04:00
|
|
|
if (verbose()) {
|
|
|
|
SkDebugf("+");
|
2014-06-17 16:15:38 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
static void encodeFound(TestState& state) {
|
|
|
|
if (verbose()) {
|
2014-06-17 16:15:38 +04:00
|
|
|
if (state.fPixelWorst.count()) {
|
|
|
|
SkTDArray<SortByPixel*> worst;
|
|
|
|
for (int index = 0; index < state.fPixelWorst.count(); ++index) {
|
|
|
|
*worst.append() = &state.fPixelWorst[index];
|
|
|
|
}
|
|
|
|
SkTQSort<SortByPixel>(worst.begin(), worst.end() - 1);
|
|
|
|
for (int index = 0; index < state.fPixelWorst.count(); ++index) {
|
|
|
|
const TestResult& result = *worst[index];
|
|
|
|
SkDebugf("%d %s pixelError=%d\n", result.fDirNo, result.fFilename, result.fPixelError);
|
|
|
|
}
|
2014-04-14 21:08:59 +04:00
|
|
|
}
|
2014-06-17 16:15:38 +04:00
|
|
|
if (state.fSlowest.count()) {
|
|
|
|
SkTDArray<SortByTime*> slowest;
|
|
|
|
for (int index = 0; index < state.fSlowest.count(); ++index) {
|
|
|
|
*slowest.append() = &state.fSlowest[index];
|
|
|
|
}
|
|
|
|
if (slowest.count() > 0) {
|
|
|
|
SkTQSort<SortByTime>(slowest.begin(), slowest.end() - 1);
|
|
|
|
for (int index = 0; index < slowest.count(); ++index) {
|
|
|
|
const TestResult& result = *slowest[index];
|
|
|
|
SkDebugf("%d %s time=%d\n", result.fDirNo, result.fFilename, result.fTime);
|
|
|
|
}
|
|
|
|
}
|
2014-04-14 21:08:59 +04:00
|
|
|
}
|
2014-06-17 16:15:38 +04:00
|
|
|
}
|
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in
one global pool. Each SkTaskGroup itself is tiny (4 bytes)
and its wait() method applies only to tasks add()ed to that
instance, not the whole thread pool.
This means we don't need to bring up new thread pools when
tests themselves want to use multithreading (e.g. pathops,
quilt). We just create a new SkTaskGroup and wait for that
to complete. This should be more efficient, and allow us
to expand where we use threads to really latency sensitive
places. E.g. we can probably now use these in nanobench
for CPU .skp rendering.
Now that all threads are sharing the same pool, I think we
can remove most of the custom mechanism pathops tests use
to control threading. They'll just ride on the global pool
with all other tests now.
This (temporarily?) removes the GPU multithreading feature
from DM, which we don't use.
On my desktop, DM runs a little faster (57s -> 55s) in
Debug, and a lot faster in Release (36s -> 24s). The bots
show speedups of similar proportions, cutting more than a
minute off the N4/Release and Win7/Debug runtimes.
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f
R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/531653002
2014-09-04 02:34:37 +04:00
|
|
|
TestRunner testRunner;
|
2014-06-17 16:15:38 +04:00
|
|
|
for (int index = 0; index < state.fPixelWorst.count(); ++index) {
|
|
|
|
const TestResult& result = state.fPixelWorst[index];
|
|
|
|
SkString filename(result.fFilename);
|
|
|
|
if (!filename.endsWith(".skp")) {
|
|
|
|
filename.append(".skp");
|
2013-06-04 21:59:42 +04:00
|
|
|
}
|
2014-06-17 16:15:38 +04:00
|
|
|
*testRunner.fRunnables.append() = SkNEW_ARGS(TestRunnableEncode,
|
|
|
|
(&testSkpClipEncode, result.fDirNo, filename.c_str(), &testRunner));
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
2014-06-17 16:15:38 +04:00
|
|
|
testRunner.render();
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
class Test {
|
|
|
|
public:
|
|
|
|
Test() {}
|
|
|
|
virtual ~Test() {}
|
|
|
|
|
|
|
|
const char* getName() { onGetName(&fName); return fName.c_str(); }
|
|
|
|
void run() { onRun(); }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void onGetName(SkString*) = 0;
|
|
|
|
virtual void onRun() = 0;
|
|
|
|
|
|
|
|
private:
|
|
|
|
SkString fName;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef SkTRegistry<Test*(*)(void*)> TestRegistry;
|
|
|
|
|
|
|
|
#define DEF_TEST(name) \
|
|
|
|
static void test_##name(); \
|
|
|
|
class name##Class : public Test { \
|
|
|
|
public: \
|
|
|
|
static Test* Factory(void*) { return SkNEW(name##Class); } \
|
|
|
|
protected: \
|
|
|
|
virtual void onGetName(SkString* name) SK_OVERRIDE { \
|
|
|
|
name->set(#name); \
|
|
|
|
} \
|
|
|
|
virtual void onRun() SK_OVERRIDE { test_##name(); } \
|
|
|
|
}; \
|
|
|
|
static TestRegistry gReg_##name##Class(name##Class::Factory); \
|
|
|
|
static void test_##name()
|
|
|
|
|
|
|
|
DEF_TEST(PathOpsSkpClip) {
|
|
|
|
gDirs.setDefault();
|
|
|
|
initTest();
|
2013-11-01 21:36:03 +04:00
|
|
|
SkTArray<TestResult, true> errors;
|
|
|
|
TestState state;
|
2014-07-18 16:08:14 +04:00
|
|
|
state.init(0);
|
|
|
|
int dirNo;
|
|
|
|
gDirs.reset();
|
|
|
|
while ((dirNo = gDirs.next()) > 0) {
|
|
|
|
if (verbose()) {
|
2013-11-01 21:36:03 +04:00
|
|
|
SkDebugf("dirNo=%d\n", dirNo);
|
2013-10-02 18:49:34 +04:00
|
|
|
}
|
2013-11-01 21:36:03 +04:00
|
|
|
state.fResult.fDirNo = dirNo;
|
2014-04-25 16:59:11 +04:00
|
|
|
if (!doOneDir(&state, false)) {
|
2013-11-01 21:36:03 +04:00
|
|
|
break;
|
2013-10-02 18:49:34 +04:00
|
|
|
}
|
|
|
|
}
|
2014-07-18 16:08:14 +04:00
|
|
|
encodeFound(state);
|
2013-10-02 18:49:34 +04:00
|
|
|
}
|
|
|
|
|
2013-11-01 21:36:03 +04:00
|
|
|
static void testSkpClipMain(TestState* data) {
|
2014-04-25 16:59:11 +04:00
|
|
|
(void) doOneDir(data, true);
|
2013-07-08 21:17:02 +04:00
|
|
|
}
|
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
DEF_TEST(PathOpsSkpClipThreaded) {
|
|
|
|
gDirs.setDefault();
|
|
|
|
initTest();
|
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in
one global pool. Each SkTaskGroup itself is tiny (4 bytes)
and its wait() method applies only to tasks add()ed to that
instance, not the whole thread pool.
This means we don't need to bring up new thread pools when
tests themselves want to use multithreading (e.g. pathops,
quilt). We just create a new SkTaskGroup and wait for that
to complete. This should be more efficient, and allow us
to expand where we use threads to really latency sensitive
places. E.g. we can probably now use these in nanobench
for CPU .skp rendering.
Now that all threads are sharing the same pool, I think we
can remove most of the custom mechanism pathops tests use
to control threading. They'll just ride on the global pool
with all other tests now.
This (temporarily?) removes the GPU multithreading feature
from DM, which we don't use.
On my desktop, DM runs a little faster (57s -> 55s) in
Debug, and a lot faster in Release (36s -> 24s). The bots
show speedups of similar proportions, cutting more than a
minute off the N4/Release and Win7/Debug runtimes.
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f
R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/531653002
2014-09-04 02:34:37 +04:00
|
|
|
TestRunner testRunner;
|
2014-07-18 16:08:14 +04:00
|
|
|
int dirNo;
|
|
|
|
gDirs.reset();
|
|
|
|
while ((dirNo = gDirs.next()) > 0) {
|
2014-06-17 16:15:38 +04:00
|
|
|
*testRunner.fRunnables.append() = SkNEW_ARGS(TestRunnableDir,
|
2013-11-01 21:36:03 +04:00
|
|
|
(&testSkpClipMain, dirNo, &testRunner));
|
2013-05-08 11:01:40 +04:00
|
|
|
}
|
2013-07-08 21:17:02 +04:00
|
|
|
testRunner.render();
|
2013-11-01 21:36:03 +04:00
|
|
|
TestState state;
|
2014-07-18 16:08:14 +04:00
|
|
|
state.init(0);
|
|
|
|
gDirs.reset();
|
|
|
|
while ((dirNo = gDirs.next()) > 0) {
|
2013-11-01 21:36:03 +04:00
|
|
|
TestState& testState = testRunner.fRunnables[dirNo - 1]->fState;
|
2014-06-17 16:15:38 +04:00
|
|
|
SkASSERT(testState.fResult.fDirNo == dirNo);
|
2014-04-14 21:08:59 +04:00
|
|
|
for (int inner = 0; inner < testState.fPixelWorst.count(); ++inner) {
|
|
|
|
addError(&state, testState.fPixelWorst[inner]);
|
2013-10-02 18:49:34 +04:00
|
|
|
}
|
2014-06-17 16:15:38 +04:00
|
|
|
for (int inner = 0; inner < testState.fSlowest.count(); ++inner) {
|
|
|
|
addError(&state, testState.fSlowest[inner]);
|
|
|
|
}
|
|
|
|
}
|
2014-07-18 16:08:14 +04:00
|
|
|
encodeFound(state);
|
2014-06-17 16:15:38 +04:00
|
|
|
}
|
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in
one global pool. Each SkTaskGroup itself is tiny (4 bytes)
and its wait() method applies only to tasks add()ed to that
instance, not the whole thread pool.
This means we don't need to bring up new thread pools when
tests themselves want to use multithreading (e.g. pathops,
quilt). We just create a new SkTaskGroup and wait for that
to complete. This should be more efficient, and allow us
to expand where we use threads to really latency sensitive
places. E.g. we can probably now use these in nanobench
for CPU .skp rendering.
Now that all threads are sharing the same pool, I think we
can remove most of the custom mechanism pathops tests use
to control threading. They'll just ride on the global pool
with all other tests now.
This (temporarily?) removes the GPU multithreading feature
from DM, which we don't use.
On my desktop, DM runs a little faster (57s -> 55s) in
Debug, and a lot faster in Release (36s -> 24s). The bots
show speedups of similar proportions, cutting more than a
minute off the N4/Release and Win7/Debug runtimes.
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f
R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/531653002
2014-09-04 02:34:37 +04:00
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
static bool buildTests(SkTDArray<TestResult>* tests, SkTDArray<SortByName*>* sorted) {
|
|
|
|
int firstDirNo = gDirs.first();
|
|
|
|
int dirNo;
|
|
|
|
while ((dirNo = gDirs.next()) > 0) {
|
|
|
|
if (!buildTestDir(dirNo, firstDirNo, tests, sorted)) {
|
2014-06-17 16:15:38 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
DEF_TEST(PathOpsSkpClipUberThreaded) {
|
|
|
|
gDirs.setDefault();
|
|
|
|
const int firstDirNo = gDirs.next();
|
|
|
|
const int lastDirNo = gDirs.last();
|
|
|
|
initTest();
|
|
|
|
int dirCount = lastDirNo - firstDirNo + 1;
|
|
|
|
SkAutoTDeleteArray<SkTDArray<TestResult> > tests(new SkTDArray<TestResult>[dirCount]);
|
|
|
|
SkAutoTDeleteArray<SkTDArray<SortByName*> > sorted(new SkTDArray<SortByName*>[dirCount]);
|
|
|
|
if (!buildTests(tests.get(), sorted.get())) {
|
2014-06-17 16:15:38 +04:00
|
|
|
return;
|
|
|
|
}
|
SkThreadPool ~~> SkTaskGroup
SkTaskGroup is like SkThreadPool except the threads stay in
one global pool. Each SkTaskGroup itself is tiny (4 bytes)
and its wait() method applies only to tasks add()ed to that
instance, not the whole thread pool.
This means we don't need to bring up new thread pools when
tests themselves want to use multithreading (e.g. pathops,
quilt). We just create a new SkTaskGroup and wait for that
to complete. This should be more efficient, and allow us
to expand where we use threads to really latency sensitive
places. E.g. we can probably now use these in nanobench
for CPU .skp rendering.
Now that all threads are sharing the same pool, I think we
can remove most of the custom mechanism pathops tests use
to control threading. They'll just ride on the global pool
with all other tests now.
This (temporarily?) removes the GPU multithreading feature
from DM, which we don't use.
On my desktop, DM runs a little faster (57s -> 55s) in
Debug, and a lot faster in Release (36s -> 24s). The bots
show speedups of similar proportions, cutting more than a
minute off the N4/Release and Win7/Debug runtimes.
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/9c7207b5dc71dc5a96a2eb107d401133333d5b6f
R=caryclark@google.com, bsalomon@google.com, bungeman@google.com, mtklein@google.com, reed@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/531653002
2014-09-04 02:34:37 +04:00
|
|
|
TestRunner testRunner;
|
2014-07-18 16:08:14 +04:00
|
|
|
int dirNo;
|
|
|
|
gDirs.reset();
|
|
|
|
while ((dirNo = gDirs.next()) > 0) {
|
|
|
|
SkString dirName = get_in_path(dirNo, NULL);
|
2014-06-17 16:15:38 +04:00
|
|
|
if (!dirName.size()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
SkOSFile::Iter iter(dirName.c_str(), "skp");
|
|
|
|
SkString filename;
|
|
|
|
while (iter.next(&filename)) {
|
2014-07-18 16:08:14 +04:00
|
|
|
for (size_t index = 0; index < skipOverCount; ++index) {
|
|
|
|
if (skipOver[index].directory == dirNo
|
|
|
|
&& strcmp(filename.c_str(), skipOver[index].filename) == 0) {
|
2014-06-17 16:15:38 +04:00
|
|
|
goto checkEarlyExit;
|
|
|
|
}
|
|
|
|
}
|
2014-07-18 16:08:14 +04:00
|
|
|
{
|
|
|
|
SortByName name;
|
|
|
|
name.init(dirNo);
|
|
|
|
strncpy(name.fFilename, filename.c_str(), filename.size() - 4); // drop .skp
|
|
|
|
int count = sorted.get()[dirNo - firstDirNo].count();
|
|
|
|
if (SkTSearch<SortByName, Less>(sorted.get()[dirNo - firstDirNo].begin(),
|
|
|
|
count, &name, sizeof(&name)) < 0) {
|
|
|
|
*testRunner.fRunnables.append() = SkNEW_ARGS(TestRunnableFile,
|
|
|
|
(&testSkpClip, dirNo, filename.c_str(), &testRunner));
|
|
|
|
}
|
2014-06-17 16:15:38 +04:00
|
|
|
}
|
|
|
|
checkEarlyExit:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
testRunner.render();
|
2014-07-18 16:08:14 +04:00
|
|
|
SkAutoTDeleteArray<SkTDArray<TestResult> > results(new SkTDArray<TestResult>[dirCount]);
|
|
|
|
if (!buildTests(results.get(), NULL)) {
|
2014-06-17 16:15:38 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
SkTDArray<TestResult> allResults;
|
|
|
|
for (int dirNo = firstDirNo; dirNo <= lastDirNo; ++dirNo) {
|
2014-07-18 16:08:14 +04:00
|
|
|
SkTDArray<TestResult>& array = results.get()[dirNo - firstDirNo];
|
2014-06-17 16:15:38 +04:00
|
|
|
allResults.append(array.count(), array.begin());
|
|
|
|
}
|
|
|
|
int allCount = allResults.count();
|
|
|
|
SkTDArray<SortByPixel*> pixels;
|
|
|
|
SkTDArray<SortByTime*> times;
|
|
|
|
for (int index = 0; index < allCount; ++index) {
|
|
|
|
*pixels.append() = (SortByPixel*) &allResults[index];
|
|
|
|
*times.append() = (SortByTime*) &allResults[index];
|
|
|
|
}
|
|
|
|
TestState state;
|
|
|
|
if (pixels.count()) {
|
|
|
|
SkTQSort<SortByPixel>(pixels.begin(), pixels.end() - 1);
|
|
|
|
for (int inner = 0; inner < kMaxFiles; ++inner) {
|
|
|
|
*state.fPixelWorst.append() = *pixels[allCount - inner - 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (times.count()) {
|
|
|
|
SkTQSort<SortByTime>(times.begin(), times.end() - 1);
|
|
|
|
for (int inner = 0; inner < kMaxFiles; ++inner) {
|
|
|
|
*state.fSlowest.append() = *times[allCount - inner - 1];
|
|
|
|
}
|
2013-10-02 18:49:34 +04:00
|
|
|
}
|
2014-07-18 16:08:14 +04:00
|
|
|
encodeFound(state);
|
2013-10-02 18:49:34 +04:00
|
|
|
}
|
|
|
|
|
2014-07-18 16:08:14 +04:00
|
|
|
DEF_TEST(PathOpsSkpClipOneOff) {
|
|
|
|
const int testIndex = FLAGS_testIndex;
|
|
|
|
int dirNo = gDirs.next();
|
|
|
|
if (dirNo < 0) {
|
|
|
|
dirNo = skipOver[testIndex].directory;
|
|
|
|
}
|
|
|
|
const char* skp = gNames.next();
|
|
|
|
if (!skp) {
|
|
|
|
skp = skipOver[testIndex].filename;
|
2013-11-01 21:36:03 +04:00
|
|
|
}
|
2014-07-18 16:08:14 +04:00
|
|
|
initTest();
|
|
|
|
SkAssertResult(get_in_path(dirNo, skp).size());
|
|
|
|
SkString filename(skp);
|
2013-11-01 21:36:03 +04:00
|
|
|
TestResult state;
|
|
|
|
state.test(dirNo, filename);
|
2014-07-18 16:08:14 +04:00
|
|
|
if (verbose()) {
|
2013-11-01 21:36:03 +04:00
|
|
|
SkDebugf("%s", state.status().c_str());
|
|
|
|
}
|
|
|
|
state.fTestStep = kEncodeFiles;
|
|
|
|
state.testOne();
|
2013-05-08 11:01:40 +04:00
|
|
|
}
|
2014-07-18 16:08:14 +04:00
|
|
|
|
|
|
|
DEF_TEST(PathOpsTestSkipped) {
|
|
|
|
for (size_t index = 0; index < skipOverCount; ++index) {
|
|
|
|
const SkipOverTest& skip = skipOver[index];
|
|
|
|
if (!skip.blamePathOps) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
int dirNo = skip.directory;
|
|
|
|
const char* skp = skip.filename;
|
|
|
|
initTest();
|
|
|
|
SkAssertResult(get_in_path(dirNo, skp).size());
|
|
|
|
SkString filename(skp);
|
|
|
|
TestResult state;
|
|
|
|
state.test(dirNo, filename);
|
|
|
|
if (verbose()) {
|
|
|
|
SkDebugf("%s", state.status().c_str());
|
|
|
|
}
|
|
|
|
state.fTestStep = kEncodeFiles;
|
|
|
|
state.testOne();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DEF_TEST(PathOpsCopyFails) {
|
|
|
|
FLAGS_verbose = true;
|
|
|
|
for (size_t index = 0; index < skipOverCount; ++index) {
|
|
|
|
int dirNo = skipOver[index].directory;
|
|
|
|
SkDebugf("mkdir -p " IN_DIR_PRE "%d" DIR_POST "\n", dirNo);
|
|
|
|
}
|
|
|
|
for (size_t index = 0; index < skipOverCount; ++index) {
|
|
|
|
int dirNo = skipOver[index].directory;
|
|
|
|
const char* filename = skipOver[index].filename;
|
|
|
|
SkDebugf("rsync -av cary-linux.cnc:/tera" PATH_SLASH "skps" PATH_SLASH "slave"
|
|
|
|
"%d" DIR_POST "/%s " IN_DIR_PRE "%d" DIR_POST "\n", dirNo, filename, dirNo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template TestRegistry* TestRegistry::gHead;
|
|
|
|
|
|
|
|
class Iter {
|
|
|
|
public:
|
|
|
|
Iter() { this->reset(); }
|
|
|
|
void reset() { fReg = TestRegistry::Head(); }
|
|
|
|
|
|
|
|
Test* next() {
|
|
|
|
if (fReg) {
|
|
|
|
TestRegistry::Factory fact = fReg->factory();
|
|
|
|
fReg = fReg->next();
|
|
|
|
Test* test = fact(NULL);
|
|
|
|
return test;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const TestRegistry* fReg;
|
|
|
|
};
|
|
|
|
|
|
|
|
int tool_main(int argc, char** argv);
|
|
|
|
int tool_main(int argc, char** argv) {
|
|
|
|
SetupCrashHandler();
|
|
|
|
SkCommandLineFlags::SetUsage("");
|
|
|
|
SkCommandLineFlags::Parse(argc, argv);
|
|
|
|
SkGraphics::Init();
|
|
|
|
SkString header("PathOps SkpClip:");
|
|
|
|
if (!FLAGS_match.isEmpty()) {
|
|
|
|
header.appendf(" --match");
|
|
|
|
for (int index = 0; index < FLAGS_match.count(); ++index) {
|
|
|
|
header.appendf(" %s", FLAGS_match[index]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!FLAGS_dir.isEmpty()) {
|
|
|
|
int count = FLAGS_dir.count();
|
|
|
|
for (int i = 0; i < count; ++i) {
|
|
|
|
const char* range = FLAGS_dir[i];
|
|
|
|
const char* dash = strchr(range, '-');
|
|
|
|
if (!dash) {
|
|
|
|
dash = strchr(range, ',');
|
|
|
|
}
|
|
|
|
int first = atoi(range);
|
|
|
|
int last = dash ? atoi(dash + 1) : first;
|
|
|
|
if (!first || !last) {
|
|
|
|
SkDebugf("couldn't parse --dir %s\n", range);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
gDirs.set(first, last);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!FLAGS_skp.isEmpty()) {
|
|
|
|
gNames.set(FLAGS_skp);
|
|
|
|
}
|
|
|
|
#ifdef SK_DEBUG
|
|
|
|
header.append(" SK_DEBUG");
|
|
|
|
#else
|
|
|
|
header.append(" SK_RELEASE");
|
|
|
|
#endif
|
|
|
|
header.appendf(" skia_arch_width=%d", (int)sizeof(void*) * 8);
|
|
|
|
if (FLAGS_verbose) {
|
|
|
|
header.appendf("\n");
|
|
|
|
}
|
|
|
|
SkDebugf(header.c_str());
|
|
|
|
Iter iter;
|
|
|
|
Test* test;
|
|
|
|
while ((test = iter.next()) != NULL) {
|
|
|
|
SkAutoTDelete<Test> owned(test);
|
|
|
|
if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) {
|
|
|
|
test->run();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SkGraphics::Term();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
|
|
|
|
int main(int argc, char * const argv[]) {
|
|
|
|
return tool_main(argc, (char**) argv);
|
|
|
|
}
|
|
|
|
#endif
|