| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // Provides a minimal wrapping of the Blink image decoders. Used to perform | |
| 6 // a non-threaded, memory-to-memory image decode using micro second accuracy | |
| 7 // clocks to measure image decode time. Optionally applies color correction | |
| 8 // during image decoding on supported platforms (default off). Usage: | |
| 9 // | |
| 10 // % ninja -C /out/Release image_decode_bench && | |
| 11 // ./out/Release/image_decode_bench file [iterations] | |
| 12 // | |
| 13 // TODO(noel): Consider adding md5 checksum support to WTF. Use it to compute | |
| 14 // the decoded image frame md5 and output that value. | |
| 15 // | |
| 16 // TODO(noel): Consider integrating this tool in Chrome telemetry for realz, | |
| 17 // using the image corpii used to assess Blink image decode performance. Refer | |
| 18 // to http://crbug.com/398235#c103 and http://crbug.com/258324#c5 | |
| 19 | |
| 20 #include "platform/SharedBuffer.h" | |
| 21 #include "platform/image-decoders/ImageDecoder.h" | |
| 22 #include "platform/testing/TestingPlatformSupport.h" | |
| 23 #include "public/platform/Platform.h" | |
| 24 #include "public/web/WebKit.h" | |
| 25 #include "wtf/OwnPtr.h" | |
| 26 #include "wtf/PassRefPtr.h" | |
| 27 | |
| 28 #if defined(_WIN32) | |
| 29 #if defined(WIN32_LEAN_AND_MEAN) | |
| 30 #error Fix: WIN32_LEAN_AND_MEAN disables timeBeginPeriod/TimeEndPeriod. | |
| 31 #endif | |
| 32 #include <mmsystem.h> | |
| 33 #include <sys/stat.h> | |
| 34 #include <time.h> | |
| 35 #define stat(x,y) _stat(x,y) | |
| 36 typedef struct _stat sttype; | |
| 37 #else | |
| 38 #include <sys/stat.h> | |
| 39 #include <sys/time.h> | |
| 40 typedef struct stat sttype; | |
| 41 #endif | |
| 42 | |
| 43 using namespace blink; | |
| 44 | |
| 45 #if defined(_WIN32) | |
| 46 | |
| 47 // There is no real platform support herein, so adopt the WIN32 performance coun
ter from | |
| 48 // WTF http://trac.webkit.org/browser/trunk/Source/WTF/wtf/CurrentTime.cpp?rev=1
52438 | |
| 49 | |
| 50 static double lowResUTCTime() | |
| 51 { | |
| 52 FILETIME fileTime; | |
| 53 GetSystemTimeAsFileTime(&fileTime); | |
| 54 | |
| 55 // As per Windows documentation for FILETIME, copy the resulting FILETIME st
ructure to a | |
| 56 // ULARGE_INTEGER structure using memcpy (using memcpy instead of direct ass
ignment can | |
| 57 // prevent alignment faults on 64-bit Windows). | |
| 58 ULARGE_INTEGER dateTime; | |
| 59 memcpy(&dateTime, &fileTime, sizeof(dateTime)); | |
| 60 | |
| 61 // Number of 100 nanosecond between January 1, 1601 and January 1, 1970. | |
| 62 static const ULONGLONG epochBias = 116444736000000000ULL; | |
| 63 // Windows file times are in 100s of nanoseconds. | |
| 64 static const double hundredsOfNanosecondsPerMillisecond = 10000; | |
| 65 return (dateTime.QuadPart - epochBias) / hundredsOfNanosecondsPerMillisecond
; | |
| 66 } | |
| 67 | |
| 68 static LARGE_INTEGER qpcFrequency; | |
| 69 static bool syncedTime; | |
| 70 | |
| 71 static double highResUpTime() | |
| 72 { | |
| 73 // We use QPC, but only after sanity checking its result, due to bugs: | |
| 74 // http://support.microsoft.com/kb/274323 http://support.microsoft.com/kb/89
5980 | |
| 75 // http://msdn.microsoft.com/en-us/library/ms644904.aspx ("you can get diffe
rent results | |
| 76 // on different processors due to bugs in the basic input/output system (BIO
S) or the | |
| 77 // hardware abstraction layer (HAL)."). | |
| 78 | |
| 79 static LARGE_INTEGER qpcLast; | |
| 80 static DWORD tickCountLast; | |
| 81 static bool inited; | |
| 82 | |
| 83 LARGE_INTEGER qpc; | |
| 84 QueryPerformanceCounter(&qpc); | |
| 85 DWORD tickCount = GetTickCount(); | |
| 86 | |
| 87 if (inited) { | |
| 88 __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFre
quency.QuadPart; | |
| 89 __int64 tickCountElapsed; | |
| 90 if (tickCount >= tickCountLast) { | |
| 91 tickCountElapsed = (tickCount - tickCountLast); | |
| 92 } else { | |
| 93 __int64 tickCountLarge = tickCount + 0x100000000I64; | |
| 94 tickCountElapsed = tickCountLarge - tickCountLast; | |
| 95 } | |
| 96 | |
| 97 // Force a re-sync if QueryPerformanceCounter differs from GetTickCount(
) by more than | |
| 98 // 500ms. (The 500ms value is from http://support.microsoft.com/kb/27432
3). | |
| 99 __int64 diff = tickCountElapsed - qpcElapsed; | |
| 100 if (diff > 500 || diff < -500) | |
| 101 syncedTime = false; | |
| 102 } else { | |
| 103 inited = true; | |
| 104 } | |
| 105 | |
| 106 qpcLast = qpc; | |
| 107 tickCountLast = tickCount; | |
| 108 | |
| 109 return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart); | |
| 110 } | |
| 111 | |
| 112 static bool qpcAvailable() | |
| 113 { | |
| 114 static bool available; | |
| 115 static bool checked; | |
| 116 | |
| 117 if (checked) | |
| 118 return available; | |
| 119 | |
| 120 available = QueryPerformanceFrequency(&qpcFrequency); | |
| 121 checked = true; | |
| 122 return available; | |
| 123 } | |
| 124 | |
| 125 static double getCurrentTime() | |
| 126 { | |
| 127 // Use a combination of ftime and QueryPerformanceCounter. | |
| 128 // ftime returns the information we want, but doesn't have sufficient resolu
tion. | |
| 129 // QueryPerformanceCounter has high resolution, but is only usable to measur
e time intervals. | |
| 130 // To combine them, we call ftime and QueryPerformanceCounter initially. Lat
er calls will | |
| 131 // use QueryPerformanceCounter by itself, adding the delta to the saved ftim
e. | |
| 132 // We periodically re-sync to correct for drift. | |
| 133 static double syncLowResUTCTime; | |
| 134 static double syncHighResUpTime; | |
| 135 static double lastUTCTime; | |
| 136 | |
| 137 double lowResTime = lowResUTCTime(); | |
| 138 if (!qpcAvailable()) | |
| 139 return lowResTime * (1.0 / 1000.0); | |
| 140 | |
| 141 double highResTime = highResUpTime(); | |
| 142 if (!syncedTime) { | |
| 143 timeBeginPeriod(1); // increase time resolution around low-res time gett
er | |
| 144 syncLowResUTCTime = lowResTime = lowResUTCTime(); | |
| 145 timeEndPeriod(1); // restore time resolution | |
| 146 syncHighResUpTime = highResTime; | |
| 147 syncedTime = true; | |
| 148 } | |
| 149 | |
| 150 double highResElapsed = highResTime - syncHighResUpTime; | |
| 151 double utc = syncLowResUTCTime + highResElapsed; | |
| 152 | |
| 153 // Force a clock re-sync if we've drifted. | |
| 154 double lowResElapsed = lowResTime - syncLowResUTCTime; | |
| 155 const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-r
es accuracy | |
| 156 if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec) | |
| 157 syncedTime = false; | |
| 158 | |
| 159 // Make sure time doesn't run backwards (only correct if the difference is <
2 seconds, | |
| 160 // since DST or clock changes could occur). | |
| 161 const double backwardTimeLimit = 2000.0; | |
| 162 if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit) | |
| 163 return lastUTCTime * (1.0 / 1000.0); | |
| 164 | |
| 165 lastUTCTime = utc; | |
| 166 return utc * (1.0 / 1000.0); | |
| 167 } | |
| 168 | |
| 169 #else | |
| 170 | |
| 171 static double getCurrentTime() | |
| 172 { | |
| 173 struct timeval now; | |
| 174 gettimeofday(&now, 0); | |
| 175 return now.tv_sec + now.tv_usec * (1.0 / 1000000.0); | |
| 176 } | |
| 177 | |
| 178 #endif | |
| 179 | |
| 180 void getScreenColorProfile(WebVector<char>* profile) | |
| 181 { | |
| 182 static unsigned char profileData[] = { | |
| 183 0x00,0x00,0x01,0xea,0x54,0x45,0x53,0x54,0x00,0x00,0x00,0x00, | |
| 184 0x6d,0x6e,0x74,0x72,0x52,0x47,0x42,0x20,0x58,0x59,0x5a,0x20, | |
| 185 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 186 0x61,0x63,0x73,0x70,0x74,0x65,0x73,0x74,0x00,0x00,0x00,0x00, | |
| 187 0x74,0x65,0x73,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 188 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf6,0xd6, | |
| 189 0x00,0x01,0x00,0x00,0x00,0x00,0xd3,0x2d,0x74,0x65,0x73,0x74, | |
| 190 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 191 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 192 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 193 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09, | |
| 194 0x63,0x70,0x72,0x74,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x0d, | |
| 195 0x64,0x65,0x73,0x63,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x8c, | |
| 196 0x77,0x74,0x70,0x74,0x00,0x00,0x01,0x8c,0x00,0x00,0x00,0x14, | |
| 197 0x72,0x58,0x59,0x5a,0x00,0x00,0x01,0xa0,0x00,0x00,0x00,0x14, | |
| 198 0x67,0x58,0x59,0x5a,0x00,0x00,0x01,0xb4,0x00,0x00,0x00,0x14, | |
| 199 0x62,0x58,0x59,0x5a,0x00,0x00,0x01,0xc8,0x00,0x00,0x00,0x14, | |
| 200 0x72,0x54,0x52,0x43,0x00,0x00,0x01,0xdc,0x00,0x00,0x00,0x0e, | |
| 201 0x67,0x54,0x52,0x43,0x00,0x00,0x01,0xdc,0x00,0x00,0x00,0x0e, | |
| 202 0x62,0x54,0x52,0x43,0x00,0x00,0x01,0xdc,0x00,0x00,0x00,0x0e, | |
| 203 0x74,0x65,0x78,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 204 0x00,0x00,0x00,0x00,0x64,0x65,0x73,0x63,0x00,0x00,0x00,0x00, | |
| 205 0x00,0x00,0x00,0x10,0x77,0x68,0x61,0x63,0x6b,0x65,0x64,0x2e, | |
| 206 0x69,0x63,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 207 0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 208 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 209 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 210 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 211 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 212 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 213 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 214 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 215 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
| 216 0x58,0x59,0x5a,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0xf3,0x52, | |
| 217 0x00,0x01,0x00,0x00,0x00,0x01,0x16,0xcc,0x58,0x59,0x5a,0x20, | |
| 218 0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x8d,0x00,0x00,0xa0,0x2c, | |
| 219 0x00,0x00,0x0f,0x95,0x58,0x59,0x5a,0x20,0x00,0x00,0x00,0x00, | |
| 220 0x00,0x00,0x26,0x31,0x00,0x00,0x10,0x2f,0x00,0x00,0xbe,0x9b, | |
| 221 0x58,0x59,0x5a,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x18, | |
| 222 0x00,0x00,0x4f,0xa5,0x00,0x00,0x04,0xfc,0x63,0x75,0x72,0x76, | |
| 223 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x33 | |
| 224 }; | |
| 225 | |
| 226 static struct WhackedColorProfile { | |
| 227 | |
| 228 char* data() { return reinterpret_cast<char*>(profileData); } | |
| 229 | |
| 230 const size_t profileSize = 490u; | |
| 231 | |
| 232 size_t size() { return profileSize; } | |
| 233 | |
| 234 } screenProfile; | |
| 235 | |
| 236 profile->assign(screenProfile.data(), screenProfile.size()); | |
| 237 } | |
| 238 | |
| 239 PassRefPtr<SharedBuffer> readFile(const char* fileName) | |
| 240 { | |
| 241 FILE* fp = fopen(fileName, "rb"); | |
| 242 if (!fp) { | |
| 243 fprintf(stderr, "Can't open file %s\n", fileName); | |
| 244 exit(2); | |
| 245 } | |
| 246 | |
| 247 sttype s; | |
| 248 stat(fileName, &s); | |
| 249 size_t fileSize = s.st_size; | |
| 250 if (s.st_size <= 0) | |
| 251 return SharedBuffer::create(); | |
| 252 | |
| 253 OwnPtr<unsigned char[]> buffer = adoptArrayPtr(new unsigned char[fileSize]); | |
| 254 if (fileSize != fread(buffer.get(), 1, fileSize, fp)) { | |
| 255 fprintf(stderr, "Error reading file %s\n", fileName); | |
| 256 exit(2); | |
| 257 } | |
| 258 | |
| 259 fclose(fp); | |
| 260 return SharedBuffer::create(buffer.get(), fileSize); | |
| 261 } | |
| 262 | |
| 263 bool decodeImageData(SharedBuffer* data, bool colorCorrection, size_t packetSize
) | |
| 264 { | |
| 265 OwnPtr<ImageDecoder> decoder = ImageDecoder::create(*data, | |
| 266 ImageDecoder::AlphaPremultiplied, colorCorrection ? | |
| 267 ImageDecoder::GammaAndColorProfileApplied : ImageDecoder::GammaAndCo
lorProfileIgnored); | |
| 268 | |
| 269 if (!packetSize) { | |
| 270 bool allDataReceived = true; | |
| 271 decoder->setData(data, allDataReceived); | |
| 272 | |
| 273 int frameCount = decoder->frameCount(); | |
| 274 for (int i = 0; i < frameCount; ++i) { | |
| 275 if (!decoder->frameBufferAtIndex(i)) | |
| 276 return false; | |
| 277 } | |
| 278 | |
| 279 return !decoder->failed(); | |
| 280 } | |
| 281 | |
| 282 RefPtr<SharedBuffer> packetData = SharedBuffer::create(); | |
| 283 unsigned position = 0; | |
| 284 while (true) { | |
| 285 const char* packet; | |
| 286 unsigned length = data->getSomeData(packet, position); | |
| 287 | |
| 288 length = std::min(static_cast<size_t>(length), packetSize); | |
| 289 packetData->append(packet, length); | |
| 290 position += length; | |
| 291 | |
| 292 bool allDataReceived = position == data->size(); | |
| 293 decoder->setData(packetData.get(), allDataReceived); | |
| 294 | |
| 295 int frameCount = decoder->frameCount(); | |
| 296 for (int i = 0; i < frameCount; ++i) { | |
| 297 if (!decoder->frameBufferAtIndex(i)) | |
| 298 break; | |
| 299 } | |
| 300 | |
| 301 if (allDataReceived || decoder->failed()) | |
| 302 break; | |
| 303 } | |
| 304 | |
| 305 return !decoder->failed(); | |
| 306 } | |
| 307 | |
| 308 int main(int argc, char* argv[]) | |
| 309 { | |
| 310 char* name = argv[0]; | |
| 311 | |
| 312 // If the platform supports color correction, allow it to be controlled. | |
| 313 | |
| 314 bool applyColorCorrection = false; | |
| 315 | |
| 316 #if USE(QCMSLIB) | |
| 317 if (argc >= 2 && strcmp(argv[1], "--color-correct") == 0) | |
| 318 applyColorCorrection = (--argc, ++argv, true); | |
| 319 | |
| 320 if (argc < 2) { | |
| 321 fprintf(stderr, "Usage: %s [--color-correct] file [iterations] [packetSi
ze]\n", name); | |
| 322 exit(1); | |
| 323 } | |
| 324 #else | |
| 325 if (argc < 2) { | |
| 326 fprintf(stderr, "Usage: %s file [iterations] [packetSize]\n", name); | |
| 327 exit(1); | |
| 328 } | |
| 329 #endif | |
| 330 | |
| 331 // Control decode bench iterations and packet size. | |
| 332 | |
| 333 size_t iterations = 1; | |
| 334 if (argc >= 3) { | |
| 335 char* end = 0; | |
| 336 iterations = strtol(argv[2], &end, 10); | |
| 337 if (*end != '\0' || !iterations) { | |
| 338 fprintf(stderr, "Second argument should be number of iterations. " | |
| 339 "The default is 1. You supplied %s\n", argv[2]); | |
| 340 exit(1); | |
| 341 } | |
| 342 } | |
| 343 | |
| 344 size_t packetSize = 0; | |
| 345 if (argc >= 4) { | |
| 346 char* end = 0; | |
| 347 packetSize = strtol(argv[3], &end, 10); | |
| 348 if (*end != '\0') { | |
| 349 fprintf(stderr, "Third argument should be packet size. Default is " | |
| 350 "0, meaning to decode the entire image in one packet. You " | |
| 351 "supplied %s\n", argv[3]); | |
| 352 exit(1); | |
| 353 } | |
| 354 } | |
| 355 | |
| 356 // Create a web platform without V8. | |
| 357 | |
| 358 class WebPlatform : public TestingPlatformSupport { | |
| 359 public: | |
| 360 void screenColorProfile(WebVector<char>* profile) override | |
| 361 { | |
| 362 getScreenColorProfile(profile); // Returns a whacked color profile. | |
| 363 } | |
| 364 }; | |
| 365 | |
| 366 Platform::initialize(new WebPlatform()); | |
| 367 | |
| 368 // Set image decoding Platform options. | |
| 369 | |
| 370 #if USE(QCMSLIB) | |
| 371 ImageDecoder::qcmsOutputDeviceProfile(); // Initialize screen colorProfile. | |
| 372 #endif | |
| 373 | |
| 374 // Read entire file content to data. | |
| 375 | |
| 376 RefPtr<SharedBuffer> data = readFile(argv[1]); | |
| 377 if (!data.get() || !data->size()) { | |
| 378 fprintf(stderr, "Error reading image data from [%s]\n", argv[1]); | |
| 379 exit(2); | |
| 380 } | |
| 381 | |
| 382 // Consolidate the SharedBuffer data segments into one, contiguous block of
memory. | |
| 383 data->data(); | |
| 384 | |
| 385 // Image decode bench for iterations. | |
| 386 | |
| 387 double totalTime = 0.0; | |
| 388 | |
| 389 for (size_t i = 0; i < iterations; ++i) { | |
| 390 double startTime = getCurrentTime(); | |
| 391 bool decoded = decodeImageData(data.get(), applyColorCorrection, packetS
ize); | |
| 392 double elapsedTime = getCurrentTime() - startTime; | |
| 393 totalTime += elapsedTime; | |
| 394 if (!decoded) { | |
| 395 fprintf(stderr, "Image decode failed [%s]\n", argv[1]); | |
| 396 exit(3); | |
| 397 } | |
| 398 } | |
| 399 | |
| 400 // Results to stdout. | |
| 401 | |
| 402 double averageTime = totalTime / static_cast<double>(iterations); | |
| 403 printf("%f %f\n", totalTime, averageTime); | |
| 404 return 0; | |
| 405 } | |
| OLD | NEW |