Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(758)

Side by Side Diff: dm/DM.cpp

Issue 1675423002: dm: simplify parallel/serial decisions (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | dm/DMSrcSink.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 565 matching lines...) Expand 10 before | Expand all | Expand 10 after
576 } 576 }
577 } 577 }
578 578
579 SkTArray<SkString> images; 579 SkTArray<SkString> images;
580 if (!CollectImages(&images)) { 580 if (!CollectImages(&images)) {
581 return false; 581 return false;
582 } 582 }
583 583
584 for (auto image : images) { 584 for (auto image : images) {
585 push_codec_srcs(image); 585 push_codec_srcs(image);
586 const char* ext = ""; 586 const char* ext = strrchr(image.c_str(), '.');
587 int index = image.findLastOf('.'); 587 if (ext && brd_supported(ext+1)) {
588 if (index >= 0 && (size_t) ++index < image.size()) {
589 ext = &image.c_str()[index];
590 }
591 if (brd_supported(ext)) {
592 push_brd_srcs(image); 588 push_brd_srcs(image);
593 } 589 }
594 } 590 }
595 591
596 return true; 592 return true;
597 } 593 }
598 594
599 static void push_sink(const SkCommandLineConfig& config, Sink* s) { 595 static void push_sink(const SkCommandLineConfig& config, Sink* s) {
600 SkAutoTDelete<Sink> sink(s); 596 SkAutoTDelete<Sink> sink(s);
601 597
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
835 // .png encoding are definitely thread safe. This lets us offload that work to CPU threads. 831 // .png encoding are definitely thread safe. This lets us offload that work to CPU threads.
836 static SkTaskGroup gDefinitelyThreadSafeWork; 832 static SkTaskGroup gDefinitelyThreadSafeWork;
837 833
838 // The finest-grained unit of work we can run: draw a single Src into a single S ink, 834 // The finest-grained unit of work we can run: draw a single Src into a single S ink,
839 // report any errors, and perhaps write out the output: a .png of the bitmap, or a raw stream. 835 // report any errors, and perhaps write out the output: a .png of the bitmap, or a raw stream.
840 struct Task { 836 struct Task {
841 Task(const TaggedSrc& src, const TaggedSink& sink) : src(src), sink(sink) {} 837 Task(const TaggedSrc& src, const TaggedSink& sink) : src(src), sink(sink) {}
842 const TaggedSrc& src; 838 const TaggedSrc& src;
843 const TaggedSink& sink; 839 const TaggedSink& sink;
844 840
845 static void Run(Task* task) { 841 static void Run(const Task& task) {
846 SkString name = task->src->name(); 842 SkString name = task.src->name();
847 843
848 // We'll skip drawing this Src/Sink pair if: 844 // We'll skip drawing this Src/Sink pair if:
849 // - the Src vetoes the Sink; 845 // - the Src vetoes the Sink;
850 // - this Src / Sink combination is on the blacklist; 846 // - this Src / Sink combination is on the blacklist;
851 // - it's a dry run. 847 // - it's a dry run.
852 SkString note(task->src->veto(task->sink->flags()) ? " (veto)" : ""); 848 SkString note(task.src->veto(task.sink->flags()) ? " (veto)" : "");
853 SkString whyBlacklisted = is_blacklisted(task->sink.tag.c_str(), task->s rc.tag.c_str(), 849 SkString whyBlacklisted = is_blacklisted(task.sink.tag.c_str(), task.src .tag.c_str(),
854 task->src.options.c_str(), name .c_str()); 850 task.src.options.c_str(), name. c_str());
855 if (!whyBlacklisted.isEmpty()) { 851 if (!whyBlacklisted.isEmpty()) {
856 note.appendf(" (--blacklist %s)", whyBlacklisted.c_str()); 852 note.appendf(" (--blacklist %s)", whyBlacklisted.c_str());
857 } 853 }
858 854
859 SkString log; 855 SkString log;
860 auto timerStart = now_ms(); 856 auto timerStart = now_ms();
861 if (!FLAGS_dryRun && note.isEmpty()) { 857 if (!FLAGS_dryRun && note.isEmpty()) {
862 SkBitmap bitmap; 858 SkBitmap bitmap;
863 SkDynamicMemoryWStream stream; 859 SkDynamicMemoryWStream stream;
864 if (FLAGS_pre_log) { 860 if (FLAGS_pre_log) {
865 SkDebugf("\nRunning %s->%s", name.c_str(), task->sink.tag.c_str( )); 861 SkDebugf("\nRunning %s->%s", name.c_str(), task.sink.tag.c_str() );
866 } 862 }
867 start(task->sink.tag.c_str(), task->src.tag, task->src.options, name .c_str()); 863 start(task.sink.tag.c_str(), task.src.tag, task.src.options, name.c_ str());
868 Error err = task->sink->draw(*task->src, &bitmap, &stream, &log); 864 Error err = task.sink->draw(*task.src, &bitmap, &stream, &log);
869 if (!err.isEmpty()) { 865 if (!err.isEmpty()) {
870 if (err.isFatal()) { 866 if (err.isFatal()) {
871 fail(SkStringPrintf("%s %s %s %s: %s", 867 fail(SkStringPrintf("%s %s %s %s: %s",
872 task->sink.tag.c_str(), 868 task.sink.tag.c_str(),
873 task->src.tag.c_str(), 869 task.src.tag.c_str(),
874 task->src.options.c_str(), 870 task.src.options.c_str(),
875 name.c_str(), 871 name.c_str(),
876 err.c_str())); 872 err.c_str()));
877 } else { 873 } else {
878 note.appendf(" (skipped: %s)", err.c_str()); 874 note.appendf(" (skipped: %s)", err.c_str());
879 auto elapsed = now_ms() - timerStart; 875 auto elapsed = now_ms() - timerStart;
880 done(elapsed, task->sink.tag.c_str(), task->src.tag, task->s rc.options, 876 done(elapsed, task.sink.tag.c_str(), task.src.tag, task.src. options,
881 name, note, log); 877 name, note, log);
882 return; 878 return;
883 } 879 }
884 } 880 }
885 881
886 // We're likely switching threads here, so we must capture by value, [=] or [foo,bar]. 882 // We're likely switching threads here, so we must capture by value, [=] or [foo,bar].
887 SkStreamAsset* data = stream.detachAsStream(); 883 SkStreamAsset* data = stream.detachAsStream();
888 gDefinitelyThreadSafeWork.add([task,name,bitmap,data]{ 884 gDefinitelyThreadSafeWork.add([task,name,bitmap,data]{
889 SkAutoTDelete<SkStreamAsset> ownedData(data); 885 SkAutoTDelete<SkStreamAsset> ownedData(data);
890 886
(...skipping 20 matching lines...) Expand all
911 } 907 }
912 } 908 }
913 SkMD5::Digest digest; 909 SkMD5::Digest digest;
914 hash.finish(digest); 910 hash.finish(digest);
915 for (int i = 0; i < 16; i++) { 911 for (int i = 0; i < 16; i++) {
916 md5.appendf("%02x", digest.data[i]); 912 md5.appendf("%02x", digest.data[i]);
917 } 913 }
918 } 914 }
919 915
920 if (!FLAGS_readPath.isEmpty() && 916 if (!FLAGS_readPath.isEmpty() &&
921 !gGold.contains(Gold(task->sink.tag.c_str(), task->src.tag.c _str(), 917 !gGold.contains(Gold(task.sink.tag.c_str(), task.src.tag.c_s tr(),
922 task->src.options.c_str(), name, md5))) { 918 task.src.options.c_str(), name, md5))) {
923 fail(SkStringPrintf("%s not found for %s %s %s %s in %s", 919 fail(SkStringPrintf("%s not found for %s %s %s %s in %s",
924 md5.c_str(), 920 md5.c_str(),
925 task->sink.tag.c_str(), 921 task.sink.tag.c_str(),
926 task->src.tag.c_str(), 922 task.src.tag.c_str(),
927 task->src.options.c_str(), 923 task.src.options.c_str(),
928 name.c_str(), 924 name.c_str(),
929 FLAGS_readPath[0])); 925 FLAGS_readPath[0]));
930 } 926 }
931 927
932 if (!FLAGS_writePath.isEmpty()) { 928 if (!FLAGS_writePath.isEmpty()) {
933 const char* ext = task->sink->fileExtension(); 929 const char* ext = task.sink->fileExtension();
934 if (data->getLength()) { 930 if (data->getLength()) {
935 WriteToDisk(*task, md5, ext, data, data->getLength(), nu llptr); 931 WriteToDisk(task, md5, ext, data, data->getLength(), nul lptr);
936 SkASSERT(bitmap.drawsNothing()); 932 SkASSERT(bitmap.drawsNothing());
937 } else if (!bitmap.drawsNothing()) { 933 } else if (!bitmap.drawsNothing()) {
938 WriteToDisk(*task, md5, ext, nullptr, 0, &bitmap); 934 WriteToDisk(task, md5, ext, nullptr, 0, &bitmap);
939 } 935 }
940 } 936 }
941 }); 937 });
942 } 938 }
943 auto elapsed = now_ms() - timerStart; 939 auto elapsed = now_ms() - timerStart;
944 done(elapsed, task->sink.tag.c_str(), task->src.tag.c_str(), task->src.o ptions.c_str(), 940 done(elapsed, task.sink.tag.c_str(), task.src.tag.c_str(), task.src.opti ons.c_str(),
945 name, note, log); 941 name, note, log);
946 } 942 }
947 943
948 static void WriteToDisk(const Task& task, 944 static void WriteToDisk(const Task& task,
949 SkString md5, 945 SkString md5,
950 const char* ext, 946 const char* ext,
951 SkStream* data, size_t len, 947 SkStream* data, size_t len,
952 const SkBitmap* bitmap) { 948 const SkBitmap* bitmap) {
953 JsonWriter::BitmapResult result; 949 JsonWriter::BitmapResult result;
954 result.name = task.src->name(); 950 result.name = task.src->name();
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
1005 return; 1001 return;
1006 } 1002 }
1007 if (!file.writeStream(data, len)) { 1003 if (!file.writeStream(data, len)) {
1008 fail(SkStringPrintf("Can't write to %s.\n", path.c_str())); 1004 fail(SkStringPrintf("Can't write to %s.\n", path.c_str()));
1009 return; 1005 return;
1010 } 1006 }
1011 } 1007 }
1012 } 1008 }
1013 }; 1009 };
1014 1010
1015 // Run all tasks in the same enclave serially on the same thread.
1016 // They can't possibly run concurrently with each other.
1017 static void run_enclave(SkTArray<Task>* tasks) {
1018 for (int i = 0; i < tasks->count(); i++) {
1019 Task::Run(tasks->begin() + i);
1020 }
1021 }
1022
1023 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~*/ 1011 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~*/
1024 1012
1025 // Unit tests don't fit so well into the Src/Sink model, so we give them special treatment. 1013 // Unit tests don't fit so well into the Src/Sink model, so we give them special treatment.
1026 1014
1027 static SkTDArray<skiatest::Test> gThreadedTests, gGPUTests; 1015 static SkTDArray<skiatest::Test> gParallelTests, gSerialTests;
1028 1016
1029 static void gather_tests() { 1017 static void gather_tests() {
1030 if (!FLAGS_src.contains("tests")) { 1018 if (!FLAGS_src.contains("tests")) {
1031 return; 1019 return;
1032 } 1020 }
1033 for (const skiatest::TestRegistry* r = skiatest::TestRegistry::Head(); r; r = r->next()) { 1021 for (const skiatest::TestRegistry* r = skiatest::TestRegistry::Head(); r; r = r->next()) {
1034 if (!in_shard()) { 1022 if (!in_shard()) {
1035 continue; 1023 continue;
1036 } 1024 }
1037 // Despite its name, factory() is returning a reference to 1025 // Despite its name, factory() is returning a reference to
1038 // link-time static const POD data. 1026 // link-time static const POD data.
1039 const skiatest::Test& test = r->factory(); 1027 const skiatest::Test& test = r->factory();
1040 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, test.name)) { 1028 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, test.name)) {
1041 continue; 1029 continue;
1042 } 1030 }
1043 if (test.needsGpu && gpu_supported()) { 1031 if (test.needsGpu && gpu_supported()) {
1044 (FLAGS_gpu_threading ? gThreadedTests : gGPUTests).push(test); 1032 (FLAGS_gpu_threading ? gParallelTests : gSerialTests).push(test);
1045 } else if (!test.needsGpu && FLAGS_cpu) { 1033 } else if (!test.needsGpu && FLAGS_cpu) {
1046 gThreadedTests.push(test); 1034 gParallelTests.push(test);
1047 } 1035 }
1048 } 1036 }
1049 } 1037 }
1050 1038
1051 static void run_test(skiatest::Test* test) { 1039 static void run_test(skiatest::Test test) {
1052 struct : public skiatest::Reporter { 1040 struct : public skiatest::Reporter {
1053 void reportFailed(const skiatest::Failure& failure) override { 1041 void reportFailed(const skiatest::Failure& failure) override {
1054 fail(failure.toString()); 1042 fail(failure.toString());
1055 JsonWriter::AddTestFailure(failure); 1043 JsonWriter::AddTestFailure(failure);
1056 } 1044 }
1057 bool allowExtendedTest() const override { 1045 bool allowExtendedTest() const override {
1058 return FLAGS_pathOpsExtended; 1046 return FLAGS_pathOpsExtended;
1059 } 1047 }
1060 bool verbose() const override { return FLAGS_veryVerbose; } 1048 bool verbose() const override { return FLAGS_veryVerbose; }
1061 } reporter; 1049 } reporter;
1062 1050
1063 SkString note; 1051 SkString note;
1064 SkString whyBlacklisted = is_blacklisted("_", "tests", "_", test->name); 1052 SkString whyBlacklisted = is_blacklisted("_", "tests", "_", test.name);
1065 if (!whyBlacklisted.isEmpty()) { 1053 if (!whyBlacklisted.isEmpty()) {
1066 note.appendf(" (--blacklist %s)", whyBlacklisted.c_str()); 1054 note.appendf(" (--blacklist %s)", whyBlacklisted.c_str());
1067 } 1055 }
1068 1056
1069 auto timerStart = now_ms(); 1057 auto timerStart = now_ms();
1070 if (!FLAGS_dryRun && whyBlacklisted.isEmpty()) { 1058 if (!FLAGS_dryRun && whyBlacklisted.isEmpty()) {
1071 start("unit", "test", "", test->name); 1059 start("unit", "test", "", test.name);
1072 GrContextFactory factory; 1060 GrContextFactory factory;
1073 if (FLAGS_pre_log) { 1061 if (FLAGS_pre_log) {
1074 SkDebugf("\nRunning test %s", test->name); 1062 SkDebugf("\nRunning test %s", test.name);
1075 } 1063 }
1076 test->proc(&reporter, &factory); 1064 test.proc(&reporter, &factory);
1077 } 1065 }
1078 done(now_ms()-timerStart, "unit", "test", "", test->name, note, ""); 1066 done(now_ms()-timerStart, "unit", "test", "", test.name, note, "");
1079 } 1067 }
1080 1068
1081 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~*/ 1069 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~*/
1082 1070
1083 // If we're isolating all GPU-bound work to one thread (the default), this funct ion runs all that.
1084 static void run_enclave_and_gpu_tests(SkTArray<Task>* tasks) {
1085 run_enclave(tasks);
1086 for (int i = 0; i < gGPUTests.count(); i++) {
1087 run_test(&gGPUTests[i]);
1088 }
1089 }
1090
1091 // Some runs (mostly, Valgrind) are so slow that the bot framework thinks we've hung. 1071 // Some runs (mostly, Valgrind) are so slow that the bot framework thinks we've hung.
1092 // This prints something every once in a while so that it knows we're still work ing. 1072 // This prints something every once in a while so that it knows we're still work ing.
1093 static void start_keepalive() { 1073 static void start_keepalive() {
1094 struct Loop { 1074 struct Loop {
1095 static void forever(void*) { 1075 static void forever(void*) {
1096 for (;;) { 1076 for (;;) {
1097 static const int kSec = 300; 1077 static const int kSec = 300;
1098 #if defined(SK_BUILD_FOR_WIN) 1078 #if defined(SK_BUILD_FOR_WIN)
1099 Sleep(kSec * 1000); 1079 Sleep(kSec * 1000);
1100 #else 1080 #else
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1141 1121
1142 gather_gold(); 1122 gather_gold();
1143 gather_uninteresting_hashes(); 1123 gather_uninteresting_hashes();
1144 1124
1145 if (!gather_srcs()) { 1125 if (!gather_srcs()) {
1146 return 1; 1126 return 1;
1147 } 1127 }
1148 gather_sinks(); 1128 gather_sinks();
1149 gather_tests(); 1129 gather_tests();
1150 1130
1151 gPending = gSrcs.count() * gSinks.count() + gThreadedTests.count() + gGPUTes ts.count(); 1131 gPending = gSrcs.count() * gSinks.count() + gParallelTests.count() + gSerial Tests.count();
1152 SkDebugf("%d srcs * %d sinks + %d tests == %d tasks\n", 1132 SkDebugf("%d srcs * %d sinks + %d tests == %d tasks\n",
1153 gSrcs.count(), gSinks.count(), gThreadedTests.count() + gGPUTests.c ount(), gPending); 1133 gSrcs.count(), gSinks.count(), gParallelTests.count() + gSerialTest s.count(), gPending);
1154 1134
1155 // We try to exploit as much parallelism as is safe. Most Src/Sink pairs ru n on any thread, 1135 // Kick off as much parallel work as we can, making note of any serial work we'll need to do.
1156 // but Sinks that identify as part of a particular enclave run serially on a single thread. 1136 SkTaskGroup parallel;
1157 // CPU tests run on any thread. GPU tests depend on --gpu_threading. 1137 SkTArray<Task> serial;
1158 SkTArray<Task> enclaves[kNumEnclaves]; 1138
1159 for (int j = 0; j < gSinks.count(); j++) { 1139 for (auto& sink : gSinks)
1160 SkTArray<Task>& tasks = enclaves[gSinks[j]->enclave()]; 1140 for (auto& src : gSrcs) {
1161 for (int i = 0; i < gSrcs.count(); i++) { 1141 Task task(src, sink);
1162 tasks.push_back(Task(gSrcs[i], gSinks[j])); 1142 if (src->serial() || sink->serial()) {
1143 serial.push_back(task);
1144 } else {
1145 parallel.add([task] { Task::Run(task); });
1163 } 1146 }
1164 } 1147 }
1148 for (auto test : gParallelTests) {
1149 parallel.add([test] { run_test(test); });
1150 }
1165 1151
1166 SkTaskGroup tg; 1152 // With the parallel work running, run serial tasks and tests here on main t hread.
1167 tg.batch(gThreadedTests.count(), [](int i){ run_test(&gThreadedTests[i]); }) ; 1153 for (auto task : serial) { Task::Run(task); }
1168 for (int i = 0; i < kNumEnclaves; i++) { 1154 for (auto test : gSerialTests) { run_test(test); }
1169 SkTArray<Task>* currentEnclave = &enclaves[i]; 1155
1170 switch(i) { 1156 // Wait for any remaining parallel work to complete (including any spun off of serial tasks).
1171 case kAnyThread_Enclave: 1157 parallel.wait();
1172 tg.batch(currentEnclave->count(),
1173 [currentEnclave](int j) { Task::Run(&(*currentEnclave)[ j]); });
1174 break;
1175 case kGPU_Enclave:
1176 tg.add([currentEnclave](){ run_enclave_and_gpu_tests(currentEncl ave); });
1177 break;
1178 default:
1179 tg.add([currentEnclave](){ run_enclave(currentEnclave); });
1180 break;
1181 }
1182 }
1183 tg.wait();
1184 gDefinitelyThreadSafeWork.wait(); 1158 gDefinitelyThreadSafeWork.wait();
1185 1159
1186 // At this point we're back in single-threaded land. 1160 // At this point we're back in single-threaded land.
1187 sk_tool_utils::release_portable_typefaces(); 1161 sk_tool_utils::release_portable_typefaces();
1188 1162
1189 if (FLAGS_verbose && gNoteTally.count() > 0) { 1163 if (FLAGS_verbose && gNoteTally.count() > 0) {
1190 SkDebugf("\nNote tally:\n"); 1164 SkDebugf("\nNote tally:\n");
1191 gNoteTally.foreach([](const SkString& note, int* tally) { 1165 gNoteTally.foreach([](const SkString& note, int* tally) {
1192 SkDebugf("%dx\t%s\n", *tally, note.c_str()); 1166 SkDebugf("%dx\t%s\n", *tally, note.c_str());
1193 }); 1167 });
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
1300 Reporter* reporter, 1274 Reporter* reporter,
1301 GrContextFactory* fac tory); 1275 GrContextFactory* fac tory);
1302 } // namespace skiatest 1276 } // namespace skiatest
1303 1277
1304 #if !defined(SK_BUILD_FOR_IOS) 1278 #if !defined(SK_BUILD_FOR_IOS)
1305 int main(int argc, char** argv) { 1279 int main(int argc, char** argv) {
1306 SkCommandLineFlags::Parse(argc, argv); 1280 SkCommandLineFlags::Parse(argc, argv);
1307 return dm_main(); 1281 return dm_main();
1308 } 1282 }
1309 #endif 1283 #endif
OLDNEW
« no previous file with comments | « no previous file | dm/DMSrcSink.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698