Chromium Code Reviews| Index: Source/WebKit/chromium/src/ImageDecodeBench.cpp |
| diff --git a/Source/WebKit/chromium/src/ImageDecodeBench.cpp b/Source/WebKit/chromium/src/ImageDecodeBench.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ba9c8a0437bfcf622a0a2dce0cb3b89ff6f569c3 |
| --- /dev/null |
| +++ b/Source/WebKit/chromium/src/ImageDecodeBench.cpp |
| @@ -0,0 +1,266 @@ |
| +/* |
| + * Copyright (C) 2013 Google Inc. All rights reserved. |
| + * |
| + * Redistribution and use in source and binary forms, with or without |
| + * modification, are permitted provided that the following conditions are |
| + * met: |
| + * |
| + * * Redistributions of source code must retain the above copyright |
| + * notice, this list of conditions and the following disclaimer. |
| + * * Redistributions in binary form must reproduce the above |
| + * copyright notice, this list of conditions and the following disclaimer |
| + * in the documentation and/or other materials provided with the |
| + * distribution. |
| + * * Neither the name of Google Inc. nor the names of its |
| + * contributors may be used to endorse or promote products derived from |
| + * this software without specific prior written permission. |
| + * |
| + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| + */ |
| + |
| +// % ninja -C out/Release image_decode_bench |
|
Alpha Left Google
2013/07/10 18:51:07
There's no need to add comments about building it.
Noel Gordon
2013/07/11 03:09:00
removed - there is no build item for image_decode_
|
| + |
| +#include "config.h" |
| + |
| +#include "RuntimeEnabledFeatures.h" |
| +#include "core/platform/SharedBuffer.h" |
| +#include "core/platform/image-decoders/ImageDecoder.h" |
| +#include "public/web/WebKit.h" |
| +#include "wtf/OwnPtr.h" |
| +#include "wtf/PassOwnPtr.h" |
| + |
| +#if OS(WINDOWS) |
| +#include <mmsystem.h> |
| +#include <time.h> |
| +#else |
| +#include <sys/time.h> |
| +#endif |
| + |
| +using namespace std; |
|
Alpha Left Google
2013/07/10 18:51:07
You're not using <iostream> you can get rid of thi
Noel Gordon
2013/07/11 03:09:00
Done.
|
| +using namespace WebCore; |
| + |
| +#if OS(WINDOWS) |
| + |
| +// Adopt the performance counter from WTF:currentTime() since chromium's currentTime() is |
| +// not the high performance counter anymore, making it unsuitable for decode benchmarking. |
| +// http://trac.webkit.org/browser/trunk/Source/WTF/wtf/CurrentTime.cpp?rev=152438 |
|
jamesr
2013/07/10 19:20:33
nack, just use WTF::monotonicallyIncreasingTime().
Noel Gordon
2013/07/11 03:09:00
Ah if only we had it. There's no real platform su
|
| + |
| +static double lowResUTCTime() |
| +{ |
| + FILETIME fileTime; |
| + GetSystemTimeAsFileTime(&fileTime); |
| + |
| + // As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a |
| + // ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can |
| + // prevent alignment faults on 64-bit Windows). |
| + ULARGE_INTEGER dateTime; |
| + memcpy(&dateTime, &fileTime, sizeof(dateTime)); |
| + |
| + // Number of 100 nanosecond between January 1, 1601 and January 1, 1970. |
| + static const ULONGLONG epochBias = 116444736000000000ULL; |
| + // Windows file times are in 100s of nanoseconds. |
| + static const double hundredsOfNanosecondsPerMillisecond = 10000; |
| + return (dateTime.QuadPart - epochBias) / hundredsOfNanosecondsPerMillisecond; |
| +} |
| + |
| +static LARGE_INTEGER qpcFrequency; |
| +static bool syncedTime; |
| + |
| +static double highResUpTime() |
| +{ |
| + // We use QPC, but only after sanity checking its result, due to bugs: |
| + // http://support.microsoft.com/kb/274323 http://support.microsoft.com/kb/895980 |
| + // http://msdn.microsoft.com/en-us/library/ms644904.aspx ("you can get different results |
| + // on different processors due to bugs in the basic input/output system (BIOS) or the |
| + // hardware abstraction layer (HAL)."). |
| + |
| + static LARGE_INTEGER qpcLast; |
| + static DWORD tickCountLast; |
| + static bool inited; |
| + |
| + LARGE_INTEGER qpc; |
| + QueryPerformanceCounter(&qpc); |
| + DWORD tickCount = GetTickCount(); |
| + |
| + if (inited) { |
| + __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart; |
| + __int64 tickCountElapsed; |
| + if (tickCount >= tickCountLast) { |
| + tickCountElapsed = (tickCount - tickCountLast); |
| + } else { |
| + __int64 tickCountLarge = tickCount + 0x100000000I64; |
| + tickCountElapsed = tickCountLarge - tickCountLast; |
| + } |
| + |
| + // Force a re-sync if QueryPerformanceCounter differs from GetTickCount() by more than |
| + // 500ms. (The 500ms value is from http://support.microsoft.com/kb/274323). |
| + __int64 diff = tickCountElapsed - qpcElapsed; |
| + if (diff > 500 || diff < -500) |
| + syncedTime = false; |
| + } else { |
| + inited = true; |
| + } |
| + |
| + qpcLast = qpc; |
| + tickCountLast = tickCount; |
| + |
| + return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart); |
| +} |
| + |
| +static bool qpcAvailable() |
| +{ |
| + static bool available; |
| + static bool checked; |
| + |
| + if (checked) |
| + return available; |
| + |
| + available = QueryPerformanceFrequency(&qpcFrequency); |
| + checked = true; |
| + return available; |
| +} |
| + |
| +static double getCurrentTime() |
| +{ |
| + // Use a combination of ftime and QueryPerformanceCounter. |
| + // ftime returns the information we want, but doesn't have sufficient resolution. |
| + // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals. |
| + // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will |
| + // use QueryPerformanceCounter by itself, adding the delta to the saved ftime. |
| + // We periodically re-sync to correct for drift. |
| + static double syncLowResUTCTime; |
| + static double syncHighResUpTime; |
| + static double lastUTCTime; |
| + |
| + double lowResTime = lowResUTCTime(); |
| + if (!qpcAvailable()) |
| + return lowResTime / 1000.0; |
| + |
| + double highResTime = highResUpTime(); |
| + if (!syncedTime) { |
| + timeBeginPeriod(1); // increase time resolution around low-res time getter |
| + syncLowResUTCTime = lowResTime = lowResUTCTime(); |
| + timeEndPeriod(1); // restore time resolution |
| + syncHighResUpTime = highResTime; |
| + syncedTime = true; |
| + } |
| + |
| + double highResElapsed = highResTime - syncHighResUpTime; |
| + double utc = syncLowResUTCTime + highResElapsed; |
| + |
| + // Force a clock re-sync if we've drifted. |
| + double lowResElapsed = lowResTime - syncLowResUTCTime; |
| + const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy |
| + if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec) |
| + syncedTime = false; |
| + |
| + // Make sure time doesn't run backwards (only correct if the difference is < 2 seconds, |
| + // since DST or clock changes could occur). |
| + const double backwardTimeLimit = 2000.0; |
| + if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit) |
| + return lastUTCTime / 1000.0; |
| + lastUTCTime = utc; |
| + return utc / 1000.0; |
| +} |
| + |
| +#else |
| + |
| +static double getCurrentTime() |
| +{ |
| + struct timeval now; |
| + gettimeofday(&now, 0); |
| + return now.tv_sec + now.tv_usec / 1000000.0; |
| +} |
| + |
| +#endif |
| + |
| +static PassRefPtr<SharedBuffer> readFile(const char* fileName) |
| +{ |
| + FILE* fp = fopen(fileName, "rb"); |
| + if (!fp) { |
| + fprintf(stderr, "Can't open %s\n", fileName); |
| + exit(1); |
| + } |
| + |
| + fseek(fp, 0, SEEK_END); |
| + size_t fileSize = ftell(fp); |
| + rewind(fp); |
| + |
| + unsigned char* buffer = new unsigned char[fileSize]; |
|
Alpha Left Google
2013/07/10 18:51:07
delete [] buffer after use.
Noel Gordon
2013/07/11 03:09:00
used OwnArrayPtr.
|
| + fread(buffer, 1, fileSize, fp); |
| + fclose(fp); |
| + |
| + return SharedBuffer::create(buffer, fileSize); |
| +} |
| + |
| +static bool decodeImageData(SharedBuffer* data) |
| +{ |
| + OwnPtr<ImageDecoder> decoder = ImageDecoder::create(*data, |
| + ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileIgnored); |
| + decoder->setData(data, true); |
| + |
| + int frameCount = decoder->frameCount(); |
| + for (int i = 0; i < frameCount; ++i) { |
| + if (!decoder->frameBufferAtIndex(i)) |
| + break; |
| + } |
| + |
| + return !decoder->failed(); |
| +} |
| + |
| +int main(int argc, char* argv[]) |
| +{ |
| + if (argc < 2) { |
| + fprintf(stderr, "Usage: %s file [iterations]\n", argv[0]); |
| + exit(2); |
| + } |
| + |
| + size_t iterations = 1000; |
| + if (argc >= 3) { |
| + char* end = 0; |
| + iterations = strtol(argv[2], &end, 10); |
| + if (*end != '\0' || !iterations) { |
| + fprintf(stderr, "Second argument should be number of iterations. " |
| + "The default is 1000. You supplied %s\n", argv[2]); |
| + exit(2); |
| + } |
| + } |
| + |
| + class DummyWebKitPlatformSupport : public WebKit::Platform { |
|
Alpha Left Google
2013/07/10 18:51:07
Class definition like this looks kind of weird. I
Noel Gordon
2013/07/11 03:09:00
Me either, and the style presubmit is mute about i
|
| + public: |
| + const unsigned char* getTraceCategoryEnabledFlag(const char*) |
| + { return (const unsigned char *) "none-nada-нет"; } |
| + void cryptographicallyRandomValues(unsigned char*, size_t) { } |
| + }; |
| + |
| + WebKit::initializeWithoutV8(new DummyWebKitPlatformSupport()); |
| + WebCore::RuntimeEnabledFeatures::setAnimatedWebPEnabled(true); |
| + |
| + RefPtr<SharedBuffer> data = readFile(argv[1]); |
| + double totalTime = 0.0; |
| + |
| + for (size_t i = 0; i < iterations; ++i) { |
| + double startTime = getCurrentTime(); |
| + bool decoded = decodeImageData(data.get()); |
| + double elapsedTime = getCurrentTime() - startTime; |
| + totalTime += elapsedTime; |
| + if (!decoded) { |
| + fprintf(stderr, "Image decode failed.\n"); |
| + exit(3); |
| + } |
| + } |
| + |
| + double averageTime = totalTime / static_cast<double>(iterations); |
| + printf("%f %f\n", totalTime, averageTime); |
| + return 0; |
| +} |