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.
7 Provides a minimal wrapping of the Blink image decoders
. Used to perform
8 a non
-threaded
, memory
-to
-memory image decode
using micro second accuracy
9 clocks to measure image decode time
. Optionally applies color correction
10 during image decoding on supported
platforms (default off
). Usage
:
12 % ninja
-C
/out
/Release image_decode_bench
&&
13 ./out
/Release
/image_decode_bench file
[iterations
]
15 FIXME
: Consider adding md5 checksum support to WTF
. Use it to compute the
16 decoded image frame md5
and output that value
.
18 FIXME
: Consider integrating
this tool in Chrome telemetry
for realz
, using
19 the image corpii used to assess Blink image decode performance
. Refer to
20 http
://crbug.com/398235#c103 and http://crbug.com/258324#c5
26 #include "platform/SharedBuffer.h"
27 #include "platform/image-decoders/ImageDecoder.h"
28 #include "public/platform/Platform.h"
29 #include "public/web/WebKit.h"
30 #include "wtf/OwnPtr.h"
31 #include "wtf/PassRefPtr.h"
34 #if defined(WIN32_LEAN_AND_MEAN)
35 #error Fix: WIN32_LEAN_AND_MEAN disables timeBeginPeriod/TimeEndPeriod.
40 #define stat(x,y) _stat(x,y)
41 typedef struct _stat sttype
;
45 typedef struct stat sttype
;
48 using namespace blink
;
52 // There is no real platform support herein, so adopt the WIN32 performance counter from
53 // WTF http://trac.webkit.org/browser/trunk/Source/WTF/wtf/CurrentTime.cpp?rev=152438
55 static double lowResUTCTime()
58 GetSystemTimeAsFileTime(&fileTime
);
60 // As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a
61 // ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can
62 // prevent alignment faults on 64-bit Windows).
63 ULARGE_INTEGER dateTime
;
64 memcpy(&dateTime
, &fileTime
, sizeof(dateTime
));
66 // Number of 100 nanosecond between January 1, 1601 and January 1, 1970.
67 static const ULONGLONG epochBias
= 116444736000000000ULL;
68 // Windows file times are in 100s of nanoseconds.
69 static const double hundredsOfNanosecondsPerMillisecond
= 10000;
70 return (dateTime
.QuadPart
- epochBias
) / hundredsOfNanosecondsPerMillisecond
;
73 static LARGE_INTEGER qpcFrequency
;
74 static bool syncedTime
;
76 static double highResUpTime()
78 // We use QPC, but only after sanity checking its result, due to bugs:
79 // http://support.microsoft.com/kb/274323 http://support.microsoft.com/kb/895980
80 // http://msdn.microsoft.com/en-us/library/ms644904.aspx ("you can get different results
81 // on different processors due to bugs in the basic input/output system (BIOS) or the
82 // hardware abstraction layer (HAL).").
84 static LARGE_INTEGER qpcLast
;
85 static DWORD tickCountLast
;
89 QueryPerformanceCounter(&qpc
);
90 DWORD tickCount
= GetTickCount();
93 __int64 qpcElapsed
= ((qpc
.QuadPart
- qpcLast
.QuadPart
) * 1000) / qpcFrequency
.QuadPart
;
94 __int64 tickCountElapsed
;
95 if (tickCount
>= tickCountLast
) {
96 tickCountElapsed
= (tickCount
- tickCountLast
);
98 __int64 tickCountLarge
= tickCount
+ 0x100000000I
64;
99 tickCountElapsed
= tickCountLarge
- tickCountLast
;
102 // Force a re-sync if QueryPerformanceCounter differs from GetTickCount() by more than
103 // 500ms. (The 500ms value is from http://support.microsoft.com/kb/274323).
104 __int64 diff
= tickCountElapsed
- qpcElapsed
;
105 if (diff
> 500 || diff
< -500)
112 tickCountLast
= tickCount
;
114 return (1000.0 * qpc
.QuadPart
) / static_cast<double>(qpcFrequency
.QuadPart
);
117 static bool qpcAvailable()
119 static bool available
;
125 available
= QueryPerformanceFrequency(&qpcFrequency
);
130 static double getCurrentTime()
132 // Use a combination of ftime and QueryPerformanceCounter.
133 // ftime returns the information we want, but doesn't have sufficient resolution.
134 // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals.
135 // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will
136 // use QueryPerformanceCounter by itself, adding the delta to the saved ftime.
137 // We periodically re-sync to correct for drift.
138 static double syncLowResUTCTime
;
139 static double syncHighResUpTime
;
140 static double lastUTCTime
;
142 double lowResTime
= lowResUTCTime();
144 return lowResTime
* (1.0 / 1000.0);
146 double highResTime
= highResUpTime();
148 timeBeginPeriod(1); // increase time resolution around low-res time getter
149 syncLowResUTCTime
= lowResTime
= lowResUTCTime();
150 timeEndPeriod(1); // restore time resolution
151 syncHighResUpTime
= highResTime
;
155 double highResElapsed
= highResTime
- syncHighResUpTime
;
156 double utc
= syncLowResUTCTime
+ highResElapsed
;
158 // Force a clock re-sync if we've drifted.
159 double lowResElapsed
= lowResTime
- syncLowResUTCTime
;
160 const double maximumAllowedDriftMsec
= 15.625 * 2.0; // 2x the typical low-res accuracy
161 if (fabs(highResElapsed
- lowResElapsed
) > maximumAllowedDriftMsec
)
164 // Make sure time doesn't run backwards (only correct if the difference is < 2 seconds,
165 // since DST or clock changes could occur).
166 const double backwardTimeLimit
= 2000.0;
167 if (utc
< lastUTCTime
&& (lastUTCTime
- utc
) < backwardTimeLimit
)
168 return lastUTCTime
* (1.0 / 1000.0);
171 return utc
* (1.0 / 1000.0);
176 static double getCurrentTime()
179 gettimeofday(&now
, 0);
180 return now
.tv_sec
+ now
.tv_usec
* (1.0 / 1000000.0);
185 void getScreenColorProfile(WebVector
<char>* profile
)
187 static unsigned char profileData
[] = {
188 0x00,0x00,0x01,0xea,0x54,0x45,0x53,0x54,0x00,0x00,0x00,0x00,
189 0x6d,0x6e,0x74,0x72,0x52,0x47,0x42,0x20,0x58,0x59,0x5a,0x20,
190 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
191 0x61,0x63,0x73,0x70,0x74,0x65,0x73,0x74,0x00,0x00,0x00,0x00,
192 0x74,0x65,0x73,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
193 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf6,0xd6,
194 0x00,0x01,0x00,0x00,0x00,0x00,0xd3,0x2d,0x74,0x65,0x73,0x74,
195 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
196 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
197 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
198 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,
199 0x63,0x70,0x72,0x74,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x0d,
200 0x64,0x65,0x73,0x63,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x8c,
201 0x77,0x74,0x70,0x74,0x00,0x00,0x01,0x8c,0x00,0x00,0x00,0x14,
202 0x72,0x58,0x59,0x5a,0x00,0x00,0x01,0xa0,0x00,0x00,0x00,0x14,
203 0x67,0x58,0x59,0x5a,0x00,0x00,0x01,0xb4,0x00,0x00,0x00,0x14,
204 0x62,0x58,0x59,0x5a,0x00,0x00,0x01,0xc8,0x00,0x00,0x00,0x14,
205 0x72,0x54,0x52,0x43,0x00,0x00,0x01,0xdc,0x00,0x00,0x00,0x0e,
206 0x67,0x54,0x52,0x43,0x00,0x00,0x01,0xdc,0x00,0x00,0x00,0x0e,
207 0x62,0x54,0x52,0x43,0x00,0x00,0x01,0xdc,0x00,0x00,0x00,0x0e,
208 0x74,0x65,0x78,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
209 0x00,0x00,0x00,0x00,0x64,0x65,0x73,0x63,0x00,0x00,0x00,0x00,
210 0x00,0x00,0x00,0x10,0x77,0x68,0x61,0x63,0x6b,0x65,0x64,0x2e,
211 0x69,0x63,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
212 0x00,0x00,0x00,0x11,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 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
217 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
218 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
219 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
220 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
221 0x58,0x59,0x5a,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0xf3,0x52,
222 0x00,0x01,0x00,0x00,0x00,0x01,0x16,0xcc,0x58,0x59,0x5a,0x20,
223 0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x8d,0x00,0x00,0xa0,0x2c,
224 0x00,0x00,0x0f,0x95,0x58,0x59,0x5a,0x20,0x00,0x00,0x00,0x00,
225 0x00,0x00,0x26,0x31,0x00,0x00,0x10,0x2f,0x00,0x00,0xbe,0x9b,
226 0x58,0x59,0x5a,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x18,
227 0x00,0x00,0x4f,0xa5,0x00,0x00,0x04,0xfc,0x63,0x75,0x72,0x76,
228 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x33
231 static struct WhackedColorProfile
{
233 char* data() { return reinterpret_cast<char*>(profileData
); }
235 const size_t profileSize
= 490u;
237 size_t size() { return profileSize
; }
241 profile
->assign(screenProfile
.data(), screenProfile
.size());
244 PassRefPtr
<SharedBuffer
> readFile(const char* fileName
)
246 FILE* fp
= fopen(fileName
, "rb");
248 fprintf(stderr
, "Can't open file %s\n", fileName
);
254 size_t fileSize
= s
.st_size
;
256 return SharedBuffer::create();
258 OwnPtr
<unsigned char[]> buffer
= adoptArrayPtr(new unsigned char[fileSize
]);
259 if (fileSize
!= fread(buffer
.get(), 1, fileSize
, fp
)) {
260 fprintf(stderr
, "Error reading file %s\n", fileName
);
265 return SharedBuffer::create(buffer
.get(), fileSize
);
268 bool decodeImageData(SharedBuffer
* data
, bool colorCorrection
, size_t packetSize
)
270 OwnPtr
<ImageDecoder
> decoder
= ImageDecoder::create(*data
,
271 ImageDecoder::AlphaPremultiplied
, colorCorrection
?
272 ImageDecoder::GammaAndColorProfileApplied
: ImageDecoder::GammaAndColorProfileIgnored
);
275 bool allDataReceived
= true;
276 decoder
->setData(data
, allDataReceived
);
278 int frameCount
= decoder
->frameCount();
279 for (int i
= 0; i
< frameCount
; ++i
) {
280 if (!decoder
->frameBufferAtIndex(i
))
284 return !decoder
->failed();
287 RefPtr
<SharedBuffer
> packetData
= SharedBuffer::create();
288 unsigned position
= 0;
291 unsigned length
= data
->getSomeData(packet
, position
);
293 length
= std::min(static_cast<size_t>(length
), packetSize
);
294 packetData
->append(packet
, length
);
297 bool allDataReceived
= position
== data
->size();
298 decoder
->setData(packetData
.get(), allDataReceived
);
300 int frameCount
= decoder
->frameCount();
301 for (int i
= 0; i
< frameCount
; ++i
) {
302 if (!decoder
->frameBufferAtIndex(i
))
306 if (allDataReceived
|| decoder
->failed())
310 return !decoder
->failed();
313 int main(int argc
, char* argv
[])
315 char* name
= argv
[0];
317 // If the platform supports color correction, allow it to be controlled.
319 bool applyColorCorrection
= false;
322 if (argc
>= 2 && strcmp(argv
[1], "--color-correct") == 0)
323 applyColorCorrection
= (--argc
, ++argv
, true);
326 fprintf(stderr
, "Usage: %s [--color-correct] file [iterations] [packetSize]\n", name
);
331 fprintf(stderr
, "Usage: %s file [iterations] [packetSize]\n", name
);
336 // Control decode bench iterations and packet size.
338 size_t iterations
= 1;
341 iterations
= strtol(argv
[2], &end
, 10);
342 if (*end
!= '\0' || !iterations
) {
343 fprintf(stderr
, "Second argument should be number of iterations. "
344 "The default is 1. You supplied %s\n", argv
[2]);
349 size_t packetSize
= 0;
352 packetSize
= strtol(argv
[3], &end
, 10);
354 fprintf(stderr
, "Third argument should be packet size. Default is "
355 "0, meaning to decode the entire image in one packet. You "
356 "supplied %s\n", argv
[3]);
361 // Create a web platform without V8.
363 class WebPlatform
: public blink::Platform
{
365 const unsigned char* getTraceCategoryEnabledFlag(const char*) override
367 return reinterpret_cast<const unsigned char *>("nope-none-nada");
370 void cryptographicallyRandomValues(unsigned char*, size_t) override
372 // Do nothing: make blink::Platform use the default crypto-randoms.
375 void screenColorProfile(WebVector
<char>* profile
) override
377 getScreenColorProfile(profile
); // Returns a whacked color profile.
381 blink::initializeWithoutV8(new WebPlatform());
383 // Set image decoding Platform options.
386 ImageDecoder::qcmsOutputDeviceProfile(); // Initialize screen colorProfile.
389 // Read entire file content to data.
391 RefPtr
<SharedBuffer
> data
= readFile(argv
[1]);
392 if (!data
.get() || !data
->size()) {
393 fprintf(stderr
, "Error reading image data from [%s]\n", argv
[1]);
397 // Consolidate the SharedBuffer data segments into one, contiguous block of memory.
400 // Image decode bench for iterations.
402 double totalTime
= 0.0;
404 for (size_t i
= 0; i
< iterations
; ++i
) {
405 double startTime
= getCurrentTime();
406 bool decoded
= decodeImageData(data
.get(), applyColorCorrection
, packetSize
);
407 double elapsedTime
= getCurrentTime() - startTime
;
408 totalTime
+= elapsedTime
;
410 fprintf(stderr
, "Image decode failed [%s]\n", argv
[1]);
415 // Results to stdout.
417 double averageTime
= totalTime
/ static_cast<double>(iterations
);
418 printf("%f %f\n", totalTime
, averageTime
);