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" |
11 #include "DMSrcSinkAndroid.h" | 11 #include "DMSrcSinkAndroid.h" |
12 #include "OverwriteLine.h" | |
13 #include "ProcStats.h" | 12 #include "ProcStats.h" |
14 #include "SkBBHFactory.h" | 13 #include "SkBBHFactory.h" |
15 #include "SkChecksum.h" | 14 #include "SkChecksum.h" |
16 #include "SkCodec.h" | 15 #include "SkCodec.h" |
17 #include "SkCommonFlags.h" | 16 #include "SkCommonFlags.h" |
18 #include "SkCommonFlagsConfig.h" | 17 #include "SkCommonFlagsConfig.h" |
19 #include "SkFontMgr.h" | 18 #include "SkFontMgr.h" |
20 #include "SkForceLinking.h" | 19 #include "SkForceLinking.h" |
21 #include "SkGraphics.h" | 20 #include "SkGraphics.h" |
22 #include "SkMD5.h" | 21 #include "SkMD5.h" |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 | 74 |
76 SK_DECLARE_STATIC_MUTEX(gFailuresMutex); | 75 SK_DECLARE_STATIC_MUTEX(gFailuresMutex); |
77 static SkTArray<SkString> gFailures; | 76 static SkTArray<SkString> gFailures; |
78 | 77 |
79 static void fail(ImplicitString err) { | 78 static void fail(ImplicitString err) { |
80 SkAutoMutexAcquire lock(gFailuresMutex); | 79 SkAutoMutexAcquire lock(gFailuresMutex); |
81 SkDebugf("\n\nFAILURE: %s\n\n", err.c_str()); | 80 SkDebugf("\n\nFAILURE: %s\n\n", err.c_str()); |
82 gFailures.push_back(err); | 81 gFailures.push_back(err); |
83 } | 82 } |
84 | 83 |
85 static int32_t gPending = 0; // Atomic. Total number of running and queued tas
ks. | |
86 | 84 |
87 // We use a spinlock to make locking this in a signal handler _somewhat_ safe. | 85 // We use a spinlock to make locking this in a signal handler _somewhat_ safe. |
88 SK_DECLARE_STATIC_SPINLOCK(gRunningAndTallyMutex); | 86 SK_DECLARE_STATIC_SPINLOCK(gMutex); |
| 87 static int32_t gPending; |
89 static SkTArray<SkString> gRunning; | 88 static SkTArray<SkString> gRunning; |
90 static SkTHashMap<SkString, int> gNoteTally; | 89 static SkTHashMap<SkString, int> gNoteTally; |
91 | 90 |
92 static void done(double ms, | 91 static void done(double ms, |
93 ImplicitString config, ImplicitString src, ImplicitString srcOp
tions, | 92 ImplicitString config, ImplicitString src, ImplicitString srcOp
tions, |
94 ImplicitString name, ImplicitString note, ImplicitString log) { | 93 ImplicitString name, ImplicitString note, ImplicitString log) { |
95 SkString id = SkStringPrintf("%s %s %s %s", config.c_str(), src.c_str(), | 94 SkString id = SkStringPrintf("%s %s %s %s", config.c_str(), src.c_str(), |
96 srcOptions.c_str(), name.c_str()
); | 95 srcOptions.c_str(), name.c_str()
); |
| 96 int pending; |
97 { | 97 { |
98 SkAutoTAcquire<SkPODSpinlock> lock(gRunningAndTallyMutex); | 98 SkAutoTAcquire<SkPODSpinlock> lock(gMutex); |
99 for (int i = 0; i < gRunning.count(); i++) { | 99 for (int i = 0; i < gRunning.count(); i++) { |
100 if (gRunning[i] == id) { | 100 if (gRunning[i] == id) { |
101 gRunning.removeShuffle(i); | 101 gRunning.removeShuffle(i); |
102 break; | 102 break; |
103 } | 103 } |
104 } | 104 } |
105 if (!note.isEmpty()) { | 105 if (!note.isEmpty()) { |
106 if (int* tally = gNoteTally.find(note)) { | 106 if (int* tally = gNoteTally.find(note)) { |
107 *tally += 1; | 107 *tally += 1; |
108 } else { | 108 } else { |
109 gNoteTally.set(note, 1); | 109 gNoteTally.set(note, 1); |
110 } | 110 } |
111 } | 111 } |
112 } | 112 pending = --gPending; |
113 if (!log.isEmpty()) { | |
114 log.prepend("\n"); | |
115 } | |
116 auto pending = sk_atomic_dec(&gPending)-1; | |
117 if (!FLAGS_quiet && note.isEmpty()) { | |
118 SkDebugf("%s(%4d/%-4dMB %6d) %s\t%s%s", FLAGS_verbose ? "\n" : kSkOverwr
iteLine | |
119 , sk_tools::getCurrResidentSetSizeMB(
) | |
120 , sk_tools::getMaxResidentSetSizeMB() | |
121 , pending | |
122 , HumanizeMs(ms).c_str() | |
123 , id.c_str() | |
124 , log.c_str()); | |
125 } | 113 } |
126 // We write our dm.json file every once in a while in case we crash. | 114 // We write our dm.json file every once in a while in case we crash. |
127 // Notice this also handles the final dm.json when pending == 0. | 115 // Notice this also handles the final dm.json when pending == 0. |
128 if (pending % 500 == 0) { | 116 if (pending % 500 == 0) { |
129 JsonWriter::DumpJson(); | 117 JsonWriter::DumpJson(); |
130 } | 118 } |
131 } | 119 } |
132 | 120 |
133 static void start(ImplicitString config, ImplicitString src, | 121 static void start(ImplicitString config, ImplicitString src, |
134 ImplicitString srcOptions, ImplicitString name) { | 122 ImplicitString srcOptions, ImplicitString name) { |
135 SkString id = SkStringPrintf("%s %s %s %s", config.c_str(), src.c_str(), | 123 SkString id = SkStringPrintf("%s %s %s %s", config.c_str(), src.c_str(), |
136 srcOptions.c_str(), name.c_str()
); | 124 srcOptions.c_str(), name.c_str()
); |
137 SkAutoTAcquire<SkPODSpinlock> lock(gRunningAndTallyMutex); | 125 SkAutoTAcquire<SkPODSpinlock> lock(gMutex); |
138 gRunning.push_back(id); | 126 gRunning.push_back(id); |
139 } | 127 } |
140 | 128 |
| 129 static void print_status() { |
| 130 static SkMSec start_ms = SkTime::GetMSecs(); |
| 131 |
| 132 int curr = sk_tools::getCurrResidentSetSizeMB(), |
| 133 peak = sk_tools::getMaxResidentSetSizeMB(); |
| 134 SkString elapsed = HumanizeMs(SkTime::GetMSecs() - start_ms); |
| 135 |
| 136 SkAutoTAcquire<SkPODSpinlock> lock(gMutex); |
| 137 SkDebugf("\n%s elapsed, %d active, %d queued, %dMB RAM, %dMB peak\n", |
| 138 elapsed.c_str(), gRunning.count(), gPending - gRunning.count(), cur
r, peak); |
| 139 for (auto& task : gRunning) { |
| 140 SkDebugf("\t%s\n", task.c_str()); |
| 141 } |
| 142 } |
| 143 |
141 #if defined(SK_BUILD_FOR_WIN32) | 144 #if defined(SK_BUILD_FOR_WIN32) |
142 static void setup_crash_handler() { | 145 static void setup_crash_handler() { |
143 // TODO: custom crash handler like below to print out what was running | 146 // TODO: custom crash handler like below to print out what was running |
144 SetupCrashHandler(); | 147 SetupCrashHandler(); |
145 } | 148 } |
146 | 149 |
147 #else | 150 #else |
148 #include <signal.h> | 151 #include <signal.h> |
149 static void setup_crash_handler() { | 152 static void setup_crash_handler() { |
150 const int kSignals[] = { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV }; | 153 const int kSignals[] = { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV }; |
151 for (int sig : kSignals) { | 154 for (int sig : kSignals) { |
152 signal(sig, [](int sig) { | 155 signal(sig, [](int sig) { |
153 SkAutoTAcquire<SkPODSpinlock> lock(gRunningAndTallyMutex); | 156 SkDebugf("\nCaught signal %d [%s].\n", sig, strsignal(sig)); |
154 SkDebugf("\nCaught signal %d [%s] while running %d tasks:\n", | 157 print_status(); |
155 sig, strsignal(sig), gRunning.count()); | |
156 for (auto& task : gRunning) { | |
157 SkDebugf("\t%s\n", task.c_str()); | |
158 } | |
159 }); | 158 }); |
160 } | 159 } |
161 } | 160 } |
162 #endif | 161 #endif |
163 | 162 |
164 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~*/ | 163 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~*/ |
165 | 164 |
166 struct Gold : public SkString { | 165 struct Gold : public SkString { |
167 Gold() : SkString("") {} | 166 Gold() : SkString("") {} |
168 Gold(ImplicitString sink, ImplicitString src, ImplicitString srcOptions, | 167 Gold(ImplicitString sink, ImplicitString src, ImplicitString srcOptions, |
(...skipping 725 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
894 task.src.options.c_str(), name.
c_str()); | 893 task.src.options.c_str(), name.
c_str()); |
895 if (!whyBlacklisted.isEmpty()) { | 894 if (!whyBlacklisted.isEmpty()) { |
896 note.appendf(" (--blacklist %s)", whyBlacklisted.c_str()); | 895 note.appendf(" (--blacklist %s)", whyBlacklisted.c_str()); |
897 } | 896 } |
898 | 897 |
899 SkString log; | 898 SkString log; |
900 auto timerStart = now_ms(); | 899 auto timerStart = now_ms(); |
901 if (!FLAGS_dryRun && note.isEmpty()) { | 900 if (!FLAGS_dryRun && note.isEmpty()) { |
902 SkBitmap bitmap; | 901 SkBitmap bitmap; |
903 SkDynamicMemoryWStream stream; | 902 SkDynamicMemoryWStream stream; |
904 if (FLAGS_pre_log) { | |
905 SkDebugf("\nRunning %s->%s", name.c_str(), task.sink.tag.c_str()
); | |
906 } | |
907 start(task.sink.tag.c_str(), task.src.tag, task.src.options, name.c_
str()); | 903 start(task.sink.tag.c_str(), task.src.tag, task.src.options, name.c_
str()); |
908 Error err = task.sink->draw(*task.src, &bitmap, &stream, &log); | 904 Error err = task.sink->draw(*task.src, &bitmap, &stream, &log); |
909 if (!err.isEmpty()) { | 905 if (!err.isEmpty()) { |
910 if (err.isFatal()) { | 906 if (err.isFatal()) { |
911 fail(SkStringPrintf("%s %s %s %s: %s", | 907 fail(SkStringPrintf("%s %s %s %s: %s", |
912 task.sink.tag.c_str(), | 908 task.sink.tag.c_str(), |
913 task.src.tag.c_str(), | 909 task.src.tag.c_str(), |
914 task.src.options.c_str(), | 910 task.src.options.c_str(), |
915 name.c_str(), | 911 name.c_str(), |
916 err.c_str())); | 912 err.c_str())); |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1095 SkString note; | 1091 SkString note; |
1096 SkString whyBlacklisted = is_blacklisted("_", "tests", "_", test.name); | 1092 SkString whyBlacklisted = is_blacklisted("_", "tests", "_", test.name); |
1097 if (!whyBlacklisted.isEmpty()) { | 1093 if (!whyBlacklisted.isEmpty()) { |
1098 note.appendf(" (--blacklist %s)", whyBlacklisted.c_str()); | 1094 note.appendf(" (--blacklist %s)", whyBlacklisted.c_str()); |
1099 } | 1095 } |
1100 | 1096 |
1101 auto timerStart = now_ms(); | 1097 auto timerStart = now_ms(); |
1102 if (!FLAGS_dryRun && whyBlacklisted.isEmpty()) { | 1098 if (!FLAGS_dryRun && whyBlacklisted.isEmpty()) { |
1103 start("unit", "test", "", test.name); | 1099 start("unit", "test", "", test.name); |
1104 GrContextFactory factory; | 1100 GrContextFactory factory; |
1105 if (FLAGS_pre_log) { | |
1106 SkDebugf("\nRunning test %s", test.name); | |
1107 } | |
1108 test.proc(&reporter, &factory); | 1101 test.proc(&reporter, &factory); |
1109 } | 1102 } |
1110 done(now_ms()-timerStart, "unit", "test", "", test.name, note, ""); | 1103 done(now_ms()-timerStart, "unit", "test", "", test.name, note, ""); |
1111 } | 1104 } |
1112 | 1105 |
1113 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~*/ | 1106 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~*/ |
1114 | 1107 |
1115 // Some runs (mostly, Valgrind) are so slow that the bot framework thinks we've
hung. | 1108 DEFINE_int32(status_sec, 15, "Print status this often (and if we crash)."); |
1116 // This prints something every once in a while so that it knows we're still work
ing. | 1109 |
1117 static void start_keepalive() { | 1110 SkThread* start_status_thread() { |
1118 struct Loop { | 1111 auto thread = new SkThread([] (void*) { |
1119 static void forever(void*) { | 1112 for (;;) { |
1120 for (;;) { | 1113 print_status(); |
1121 static const int kSec = 300; | 1114 #if defined(SK_BUILD_FOR_WIN) |
1122 #if defined(SK_BUILD_FOR_WIN) | 1115 Sleep(FLAGS_status_sec * 1000); |
1123 Sleep(kSec * 1000); | 1116 #else |
1124 #else | 1117 sleep(FLAGS_status_sec); |
1125 sleep(kSec); | 1118 #endif |
1126 #endif | |
1127 SkString running; | |
1128 { | |
1129 SkAutoTAcquire<SkPODSpinlock> lock(gRunningAndTallyMutex); | |
1130 for (int i = 0; i < gRunning.count(); i++) { | |
1131 running.appendf("\n\t%s", gRunning[i].c_str()); | |
1132 } | |
1133 } | |
1134 SkDebugf("\nCurrently running:%s\n", running.c_str()); | |
1135 } | |
1136 } | 1119 } |
1137 }; | 1120 }); |
1138 static SkThread* intentionallyLeaked = new SkThread(Loop::forever); | 1121 thread->start(); |
1139 intentionallyLeaked->start(); | 1122 return thread; |
1140 } | 1123 } |
1141 | 1124 |
1142 #define PORTABLE_FONT_PREFIX "Toy Liberation " | 1125 #define PORTABLE_FONT_PREFIX "Toy Liberation " |
1143 | 1126 |
1144 static SkTypeface* create_from_name(const char familyName[], SkTypeface::Style s
tyle) { | 1127 static SkTypeface* create_from_name(const char familyName[], SkTypeface::Style s
tyle) { |
1145 if (familyName && strlen(familyName) > sizeof(PORTABLE_FONT_PREFIX) | 1128 if (familyName && strlen(familyName) > sizeof(PORTABLE_FONT_PREFIX) |
1146 && !strncmp(familyName, PORTABLE_FONT_PREFIX, sizeof(PORTABLE_FONT_P
REFIX) - 1)) { | 1129 && !strncmp(familyName, PORTABLE_FONT_PREFIX, sizeof(PORTABLE_FONT_P
REFIX) - 1)) { |
1147 return sk_tool_utils::create_portable_typeface(familyName, style); | 1130 return sk_tool_utils::create_portable_typeface(familyName, style); |
1148 } | 1131 } |
1149 return nullptr; | 1132 return nullptr; |
1150 } | 1133 } |
1151 | 1134 |
1152 #undef PORTABLE_FONT_PREFIX | 1135 #undef PORTABLE_FONT_PREFIX |
1153 | 1136 |
1154 extern SkTypeface* (*gCreateTypefaceDelegate)(const char [], SkTypeface::Style )
; | 1137 extern SkTypeface* (*gCreateTypefaceDelegate)(const char [], SkTypeface::Style )
; |
1155 | 1138 |
1156 int dm_main(); | 1139 int dm_main(); |
1157 int dm_main() { | 1140 int dm_main() { |
1158 setup_crash_handler(); | 1141 setup_crash_handler(); |
| 1142 |
1159 JsonWriter::DumpJson(); // It's handy for the bots to assume this is ~never
missing. | 1143 JsonWriter::DumpJson(); // It's handy for the bots to assume this is ~never
missing. |
1160 SkAutoGraphics ag; | 1144 SkAutoGraphics ag; |
1161 SkTaskGroup::Enabler enabled(FLAGS_threads); | 1145 SkTaskGroup::Enabler enabled(FLAGS_threads); |
1162 gCreateTypefaceDelegate = &create_from_name; | 1146 gCreateTypefaceDelegate = &create_from_name; |
1163 | 1147 |
1164 start_keepalive(); | |
1165 | |
1166 gather_gold(); | 1148 gather_gold(); |
1167 gather_uninteresting_hashes(); | 1149 gather_uninteresting_hashes(); |
1168 | 1150 |
1169 if (!gather_srcs()) { | 1151 if (!gather_srcs()) { |
1170 return 1; | 1152 return 1; |
1171 } | 1153 } |
1172 gather_sinks(); | 1154 gather_sinks(); |
1173 gather_tests(); | 1155 gather_tests(); |
1174 | 1156 |
1175 gPending = gSrcs.count() * gSinks.count() + gParallelTests.count() + gSerial
Tests.count(); | 1157 gPending = gSrcs.count() * gSinks.count() + gParallelTests.count() + gSerial
Tests.count(); |
1176 SkDebugf("%d srcs * %d sinks + %d tests == %d tasks\n", | 1158 SkDebugf("%d srcs * %d sinks + %d tests == %d tasks", |
1177 gSrcs.count(), gSinks.count(), gParallelTests.count() + gSerialTest
s.count(), gPending); | 1159 gSrcs.count(), gSinks.count(), gParallelTests.count() + gSerialTest
s.count(), gPending); |
| 1160 SkAutoTDelete<SkThread> statusThread(start_status_thread()); |
1178 | 1161 |
1179 // Kick off as much parallel work as we can, making note of any serial work
we'll need to do. | 1162 // Kick off as much parallel work as we can, making note of any serial work
we'll need to do. |
1180 SkTaskGroup parallel; | 1163 SkTaskGroup parallel; |
1181 SkTArray<Task> serial; | 1164 SkTArray<Task> serial; |
1182 | 1165 |
1183 for (auto& sink : gSinks) | 1166 for (auto& sink : gSinks) |
1184 for (auto& src : gSrcs) { | 1167 for (auto& src : gSrcs) { |
1185 Task task(src, sink); | 1168 Task task(src, sink); |
1186 if (src->serial() || sink->serial()) { | 1169 if (src->serial() || sink->serial()) { |
1187 serial.push_back(task); | 1170 serial.push_back(task); |
(...skipping 25 matching lines...) Expand all Loading... |
1213 | 1196 |
1214 SkDebugf("\n"); | 1197 SkDebugf("\n"); |
1215 if (gFailures.count() > 0) { | 1198 if (gFailures.count() > 0) { |
1216 SkDebugf("Failures:\n"); | 1199 SkDebugf("Failures:\n"); |
1217 for (int i = 0; i < gFailures.count(); i++) { | 1200 for (int i = 0; i < gFailures.count(); i++) { |
1218 SkDebugf("\t%s\n", gFailures[i].c_str()); | 1201 SkDebugf("\t%s\n", gFailures[i].c_str()); |
1219 } | 1202 } |
1220 SkDebugf("%d failures\n", gFailures.count()); | 1203 SkDebugf("%d failures\n", gFailures.count()); |
1221 return 1; | 1204 return 1; |
1222 } | 1205 } |
1223 if (gPending > 0) { | 1206 |
1224 SkDebugf("Hrm, we didn't seem to run everything we intended to! Please
file a bug.\n"); | 1207 #ifdef SK_PDF_IMAGE_STATS |
1225 return 1; | |
1226 } | |
1227 #ifdef SK_PDF_IMAGE_STATS | |
1228 SkPDFImageDumpStats(); | 1208 SkPDFImageDumpStats(); |
1229 #endif // SK_PDF_IMAGE_STATS | 1209 #endif // SK_PDF_IMAGE_STATS |
| 1210 |
| 1211 print_status(); |
1230 SkDebugf("Finished!\n"); | 1212 SkDebugf("Finished!\n"); |
1231 return 0; | 1213 return 0; |
1232 } | 1214 } |
1233 | 1215 |
1234 // TODO: currently many GPU tests are declared outside SK_SUPPORT_GPU guards. | 1216 // TODO: currently many GPU tests are declared outside SK_SUPPORT_GPU guards. |
1235 // Thus we export the empty RunWithGPUTestContexts when SK_SUPPORT_GPU=0. | 1217 // Thus we export the empty RunWithGPUTestContexts when SK_SUPPORT_GPU=0. |
1236 namespace skiatest { | 1218 namespace skiatest { |
1237 namespace { | 1219 namespace { |
1238 typedef void(*TestWithGrContext)(skiatest::Reporter*, GrContext*); | 1220 typedef void(*TestWithGrContext)(skiatest::Reporter*, GrContext*); |
1239 typedef void(*TestWithGrContextAndGLContext)(skiatest::Reporter*, GrContext*, Sk
GLContext*); | 1221 typedef void(*TestWithGrContextAndGLContext)(skiatest::Reporter*, GrContext*, Sk
GLContext*); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1318 Reporter* reporter, | 1300 Reporter* reporter, |
1319 GrContextFactory* fac
tory); | 1301 GrContextFactory* fac
tory); |
1320 } // namespace skiatest | 1302 } // namespace skiatest |
1321 | 1303 |
1322 #if !defined(SK_BUILD_FOR_IOS) | 1304 #if !defined(SK_BUILD_FOR_IOS) |
1323 int main(int argc, char** argv) { | 1305 int main(int argc, char** argv) { |
1324 SkCommandLineFlags::Parse(argc, argv); | 1306 SkCommandLineFlags::Parse(argc, argv); |
1325 return dm_main(); | 1307 return dm_main(); |
1326 } | 1308 } |
1327 #endif | 1309 #endif |
OLD | NEW |