OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "CrashHandler.h" | 8 #include "CrashHandler.h" |
9 #include "DMJsonWriter.h" | 9 #include "DMJsonWriter.h" |
10 #include "DMSrcSink.h" | 10 #include "DMSrcSink.h" |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
64 "this list, no image is written for that result."); | 64 "this list, no image is written for that result."); |
65 | 65 |
66 DEFINE_int32(shards, 1, "We're splitting source data into this many shards."); | 66 DEFINE_int32(shards, 1, "We're splitting source data into this many shards."); |
67 DEFINE_int32(shard, 0, "Which shard do I run?"); | 67 DEFINE_int32(shard, 0, "Which shard do I run?"); |
68 | 68 |
69 __SK_FORCE_IMAGE_DECODER_LINKING; | 69 __SK_FORCE_IMAGE_DECODER_LINKING; |
70 using namespace DM; | 70 using namespace DM; |
71 | 71 |
72 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~*/ | 72 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~*/ |
73 | 73 |
74 static double now_ms() { return SkTime::GetNSecs() * 1e-6; } | |
75 | |
76 SK_DECLARE_STATIC_MUTEX(gFailuresMutex); | 74 SK_DECLARE_STATIC_MUTEX(gFailuresMutex); |
77 static SkTArray<SkString> gFailures; | 75 static SkTArray<SkString> gFailures; |
78 | 76 |
79 static void fail(ImplicitString err) { | 77 static void fail(const SkString& err) { |
80 SkAutoMutexAcquire lock(gFailuresMutex); | 78 SkAutoMutexAcquire lock(gFailuresMutex); |
81 SkDebugf("\n\nFAILURE: %s\n\n", err.c_str()); | 79 SkDebugf("\n\nFAILURE: %s\n\n", err.c_str()); |
82 gFailures.push_back(err); | 80 gFailures.push_back(err); |
83 } | 81 } |
84 | 82 |
85 | 83 |
86 // We use a spinlock to make locking this in a signal handler _somewhat_ safe. | 84 // We use a spinlock to make locking this in a signal handler _somewhat_ safe. |
87 SK_DECLARE_STATIC_SPINLOCK(gMutex); | 85 SK_DECLARE_STATIC_SPINLOCK(gMutex); |
88 static int32_t gPending; | 86 static int32_t gPending; |
89 static SkTArray<SkString> gRunning; | 87 static SkTArray<SkString> gRunning; |
90 static SkTHashMap<SkString, int> gNoteTally; | |
91 | 88 |
92 static void done(double ms, | 89 static void done(const char* config, const char* src, const char* srcOptions, co
nst char* name) { |
93 ImplicitString config, ImplicitString src, ImplicitString srcOp
tions, | 90 SkString id = SkStringPrintf("%s %s %s %s", config, src, srcOptions, name); |
94 ImplicitString name, ImplicitString note, ImplicitString log) { | |
95 SkString id = SkStringPrintf("%s %s %s %s", config.c_str(), src.c_str(), | |
96 srcOptions.c_str(), name.c_str()
); | |
97 int pending; | 91 int pending; |
98 { | 92 { |
99 SkAutoTAcquire<SkPODSpinlock> lock(gMutex); | 93 SkAutoTAcquire<SkPODSpinlock> lock(gMutex); |
100 for (int i = 0; i < gRunning.count(); i++) { | 94 for (int i = 0; i < gRunning.count(); i++) { |
101 if (gRunning[i] == id) { | 95 if (gRunning[i] == id) { |
102 gRunning.removeShuffle(i); | 96 gRunning.removeShuffle(i); |
103 break; | 97 break; |
104 } | 98 } |
105 } | 99 } |
106 if (!note.isEmpty()) { | |
107 if (int* tally = gNoteTally.find(note)) { | |
108 *tally += 1; | |
109 } else { | |
110 gNoteTally.set(note, 1); | |
111 } | |
112 } | |
113 pending = --gPending; | 100 pending = --gPending; |
114 } | 101 } |
115 // We write our dm.json file every once in a while in case we crash. | 102 // We write our dm.json file every once in a while in case we crash. |
116 // Notice this also handles the final dm.json when pending == 0. | 103 // Notice this also handles the final dm.json when pending == 0. |
117 if (pending % 500 == 0) { | 104 if (pending % 500 == 0) { |
118 JsonWriter::DumpJson(); | 105 JsonWriter::DumpJson(); |
119 } | 106 } |
120 } | 107 } |
121 | 108 |
122 static void start(ImplicitString config, ImplicitString src, | 109 static void start(const char* config, const char* src, const char* srcOptions, c
onst char* name) { |
123 ImplicitString srcOptions, ImplicitString name) { | 110 SkString id = SkStringPrintf("%s %s %s %s", config, src, srcOptions, name); |
124 SkString id = SkStringPrintf("%s %s %s %s", config.c_str(), src.c_str(), | |
125 srcOptions.c_str(), name.c_str()
); | |
126 SkAutoTAcquire<SkPODSpinlock> lock(gMutex); | 111 SkAutoTAcquire<SkPODSpinlock> lock(gMutex); |
127 gRunning.push_back(id); | 112 gRunning.push_back(id); |
128 } | 113 } |
129 | 114 |
130 static void print_status() { | 115 static void print_status() { |
131 static SkMSec start_ms = SkTime::GetMSecs(); | 116 static SkMSec start_ms = SkTime::GetMSecs(); |
132 | 117 |
133 int curr = sk_tools::getCurrResidentSetSizeMB(), | 118 int curr = sk_tools::getCurrResidentSetSizeMB(), |
134 peak = sk_tools::getMaxResidentSetSizeMB(); | 119 peak = sk_tools::getMaxResidentSetSizeMB(); |
135 SkString elapsed = HumanizeMs(SkTime::GetMSecs() - start_ms); | 120 SkString elapsed = HumanizeMs(SkTime::GetMSecs() - start_ms); |
(...skipping 22 matching lines...) Expand all Loading... |
158 print_status(); | 143 print_status(); |
159 }); | 144 }); |
160 } | 145 } |
161 } | 146 } |
162 #endif | 147 #endif |
163 | 148 |
164 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~*/ | 149 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~*/ |
165 | 150 |
166 struct Gold : public SkString { | 151 struct Gold : public SkString { |
167 Gold() : SkString("") {} | 152 Gold() : SkString("") {} |
168 Gold(ImplicitString sink, ImplicitString src, ImplicitString srcOptions, | 153 Gold(const SkString& sink, const SkString& src, |
169 ImplicitString name, ImplicitString md5) | 154 const SkString& srcOptions, const SkString& name, |
| 155 const SkString& md5) |
170 : SkString("") { | 156 : SkString("") { |
171 this->append(sink); | 157 this->append(sink); |
172 this->append(src); | 158 this->append(src); |
173 this->append(srcOptions); | 159 this->append(srcOptions); |
174 this->append(name); | 160 this->append(name); |
175 this->append(md5); | 161 this->append(md5); |
176 } | 162 } |
177 struct Hash { | 163 struct Hash { |
178 uint32_t operator()(const Gold& g) const { | 164 uint32_t operator()(const Gold& g) const { |
179 return SkGoodHash()((const SkString&)g); | 165 return SkGoodHash()((const SkString&)g); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 gUninterestingHashes.add(hash); | 200 gUninterestingHashes.add(hash); |
215 } | 201 } |
216 SkDebugf("FYI: loaded %d distinct uninteresting hashes from %d lines\n", | 202 SkDebugf("FYI: loaded %d distinct uninteresting hashes from %d lines\n", |
217 gUninterestingHashes.count(), hashes.count()); | 203 gUninterestingHashes.count(), hashes.count()); |
218 } | 204 } |
219 } | 205 } |
220 | 206 |
221 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~*/ | 207 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~*/ |
222 | 208 |
223 struct TaggedSrc : public SkAutoTDelete<Src> { | 209 struct TaggedSrc : public SkAutoTDelete<Src> { |
224 ImplicitString tag; | 210 SkString tag; |
225 ImplicitString options; | 211 SkString options; |
226 }; | 212 }; |
227 | 213 |
228 struct TaggedSink : public SkAutoTDelete<Sink> { | 214 struct TaggedSink : public SkAutoTDelete<Sink> { |
229 SkString tag; | 215 SkString tag; |
230 }; | 216 }; |
231 | 217 |
232 static const bool kMemcpyOK = true; | 218 static const bool kMemcpyOK = true; |
233 | 219 |
234 static SkTArray<TaggedSrc, kMemcpyOK> gSrcs; | 220 static SkTArray<TaggedSrc, kMemcpyOK> gSrcs; |
235 static SkTArray<TaggedSink, kMemcpyOK> gSinks; | 221 static SkTArray<TaggedSink, kMemcpyOK> gSinks; |
236 | 222 |
237 static bool in_shard() { | 223 static bool in_shard() { |
238 static int N = 0; | 224 static int N = 0; |
239 return N++ % FLAGS_shards == FLAGS_shard; | 225 return N++ % FLAGS_shards == FLAGS_shard; |
240 } | 226 } |
241 | 227 |
242 static void push_src(ImplicitString tag, ImplicitString options, Src* s) { | 228 static void push_src(const char* tag, ImplicitString options, Src* s) { |
243 SkAutoTDelete<Src> src(s); | 229 SkAutoTDelete<Src> src(s); |
244 if (in_shard() && | 230 if (in_shard() && |
245 FLAGS_src.contains(tag.c_str()) && | 231 FLAGS_src.contains(tag) && |
246 !SkCommandLineFlags::ShouldSkip(FLAGS_match, src->name().c_str())) { | 232 !SkCommandLineFlags::ShouldSkip(FLAGS_match, src->name().c_str())) { |
247 TaggedSrc& s = gSrcs.push_back(); | 233 TaggedSrc& s = gSrcs.push_back(); |
248 s.reset(src.detach()); | 234 s.reset(src.detach()); |
249 s.tag = tag; | 235 s.tag = tag; |
250 s.options = options; | 236 s.options = options; |
251 } | 237 } |
252 } | 238 } |
253 | 239 |
254 static void push_codec_src(Path path, CodecSrc::Mode mode, CodecSrc::DstColorTyp
e dstColorType, | 240 static void push_codec_src(Path path, CodecSrc::Mode mode, CodecSrc::DstColorTyp
e dstColorType, |
255 SkAlphaType dstAlphaType, float scale) { | 241 SkAlphaType dstAlphaType, float scale) { |
(...skipping 593 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
849 | 835 |
850 png_destroy_write_struct(&png, &info); | 836 png_destroy_write_struct(&png, &info); |
851 fclose(f); | 837 fclose(f); |
852 return true; | 838 return true; |
853 } | 839 } |
854 | 840 |
855 static bool match(const char* needle, const char* haystack) { | 841 static bool match(const char* needle, const char* haystack) { |
856 return 0 == strcmp("_", needle) || nullptr != strstr(haystack, needle); | 842 return 0 == strcmp("_", needle) || nullptr != strstr(haystack, needle); |
857 } | 843 } |
858 | 844 |
859 static ImplicitString is_blacklisted(const char* sink, const char* src, | 845 static bool is_blacklisted(const char* sink, const char* src, |
860 const char* srcOptions, const char* name) { | 846 const char* srcOptions, const char* name) { |
861 for (int i = 0; i < FLAGS_blacklist.count() - 3; i += 4) { | 847 for (int i = 0; i < FLAGS_blacklist.count() - 3; i += 4) { |
862 if (match(FLAGS_blacklist[i+0], sink) && | 848 if (match(FLAGS_blacklist[i+0], sink) && |
863 match(FLAGS_blacklist[i+1], src) && | 849 match(FLAGS_blacklist[i+1], src) && |
864 match(FLAGS_blacklist[i+2], srcOptions) && | 850 match(FLAGS_blacklist[i+2], srcOptions) && |
865 match(FLAGS_blacklist[i+3], name)) { | 851 match(FLAGS_blacklist[i+3], name)) { |
866 return SkStringPrintf("%s %s %s %s", | 852 return true; |
867 FLAGS_blacklist[i+0], FLAGS_blacklist[i+1], | |
868 FLAGS_blacklist[i+2], FLAGS_blacklist[i+3]); | |
869 } | 853 } |
870 } | 854 } |
871 return ""; | 855 return false; |
872 } | 856 } |
873 | 857 |
874 // Even when a Task Sink reports to be non-threadsafe (e.g. GPU), we know things
like | 858 // Even when a Task Sink reports to be non-threadsafe (e.g. GPU), we know things
like |
875 // .png encoding are definitely thread safe. This lets us offload that work to
CPU threads. | 859 // .png encoding are definitely thread safe. This lets us offload that work to
CPU threads. |
876 static SkTaskGroup gDefinitelyThreadSafeWork; | 860 static SkTaskGroup gDefinitelyThreadSafeWork; |
877 | 861 |
878 // The finest-grained unit of work we can run: draw a single Src into a single S
ink, | 862 // The finest-grained unit of work we can run: draw a single Src into a single S
ink, |
879 // report any errors, and perhaps write out the output: a .png of the bitmap, or
a raw stream. | 863 // report any errors, and perhaps write out the output: a .png of the bitmap, or
a raw stream. |
880 struct Task { | 864 struct Task { |
881 Task(const TaggedSrc& src, const TaggedSink& sink) : src(src), sink(sink) {} | 865 Task(const TaggedSrc& src, const TaggedSink& sink) : src(src), sink(sink) {} |
882 const TaggedSrc& src; | 866 const TaggedSrc& src; |
883 const TaggedSink& sink; | 867 const TaggedSink& sink; |
884 | 868 |
885 static void Run(const Task& task) { | 869 static void Run(const Task& task) { |
886 SkString name = task.src->name(); | 870 SkString name = task.src->name(); |
887 | 871 |
888 // We'll skip drawing this Src/Sink pair if: | |
889 // - the Src vetoes the Sink; | |
890 // - this Src / Sink combination is on the blacklist; | |
891 // - it's a dry run. | |
892 SkString note(task.src->veto(task.sink->flags()) ? " (veto)" : ""); | |
893 SkString whyBlacklisted = is_blacklisted(task.sink.tag.c_str(), task.src
.tag.c_str(), | |
894 task.src.options.c_str(), name.
c_str()); | |
895 if (!whyBlacklisted.isEmpty()) { | |
896 note.appendf(" (--blacklist %s)", whyBlacklisted.c_str()); | |
897 } | |
898 | |
899 SkString log; | 872 SkString log; |
900 auto timerStart = now_ms(); | 873 if (!FLAGS_dryRun) { |
901 if (!FLAGS_dryRun && note.isEmpty()) { | |
902 SkBitmap bitmap; | 874 SkBitmap bitmap; |
903 SkDynamicMemoryWStream stream; | 875 SkDynamicMemoryWStream stream; |
904 start(task.sink.tag.c_str(), task.src.tag, task.src.options, name.c_
str()); | 876 start(task.sink.tag.c_str(), task.src.tag.c_str(), |
| 877 task.src.options.c_str(), name.c_str()); |
905 Error err = task.sink->draw(*task.src, &bitmap, &stream, &log); | 878 Error err = task.sink->draw(*task.src, &bitmap, &stream, &log); |
906 if (!err.isEmpty()) { | 879 if (!err.isEmpty()) { |
907 if (err.isFatal()) { | 880 if (err.isFatal()) { |
908 fail(SkStringPrintf("%s %s %s %s: %s", | 881 fail(SkStringPrintf("%s %s %s %s: %s", |
909 task.sink.tag.c_str(), | 882 task.sink.tag.c_str(), |
910 task.src.tag.c_str(), | 883 task.src.tag.c_str(), |
911 task.src.options.c_str(), | 884 task.src.options.c_str(), |
912 name.c_str(), | 885 name.c_str(), |
913 err.c_str())); | 886 err.c_str())); |
914 } else { | 887 } else { |
915 note.appendf(" (skipped: %s)", err.c_str()); | 888 done(task.sink.tag.c_str(), task.src.tag.c_str(), |
916 auto elapsed = now_ms() - timerStart; | 889 task.src.options.c_str(), name.c_str()); |
917 done(elapsed, task.sink.tag.c_str(), task.src.tag, task.src.
options, | |
918 name, note, log); | |
919 return; | 890 return; |
920 } | 891 } |
921 } | 892 } |
922 | 893 |
923 // We're likely switching threads here, so we must capture by value,
[=] or [foo,bar]. | 894 // We're likely switching threads here, so we must capture by value,
[=] or [foo,bar]. |
924 SkStreamAsset* data = stream.detachAsStream(); | 895 SkStreamAsset* data = stream.detachAsStream(); |
925 gDefinitelyThreadSafeWork.add([task,name,bitmap,data]{ | 896 gDefinitelyThreadSafeWork.add([task,name,bitmap,data]{ |
926 SkAutoTDelete<SkStreamAsset> ownedData(data); | 897 SkAutoTDelete<SkStreamAsset> ownedData(data); |
927 | 898 |
928 // Why doesn't the copy constructor do this when we have pre-loc
ked pixels? | 899 // Why doesn't the copy constructor do this when we have pre-loc
ked pixels? |
(...skipping 19 matching lines...) Expand all Loading... |
948 } | 919 } |
949 } | 920 } |
950 SkMD5::Digest digest; | 921 SkMD5::Digest digest; |
951 hash.finish(digest); | 922 hash.finish(digest); |
952 for (int i = 0; i < 16; i++) { | 923 for (int i = 0; i < 16; i++) { |
953 md5.appendf("%02x", digest.data[i]); | 924 md5.appendf("%02x", digest.data[i]); |
954 } | 925 } |
955 } | 926 } |
956 | 927 |
957 if (!FLAGS_readPath.isEmpty() && | 928 if (!FLAGS_readPath.isEmpty() && |
958 !gGold.contains(Gold(task.sink.tag.c_str(), task.src.tag.c_s
tr(), | 929 !gGold.contains(Gold(task.sink.tag, task.src.tag, |
959 task.src.options.c_str(), name, md5)))
{ | 930 task.src.options, name, md5))) { |
960 fail(SkStringPrintf("%s not found for %s %s %s %s in %s", | 931 fail(SkStringPrintf("%s not found for %s %s %s %s in %s", |
961 md5.c_str(), | 932 md5.c_str(), |
962 task.sink.tag.c_str(), | 933 task.sink.tag.c_str(), |
963 task.src.tag.c_str(), | 934 task.src.tag.c_str(), |
964 task.src.options.c_str(), | 935 task.src.options.c_str(), |
965 name.c_str(), | 936 name.c_str(), |
966 FLAGS_readPath[0])); | 937 FLAGS_readPath[0])); |
967 } | 938 } |
968 | 939 |
969 if (!FLAGS_writePath.isEmpty()) { | 940 if (!FLAGS_writePath.isEmpty()) { |
970 const char* ext = task.sink->fileExtension(); | 941 const char* ext = task.sink->fileExtension(); |
971 if (data->getLength()) { | 942 if (data->getLength()) { |
972 WriteToDisk(task, md5, ext, data, data->getLength(), nul
lptr); | 943 WriteToDisk(task, md5, ext, data, data->getLength(), nul
lptr); |
973 SkASSERT(bitmap.drawsNothing()); | 944 SkASSERT(bitmap.drawsNothing()); |
974 } else if (!bitmap.drawsNothing()) { | 945 } else if (!bitmap.drawsNothing()) { |
975 WriteToDisk(task, md5, ext, nullptr, 0, &bitmap); | 946 WriteToDisk(task, md5, ext, nullptr, 0, &bitmap); |
976 } | 947 } |
977 } | 948 } |
978 }); | 949 }); |
979 } | 950 } |
980 auto elapsed = now_ms() - timerStart; | 951 done(task.sink.tag.c_str(), task.src.tag.c_str(), task.src.options.c_str
(), name.c_str()); |
981 done(elapsed, task.sink.tag.c_str(), task.src.tag.c_str(), task.src.opti
ons.c_str(), | |
982 name, note, log); | |
983 } | 952 } |
984 | 953 |
985 static void WriteToDisk(const Task& task, | 954 static void WriteToDisk(const Task& task, |
986 SkString md5, | 955 SkString md5, |
987 const char* ext, | 956 const char* ext, |
988 SkStream* data, size_t len, | 957 SkStream* data, size_t len, |
989 const SkBitmap* bitmap) { | 958 const SkBitmap* bitmap) { |
990 JsonWriter::BitmapResult result; | 959 JsonWriter::BitmapResult result; |
991 result.name = task.src->name(); | 960 result.name = task.src->name(); |
992 result.config = task.sink.tag.c_str(); | 961 result.config = task.sink.tag; |
993 result.sourceType = task.src.tag; | 962 result.sourceType = task.src.tag; |
994 result.sourceOptions = task.src.options; | 963 result.sourceOptions = task.src.options; |
995 result.ext = ext; | 964 result.ext = ext; |
996 result.md5 = md5; | 965 result.md5 = md5; |
997 JsonWriter::AddBitmapResult(result); | 966 JsonWriter::AddBitmapResult(result); |
998 | 967 |
999 // If an MD5 is uninteresting, we want it noted in the JSON file, | 968 // If an MD5 is uninteresting, we want it noted in the JSON file, |
1000 // but don't want to dump it out as a .png (or whatever ext is). | 969 // but don't want to dump it out as a .png (or whatever ext is). |
1001 if (gUninterestingHashes.contains(md5)) { | 970 if (gUninterestingHashes.contains(md5)) { |
1002 return; | 971 return; |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1082 void reportFailed(const skiatest::Failure& failure) override { | 1051 void reportFailed(const skiatest::Failure& failure) override { |
1083 fail(failure.toString()); | 1052 fail(failure.toString()); |
1084 JsonWriter::AddTestFailure(failure); | 1053 JsonWriter::AddTestFailure(failure); |
1085 } | 1054 } |
1086 bool allowExtendedTest() const override { | 1055 bool allowExtendedTest() const override { |
1087 return FLAGS_pathOpsExtended; | 1056 return FLAGS_pathOpsExtended; |
1088 } | 1057 } |
1089 bool verbose() const override { return FLAGS_veryVerbose; } | 1058 bool verbose() const override { return FLAGS_veryVerbose; } |
1090 } reporter; | 1059 } reporter; |
1091 | 1060 |
1092 SkString note; | 1061 if (!FLAGS_dryRun && !is_blacklisted("_", "tests", "_", test.name)) { |
1093 SkString whyBlacklisted = is_blacklisted("_", "tests", "_", test.name); | |
1094 if (!whyBlacklisted.isEmpty()) { | |
1095 note.appendf(" (--blacklist %s)", whyBlacklisted.c_str()); | |
1096 } | |
1097 | |
1098 auto timerStart = now_ms(); | |
1099 if (!FLAGS_dryRun && whyBlacklisted.isEmpty()) { | |
1100 start("unit", "test", "", test.name); | 1062 start("unit", "test", "", test.name); |
1101 GrContextFactory factory; | 1063 GrContextFactory factory; |
1102 test.proc(&reporter, &factory); | 1064 test.proc(&reporter, &factory); |
1103 } | 1065 } |
1104 done(now_ms()-timerStart, "unit", "test", "", test.name, note, ""); | 1066 done("unit", "test", "", test.name); |
1105 } | 1067 } |
1106 | 1068 |
1107 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~*/ | 1069 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~*/ |
1108 | 1070 |
1109 DEFINE_int32(status_sec, 15, "Print status this often (and if we crash)."); | 1071 DEFINE_int32(status_sec, 15, "Print status this often (and if we crash)."); |
1110 | 1072 |
1111 SkThread* start_status_thread() { | 1073 SkThread* start_status_thread() { |
1112 auto thread = new SkThread([] (void*) { | 1074 auto thread = new SkThread([] (void*) { |
1113 for (;;) { | 1075 for (;;) { |
1114 print_status(); | 1076 print_status(); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1166 SkDebugf("%d srcs * %d sinks + %d tests == %d tasks", | 1128 SkDebugf("%d srcs * %d sinks + %d tests == %d tasks", |
1167 gSrcs.count(), gSinks.count(), gParallelTests.count() + gSerialTest
s.count(), gPending); | 1129 gSrcs.count(), gSinks.count(), gParallelTests.count() + gSerialTest
s.count(), gPending); |
1168 SkAutoTDelete<SkThread> statusThread(start_status_thread()); | 1130 SkAutoTDelete<SkThread> statusThread(start_status_thread()); |
1169 | 1131 |
1170 // Kick off as much parallel work as we can, making note of any serial work
we'll need to do. | 1132 // Kick off as much parallel work as we can, making note of any serial work
we'll need to do. |
1171 SkTaskGroup parallel; | 1133 SkTaskGroup parallel; |
1172 SkTArray<Task> serial; | 1134 SkTArray<Task> serial; |
1173 | 1135 |
1174 for (auto& sink : gSinks) | 1136 for (auto& sink : gSinks) |
1175 for (auto& src : gSrcs) { | 1137 for (auto& src : gSrcs) { |
| 1138 if (src->veto(sink->flags()) || |
| 1139 is_blacklisted(sink.tag.c_str(), src.tag.c_str(), |
| 1140 src.options.c_str(), src->name().c_str())) { |
| 1141 SkAutoTAcquire<SkPODSpinlock> lock(gMutex); |
| 1142 gPending--; |
| 1143 continue; |
| 1144 } |
| 1145 |
1176 Task task(src, sink); | 1146 Task task(src, sink); |
1177 if (src->serial() || sink->serial()) { | 1147 if (src->serial() || sink->serial()) { |
1178 serial.push_back(task); | 1148 serial.push_back(task); |
1179 } else { | 1149 } else { |
1180 parallel.add([task] { Task::Run(task); }); | 1150 parallel.add([task] { Task::Run(task); }); |
1181 } | 1151 } |
1182 } | 1152 } |
1183 for (auto test : gParallelTests) { | 1153 for (auto test : gParallelTests) { |
1184 parallel.add([test] { run_test(test); }); | 1154 parallel.add([test] { run_test(test); }); |
1185 } | 1155 } |
1186 | 1156 |
1187 // With the parallel work running, run serial tasks and tests here on main t
hread. | 1157 // With the parallel work running, run serial tasks and tests here on main t
hread. |
1188 for (auto task : serial) { Task::Run(task); } | 1158 for (auto task : serial) { Task::Run(task); } |
1189 for (auto test : gSerialTests) { run_test(test); } | 1159 for (auto test : gSerialTests) { run_test(test); } |
1190 | 1160 |
1191 // Wait for any remaining parallel work to complete (including any spun off
of serial tasks). | 1161 // Wait for any remaining parallel work to complete (including any spun off
of serial tasks). |
1192 parallel.wait(); | 1162 parallel.wait(); |
1193 gDefinitelyThreadSafeWork.wait(); | 1163 gDefinitelyThreadSafeWork.wait(); |
1194 | 1164 |
1195 // We'd better have run everything. | 1165 // We'd better have run everything. |
1196 SkASSERT(gPending == 0); | 1166 SkASSERT(gPending == 0); |
1197 | 1167 |
1198 // At this point we're back in single-threaded land. | 1168 // At this point we're back in single-threaded land. |
1199 sk_tool_utils::release_portable_typefaces(); | 1169 sk_tool_utils::release_portable_typefaces(); |
1200 | 1170 |
1201 if (FLAGS_verbose && gNoteTally.count() > 0) { | |
1202 SkDebugf("\nNote tally:\n"); | |
1203 gNoteTally.foreach([](const SkString& note, int* tally) { | |
1204 SkDebugf("%dx\t%s\n", *tally, note.c_str()); | |
1205 }); | |
1206 } | |
1207 | |
1208 SkDebugf("\n"); | |
1209 if (gFailures.count() > 0) { | 1171 if (gFailures.count() > 0) { |
1210 SkDebugf("Failures:\n"); | 1172 SkDebugf("Failures:\n"); |
1211 for (int i = 0; i < gFailures.count(); i++) { | 1173 for (int i = 0; i < gFailures.count(); i++) { |
1212 SkDebugf("\t%s\n", gFailures[i].c_str()); | 1174 SkDebugf("\t%s\n", gFailures[i].c_str()); |
1213 } | 1175 } |
1214 SkDebugf("%d failures\n", gFailures.count()); | 1176 SkDebugf("%d failures\n", gFailures.count()); |
1215 return 1; | 1177 return 1; |
1216 } | 1178 } |
1217 | 1179 |
1218 #ifdef SK_PDF_IMAGE_STATS | 1180 #ifdef SK_PDF_IMAGE_STATS |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1311 Reporter* reporter, | 1273 Reporter* reporter, |
1312 GrContextFactory* fac
tory); | 1274 GrContextFactory* fac
tory); |
1313 } // namespace skiatest | 1275 } // namespace skiatest |
1314 | 1276 |
1315 #if !defined(SK_BUILD_FOR_IOS) | 1277 #if !defined(SK_BUILD_FOR_IOS) |
1316 int main(int argc, char** argv) { | 1278 int main(int argc, char** argv) { |
1317 SkCommandLineFlags::Parse(argc, argv); | 1279 SkCommandLineFlags::Parse(argc, argv); |
1318 return dm_main(); | 1280 return dm_main(); |
1319 } | 1281 } |
1320 #endif | 1282 #endif |
OLD | NEW |