Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: third_party/WebKit/Source/platform/testing/DeferredImageDecodeBench.cpp

Issue 2918443003: Remove redundant reading and writing of data about SharedBuffer.
Patch Set: benchmark Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/platform/image-decoders/SegmentReader.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 deferred image decoders. Used to
6 // perform a non-threaded/non-threaded, memory-to-memory image decode using
7 // micro second accuracy clocks to measure image decode time. Optionally applies
8 // color correction during image decoding on supported platforms (default off).
9 // Usage:
10 //
11 // % ninja -C out/Release deferred_image_decode_bench &&
12 // ./out/Release/deferred_image_decode_bench file [iterations]
13 //
14 // TODO(noel): Consider adding md5 checksum support to WTF. Use it to compute
15 // the decoded image frame md5 and output that value.
16 //
17 // TODO(noel): Consider integrating this tool in Chrome telemetry for realz,
18 // using the image corpii used to assess Blink image decode performance. Refer
19 // to http://crbug.com/398235#c103 and http://crbug.com/258324#c5
20
21 #include <memory>
22 #include <thread>
23
24 #include "base/command_line.h"
25 #include "base/test/test_discardable_memory_allocator.h"
26 #include "platform/SharedBuffer.h"
27 #include "platform/graphics/DeferredImageDecoder.h"
28 #include "platform/image-decoders/ImageDecoder.h"
29 #include "platform/wtf/PassRefPtr.h"
30 #include "platform/wtf/PtrUtil.h"
31 #include "platform/wtf/WTF.h"
32 #include "platform/wtf/allocator/Partitions.h"
33 #include "public/platform/Platform.h"
34 #include "third_party/skia/include/core/SkBitmap.h"
35 #include "third_party/skia/include/core/SkImage.h"
36 #include "ui/gfx/test/icc_profiles.h"
37
38 #include <sys/stat.h>
39
40 #if defined(_WIN32)
41 #include <mmsystem.h>
42 #include <time.h>
43 #define stat(x, y) _stat(x, y)
44 typedef struct _stat sttype;
45 #else
46 #include <sys/time.h>
47 typedef struct stat sttype;
48 #endif
49
50 namespace blink {
51
52 namespace {
53
54 #if defined(_WIN32)
55
56 // There is no real platform support herein, so adopt the WIN32 performance
57 // counter from WTF
58 // http://trac.webkit.org/browser/trunk/Source/WTF/wtf/CurrentTime.cpp?rev=15243 8
59
60 static double LowResUTCTime() {
61 FILETIME file_time;
62 GetSystemTimeAsFileTime(&file_time);
63
64 // As per Windows documentation for FILETIME, copy the resulting FILETIME
65 // structure to a ULARGE_INTEGER structure using memcpy (using memcpy instead
66 // of direct assignment can prevent alignment faults on 64-bit Windows).
67 ULARGE_INTEGER date_time;
68 memcpy(&date_time, &file_time, sizeof(date_time));
69
70 // Number of 100 nanosecond between January 1, 1601 and January 1, 1970.
71 static const ULONGLONG kEpochBias = 116444736000000000ULL;
72 // Windows file times are in 100s of nanoseconds.
73 static const double kHundredsOfNanosecondsPerMillisecond = 10000;
74 return (date_time.QuadPart - kEpochBias) /
75 kHundredsOfNanosecondsPerMillisecond;
76 }
77
78 static LARGE_INTEGER g_qpc_frequency;
79 static bool g_synced_time;
80
81 static double HighResUpTime() {
82 // We use QPC, but only after sanity checking its result, due to bugs:
83 // http://support.microsoft.com/kb/274323
84 // http://support.microsoft.com/kb/895980
85 // http://msdn.microsoft.com/en-us/library/ms644904.aspx ("you can get
86 // different results on different processors due to bugs in the basic
87 // input/output system (BIOS) or the hardware abstraction layer (HAL).").
88
89 static LARGE_INTEGER qpc_last;
90 static DWORD tick_count_last;
91 static bool inited;
92
93 LARGE_INTEGER qpc;
94 QueryPerformanceCounter(&qpc);
95 DWORD tick_count = GetTickCount();
96
97 if (inited) {
98 __int64 qpc_elapsed =
99 ((qpc.QuadPart - qpc_last.QuadPart) * 1000) / g_qpc_frequency.QuadPart;
100 __int64 tick_count_elapsed;
101 if (tick_count >= tick_count_last) {
102 tick_count_elapsed = (tick_count - tick_count_last);
103 } else {
104 __int64 tick_count_large = tick_count + 0x100000000I64;
105 tick_count_elapsed = tick_count_large - tick_count_last;
106 }
107
108 // Force a re-sync if QueryPerformanceCounter differs from GetTickCount() by
109 // more than 500ms. (The 500ms value is from
110 // http://support.microsoft.com/kb/274323).
111 __int64 diff = tick_count_elapsed - qpc_elapsed;
112 if (diff > 500 || diff < -500)
113 g_synced_time = false;
114 } else {
115 inited = true;
116 }
117
118 qpc_last = qpc;
119 tick_count_last = tick_count;
120
121 return (1000.0 * qpc.QuadPart) /
122 static_cast<double>(g_qpc_frequency.QuadPart);
123 }
124
125 static bool QpcAvailable() {
126 static bool available;
127 static bool checked;
128
129 if (checked)
130 return available;
131
132 available = QueryPerformanceFrequency(&g_qpc_frequency);
133 checked = true;
134 return available;
135 }
136
137 static double GetCurrentTime() {
138 // Use a combination of ftime and QueryPerformanceCounter.
139 // ftime returns the information we want, but doesn't have sufficient
140 // resolution. QueryPerformanceCounter has high resolution, but is only
141 // usable to measure time intervals. To combine them, we call ftime and
142 // QueryPerformanceCounter initially. Later calls will use
143 // QueryPerformanceCounter by itself, adding the delta to the saved ftime. We
144 // periodically re-sync to correct for drift.
145 static double sync_low_res_utc_time;
146 static double sync_high_res_up_time;
147 static double last_utc_time;
148
149 double low_res_time = LowResUTCTime();
150 if (!QpcAvailable())
151 return low_res_time * (1.0 / 1000.0);
152
153 double high_res_time = HighResUpTime();
154 if (!g_synced_time) {
155 timeBeginPeriod(1); // increase time resolution around low-res time getter
156 sync_low_res_utc_time = low_res_time = LowResUTCTime();
157 timeEndPeriod(1); // restore time resolution
158 sync_high_res_up_time = high_res_time;
159 g_synced_time = true;
160 }
161
162 double high_res_elapsed = high_res_time - sync_high_res_up_time;
163 double utc = sync_low_res_utc_time + high_res_elapsed;
164
165 // Force a clock re-sync if we've drifted.
166 double low_res_elapsed = low_res_time - sync_low_res_utc_time;
167 const double kMaximumAllowedDriftMsec =
168 15.625 * 2.0; // 2x the typical low-res accuracy
169 if (fabs(high_res_elapsed - low_res_elapsed) > kMaximumAllowedDriftMsec)
170 g_synced_time = false;
171
172 // Make sure time doesn't run backwards (only correct if the difference is < 2
173 // seconds, since DST or clock changes could occur).
174 const double kBackwardTimeLimit = 2000.0;
175 if (utc < last_utc_time && (last_utc_time - utc) < kBackwardTimeLimit)
176 return last_utc_time * (1.0 / 1000.0);
177
178 last_utc_time = utc;
179 return utc * (1.0 / 1000.0);
180 }
181
182 #else
183
184 static double GetCurrentTime() {
185 struct timeval now;
186 gettimeofday(&now, 0);
187 return now.tv_sec + now.tv_usec * (1.0 / 1000000.0);
188 }
189
190 #endif
191
192 PassRefPtr<SharedBuffer> ReadFile(const char* file_name) {
193 FILE* fp = fopen(file_name, "rb");
194 if (!fp) {
195 fprintf(stderr, "Can't open file %s\n", file_name);
196 exit(2);
197 }
198
199 sttype s;
200 stat(file_name, &s);
201 size_t file_size = s.st_size;
202 if (s.st_size <= 0)
203 return SharedBuffer::Create();
204
205 std::unique_ptr<unsigned char[]> buffer =
206 WrapArrayUnique(new unsigned char[file_size]);
207 if (file_size != fread(buffer.get(), 1, file_size, fp)) {
208 fprintf(stderr, "Error reading file %s\n", file_name);
209 exit(2);
210 }
211
212 fclose(fp);
213 return SharedBuffer::Create(buffer.get(), file_size);
214 }
215
216 bool ReadPixels(SkImage* image) {
217 SkBitmap bitmap;
218 bitmap.allocPixels(
219 SkImageInfo::MakeN32Premul(image->width(), image->width()));
220 return image->readPixels(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes(),
221 0, 0);
222 }
223
224 struct RealDecodeImages {
225 sk_sp<SkImage>* images;
226 size_t* frame_index_arr;
227 size_t count;
228 size_t avail;
229 };
230
231 void RealDecode(RealDecodeImages* real_decoded_images) {
232 size_t to_decod_index = 0;
233 size_t current_frame_index = 0;
234
235 while (true) {
236 bool ret = true;
237 bool need_decode = false;
238
239 for (size_t i = to_decod_index; i < real_decoded_images->avail; i++) {
240 if (real_decoded_images->frame_index_arr[i] != current_frame_index) {
241 current_frame_index = real_decoded_images->frame_index_arr[i];
242 break;
243 }
244 need_decode = true;
245 to_decod_index = i;
246 }
247
248 if (need_decode) {
249 sk_sp<SkImage>* image = real_decoded_images->images + to_decod_index;
250 if (image->get()) {
251 ret = ReadPixels(image->get());
252 }
253 ++to_decod_index;
254 }
255
256 if (to_decod_index == real_decoded_images->count) {
257 if (!ret) {
258 fprintf(stderr, "RealDecode failed!\n");
259 exit(3);
260 }
261 break;
262 }
263 }
264 }
265
266 bool DecodeImageData(SharedBuffer* data,
267 bool color_correction,
268 size_t packet_size) {
269 std::unique_ptr<ImageDecoder> info_decoder = ImageDecoder::Create(
270 data, true, ImageDecoder::kAlphaPremultiplied,
271 color_correction ? ColorBehavior::TransformToTargetForTesting()
272 : ColorBehavior::Ignore());
273 bool all_data_received = true;
274 info_decoder->SetData(data, all_data_received);
275
276 int frame_count = info_decoder->FrameCount();
277
278 if (!packet_size) {
279 std::unique_ptr<DeferredImageDecoder> decoder =
280 DeferredImageDecoder::Create(
281 data, false, ImageDecoder::kAlphaPremultiplied,
282 color_correction ? ColorBehavior::TransformToTargetForTesting()
283 : ColorBehavior::Ignore());
284
285 bool all_data_received = true;
286 decoder->SetData(data, all_data_received);
287
288 int frame_count = decoder->FrameCount();
289 for (int i = 0; i < frame_count; ++i) {
290 sk_sp<SkImage> image = decoder->CreateFrameAtIndex(i);
291 if (!image)
292 return false;
293 bool ret = ReadPixels(image.get());
294 if (!ret) {
295 fprintf(stderr, "DecodeImageData failed!\n");
296 exit(3);
297 }
298 }
299
300 return true;
301 }
302
303 size_t cirle_count = data->size() / packet_size + data->size() % packet_size;
304 size_t images_count = frame_count * cirle_count;
305 sk_sp<SkImage>* images = new sk_sp<SkImage>[images_count];
306 size_t* frame_index_arr = new size_t[images_count];
307 memset(frame_index_arr, 0, sizeof(size_t[images_count]));
308 size_t image_index = 0;
309
310 RealDecodeImages real_decode_images{images, frame_index_arr, images_count, 0};
311
312 std::thread real_decode_thread(RealDecode, &real_decode_images);
313
314 RefPtr<SharedBuffer> packet_data = SharedBuffer::Create();
315 size_t position = 0;
316 size_t next_frame_to_decode = 0;
317
318 std::unique_ptr<DeferredImageDecoder> pakcet_decoder;
319
320 while (true) {
321 const char* packet;
322 size_t length = data->GetSomeData(packet, position);
323
324 length = std::min(length, packet_size);
325 packet_data->Append(packet, length);
326 position += length;
327
328 bool all_data_received = position == data->size();
329 if (!pakcet_decoder) {
330 pakcet_decoder = DeferredImageDecoder::Create(
331 packet_data, false, ImageDecoder::kAlphaPremultiplied,
332 color_correction ? ColorBehavior::TransformToTargetForTesting()
333 : ColorBehavior::Ignore());
334 }
335 if (!pakcet_decoder) {
336 continue;
337 }
338
339 pakcet_decoder->SetData(packet_data.Get(), all_data_received);
340
341 size_t frame_count = pakcet_decoder->FrameCount();
342 for (size_t i = next_frame_to_decode; i < frame_count; ++i) {
343 images[image_index] = pakcet_decoder->CreateFrameAtIndex(i);
344 frame_index_arr[image_index] = i;
345 ++image_index;
346 if (pakcet_decoder->FrameIsCompleteAtIndex(i)) {
347 next_frame_to_decode = i + 1;
348 real_decode_images.avail = image_index;
349 }
350 }
351
352 if (all_data_received)
353 break;
354 }
355
356 real_decode_images.count = real_decode_images.avail;
357
358 real_decode_thread.join();
359
360 delete[] images;
361 delete[] frame_index_arr;
362
363 return true;
364 }
365
366 } // namespace
367
368 int Main(int argc, char* argv[]) {
369 base::CommandLine::Init(argc, argv);
370
371 base::TestDiscardableMemoryAllocator memoryAllocator;
372 base::DiscardableMemoryAllocator::SetInstance(&memoryAllocator);
373
374 WTF::Partitions::Initialize(nullptr);
375
376 // If the platform supports color correction, allow it to be controlled.
377
378 bool apply_color_correction = false;
379
380 if (argc >= 2 && strcmp(argv[1], "--color-correct") == 0) {
381 apply_color_correction = (--argc, ++argv, true);
382 gfx::ICCProfile profile = gfx::ICCProfileForTestingColorSpin();
383 ColorBehavior::SetGlobalTargetColorProfile(profile);
384 }
385
386 if (argc < 2) {
387 fprintf(stderr,
388 "Usage: %s [--color-correct] file [iterations] [packetSize]\n",
389 argv[0]);
390 exit(1);
391 }
392
393 // Control decode bench iterations and packet size.
394
395 size_t iterations = 1;
396 if (argc >= 3) {
397 char* end = 0;
398 iterations = strtol(argv[2], &end, 10);
399 if (*end != '\0' || !iterations) {
400 fprintf(stderr,
401 "Second argument should be number of iterations. "
402 "The default is 1. You supplied %s\n",
403 argv[2]);
404 exit(1);
405 }
406 }
407
408 size_t packet_size = 0;
409 if (argc >= 4) {
410 char* end = 0;
411 packet_size = strtol(argv[3], &end, 10);
412 if (*end != '\0') {
413 fprintf(stderr,
414 "Third argument should be packet size. Default is "
415 "0, meaning to decode the entire image in one packet. You "
416 "supplied %s\n",
417 argv[3]);
418 exit(1);
419 }
420 }
421
422 // Create a web platform. blink::Platform can't be used directly because its
423 // constructor is protected.
424
425 class WebPlatform : public blink::Platform {};
426
427 Platform::Initialize(new WebPlatform());
428
429 // Read entire file content to data, and consolidate the SharedBuffer data
430 // segments into one, contiguous block of memory.
431
432 RefPtr<SharedBuffer> data = ReadFile(argv[1]);
433 if (!data.Get() || !data->size()) {
434 fprintf(stderr, "Error reading image data from [%s]\n", argv[1]);
435 exit(2);
436 }
437
438 data->Data();
439
440 // Warm-up: throw out the first iteration for more consistent results.
441
442 if (!DecodeImageData(data.Get(), apply_color_correction, packet_size)) {
443 fprintf(stderr, "Image decode failed [%s]\n", argv[1]);
444 exit(3);
445 }
446
447 // Image decode bench for iterations.
448
449 double total_time = 0.0;
450
451 for (size_t i = 0; i < iterations; ++i) {
452 double start_time = GetCurrentTime();
453 bool decoded =
454 DecodeImageData(data.Get(), apply_color_correction, packet_size);
455 double elapsed_time = GetCurrentTime() - start_time;
456 total_time += elapsed_time;
457 if (!decoded) {
458 fprintf(stderr, "Image decode failed [%s]\n", argv[1]);
459 exit(3);
460 }
461 }
462
463 // Results to stdout.
464 double average_time = total_time / static_cast<double>(iterations);
465 printf("%f %f\n", total_time, average_time);
466 return 0;
467 }
468
469 } // namespace blink
470
471 int main(int argc, char* argv[]) {
472 return blink::Main(argc, argv);
473 }
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/platform/image-decoders/SegmentReader.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698