| 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 |