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

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

Issue 2880953002: Measure frame decodes more accurately from ImageDecodeBench
Patch Set: Created 3 years, 7 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 | « no previous file | 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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // Provides a minimal wrapping of the Blink image decoders. Used to perform 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 6 // a non-threaded, memory-to-memory image decode using micro second accuracy
7 // clocks to measure image decode time. Optionally applies color correction 7 // clocks to measure image decode time. Optionally applies color correction
8 // during image decoding on supported platforms (default off). Usage: 8 // during image decoding on supported platforms (default off). Usage:
scroggo_chromium 2017/05/15 15:59:04 Add comments about using --raster
cblume 2017/05/19 16:47:58 Done.
9 // 9 //
10 // % ninja -C out/Release image_decode_bench && 10 // % ninja -C out/Release image_decode_bench &&
11 // ./out/Release/image_decode_bench file [iterations] 11 // ./out/Release/image_decode_bench file [iterations]
12 // 12 //
13 // TODO(noel): Consider adding md5 checksum support to WTF. Use it to compute 13 // TODO(noel): Consider adding md5 checksum support to WTF. Use it to compute
14 // the decoded image frame md5 and output that value. 14 // the decoded image frame md5 and output that value.
15 // 15 //
16 // TODO(noel): Consider integrating this tool in Chrome telemetry for realz, 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 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 18 // to http://crbug.com/398235#c103 and http://crbug.com/258324#c5
19 19
20 #include <memory> 20 #include <memory>
21 #include <vector>
21 #include "base/command_line.h" 22 #include "base/command_line.h"
22 #include "platform/SharedBuffer.h" 23 #include "platform/SharedBuffer.h"
23 #include "platform/image-decoders/ImageDecoder.h" 24 #include "platform/image-decoders/ImageDecoder.h"
24 #include "platform/wtf/PassRefPtr.h" 25 #include "platform/wtf/PassRefPtr.h"
25 #include "platform/wtf/PtrUtil.h" 26 #include "platform/wtf/PtrUtil.h"
26 #include "public/platform/Platform.h" 27 #include "public/platform/Platform.h"
28 #include "third_party/skia/include/core/SkCanvas.h"
29 #include "third_party/skia/include/core/SkSurface.h"
27 #include "ui/gfx/test/icc_profiles.h" 30 #include "ui/gfx/test/icc_profiles.h"
28 31
29 #if defined(_WIN32) 32 #if defined(_WIN32)
30 #include <mmsystem.h> 33 #include <mmsystem.h>
31 #include <sys/stat.h> 34 #include <sys/stat.h>
32 #include <time.h> 35 #include <time.h>
33 #define stat(x, y) _stat(x, y) 36 #define stat(x, y) _stat(x, y)
34 typedef struct _stat sttype; 37 typedef struct _stat sttype;
35 #else 38 #else
36 #include <sys/stat.h> 39 #include <sys/stat.h>
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 WrapArrayUnique(new unsigned char[file_size]); 200 WrapArrayUnique(new unsigned char[file_size]);
198 if (file_size != fread(buffer.get(), 1, file_size, fp)) { 201 if (file_size != fread(buffer.get(), 1, file_size, fp)) {
199 fprintf(stderr, "Error reading file %s\n", file_name); 202 fprintf(stderr, "Error reading file %s\n", file_name);
200 exit(2); 203 exit(2);
201 } 204 }
202 205
203 fclose(fp); 206 fclose(fp);
204 return SharedBuffer::Create(buffer.get(), file_size); 207 return SharedBuffer::Create(buffer.get(), file_size);
205 } 208 }
206 209
207 bool DecodeImageData(SharedBuffer* data, 210 void Print1DResults(const std::vector<double>& timings) {
scroggo_chromium 2017/05/15 15:59:04 I suppose you put this here to keep it near Print2
cblume 2017/05/19 16:47:58 Done.
208 bool color_correction, 211 for (double iteration_time : timings) {
209 size_t packet_size) { 212 printf("%f,", iteration_time);
210 std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create( 213 }
211 data, true, ImageDecoder::kAlphaPremultiplied, 214 printf("\n");
212 color_correction ? ColorBehavior::TransformToTargetForTesting() 215 }
213 : ColorBehavior::Ignore());
214 if (!packet_size) {
215 bool all_data_received = true;
216 decoder->SetData(data, all_data_received);
217 216
218 int frame_count = decoder->FrameCount(); 217 // The outer vector represents multiple iterations through the image.
scroggo_chromium 2017/05/15 15:59:04 This comment appears several times. It makes me th
cblume 2017/05/19 16:47:58 Yeah. I had tried to come up with a typedef / usin
219 for (int i = 0; i < frame_count; ++i) { 218 // The inner vector represents individual frames in an animation.
220 if (!decoder->FrameBufferAtIndex(i)) 219 void Print2DResults(const std::vector<std::vector<double>>& timings) {
221 return false; 220 for (const std::vector<double>& iteration : timings) {
221 for (double frame_time : iteration) {
222 printf("%f,", frame_time);
222 } 223 }
224 printf("\n");
225 }
226 printf("\n");
227 }
223 228
224 return !decoder->Failed(); 229 void TimeDecode(ImageDecoder* decoder, SharedBuffer* data, size_t iterations) {
230 bool all_data_received = true;
231 decoder->SetData(data, all_data_received);
232
233 size_t frame_count = decoder->FrameCount();
234
235 // The outer vector represents multiple iterations through the image.
236 // The inner vector represents individual frames in an animation.
237 std::vector<std::vector<double>> timings(
238 iterations, std::vector<double>(frame_count, 0.0));
239
240 for (size_t iteration = 0; iteration < iterations; ++iteration) {
241 for (size_t frame_index = 0; frame_index < frame_count; ++frame_index) {
242 double start_time = GetCurrentTime();
243 ImageFrame* frame = decoder->FrameBufferAtIndex(frame_index);
244 double elapsed_time = GetCurrentTime() - start_time;
245 if (!frame) {
scroggo_chromium 2017/05/15 15:59:04 As I've stated elsewhere, I don't think this can e
cblume 2017/05/19 16:47:58 Done.
246 return;
247 }
248 timings[iteration][frame_index] = elapsed_time;
249 }
225 } 250 }
226 251
252 Print2DResults(timings);
253 }
254
255 // This function mimics what actually happens in Chromium.
scroggo_chromium 2017/05/15 15:59:04 There are different paths that result in a decode,
cblume 2017/05/19 16:47:58 Done.
256 void TimePacketedDecode(ImageDecoder* decoder,
257 SharedBuffer* data,
258 size_t packet_size,
259 size_t iterations) {
260 // Find total frame count.
261 // Doing this requires a decoder with full data (no packet size).
262 bool all_data_received = true;
scroggo_chromium 2017/05/15 15:59:04 This variable ends up being shadowed by a variable
cblume 2017/05/19 16:47:58 Right, I only have this bool for readability. It c
scroggo_chromium 2017/05/19 21:04:15 Ah, I prefer not having a named bool, but it makes
cblume 2017/05/19 21:47:38 I agree that I prefer the enum. I'll leave it for
263 decoder->SetData(data, all_data_received);
264 size_t total_frame_count = decoder->FrameCount();
265
266 // The outer vector represents multiple iterations through the image.
267 // The inner vector represents individual frames in an animation.
268 std::vector<std::vector<double>> timings(
269 iterations, std::vector<double>(total_frame_count, 0.0));
270
271 // Fill the buffer with only some data (|packet_size|), decode all the frames
272 // we can with that data, and then repeat -- filling with another packet.
227 RefPtr<SharedBuffer> packet_data = SharedBuffer::Create(); 273 RefPtr<SharedBuffer> packet_data = SharedBuffer::Create();
228 size_t position = 0; 274 size_t position = 0;
229 size_t next_frame_to_decode = 0; 275 size_t next_frame_to_decode = 0;
230 while (true) { 276 while (true) {
231 const char* packet; 277 const char* packet;
232 size_t length = data->GetSomeData(packet, position); 278 size_t length = data->GetSomeData(packet, position);
233 279
234 length = std::min(length, packet_size); 280 length = std::min(length, packet_size);
235 packet_data->Append(packet, length); 281 packet_data->Append(packet, length);
236 position += length; 282 position += length;
237 283
238 bool all_data_received = position == data->size(); 284 bool all_data_received = position == data->size();
285
239 size_t frame_count = decoder->FrameCount(); 286 size_t frame_count = decoder->FrameCount();
scroggo_chromium 2017/05/15 15:59:04 Since you're using the same decoder as above, I do
cblume 2017/05/19 16:47:58 Oh, you're right. I want to create a new decoder h
240 for (; next_frame_to_decode < frame_count; ++next_frame_to_decode) { 287 for (size_t iteration = 0; iteration < iterations; ++iteration) {
241 decoder->SetData(packet_data.Get(), all_data_received); 288 for (; next_frame_to_decode < frame_count; ++next_frame_to_decode) {
242 ImageFrame* frame = decoder->FrameBufferAtIndex(next_frame_to_decode); 289 decoder->SetData(packet_data.Get(), all_data_received);
243 if (frame->GetStatus() != ImageFrame::kFrameComplete) 290 double start_time = GetCurrentTime();
244 break; 291 ImageFrame* frame = decoder->FrameBufferAtIndex(next_frame_to_decode);
245 decoder->SetData(PassRefPtr<SegmentReader>(nullptr), false); 292 double elapsed_time = GetCurrentTime() - start_time;
246 decoder->ClearCacheExceptFrame(next_frame_to_decode); 293 if (frame->GetStatus() != ImageFrame::kFrameComplete)
294 break;
295 timings[iteration][next_frame_to_decode] = elapsed_time;
296 decoder->SetData(PassRefPtr<SegmentReader>(nullptr), false);
297 decoder->ClearCacheExceptFrame(next_frame_to_decode);
298 }
247 } 299 }
248 300
249 if (all_data_received || decoder->Failed()) 301 if (all_data_received || decoder->Failed())
250 break; 302 return;
251 } 303 }
252 304
253 return !decoder->Failed(); 305 Print2DResults(timings);
306 }
307
308 void TimeRaster(ImageDecoder* decoder, SharedBuffer* data, size_t iterations) {
309 // Decode first frame
scroggo_chromium 2017/05/15 15:59:04 I'm guilty of this, too, but try to keep your comm
cblume 2017/05/19 16:47:58 Done.
310 const bool all_data_received = true;
311 decoder->SetData(data, all_data_received);
312 ImageFrame* frame = decoder->FrameBufferAtIndex(0);
313
314 // Create raster target
315 const auto size = decoder->Size();
316 auto surface = SkSurface::MakeRasterN32Premul(size.Width(), size.Height());
317 auto canvas = surface->getCanvas();
318
319 // Time raster iterations
320 std::vector<double> timings(iterations);
321 for (size_t iteration = 0; iteration < iterations; ++iteration) {
322 double start_time = GetCurrentTime();
323 canvas->drawBitmap(frame->Bitmap(), 0, 0, nullptr);
324 double elapsed_time = GetCurrentTime() - start_time;
325 timings[iteration] = elapsed_time;
326 }
327
328 Print1DResults(timings);
254 } 329 }
255 330
256 } // namespace 331 } // namespace
257 332
258 int Main(int argc, char* argv[]) { 333 int Main(int argc, char* argv[]) {
259 base::CommandLine::Init(argc, argv); 334 base::CommandLine::Init(argc, argv);
260
261 // If the platform supports color correction, allow it to be controlled. 335 // If the platform supports color correction, allow it to be controlled.
262 336
263 bool apply_color_correction = false; 337 bool apply_color_correction = false;
264
265 if (argc >= 2 && strcmp(argv[1], "--color-correct") == 0) { 338 if (argc >= 2 && strcmp(argv[1], "--color-correct") == 0) {
266 apply_color_correction = (--argc, ++argv, true); 339 --argc;
340 ++argv;
341 apply_color_correction = true;
267 gfx::ICCProfile profile = gfx::ICCProfileForTestingColorSpin(); 342 gfx::ICCProfile profile = gfx::ICCProfileForTestingColorSpin();
268 ColorBehavior::SetGlobalTargetColorProfile(profile); 343 ColorBehavior::SetGlobalTargetColorProfile(profile);
269 } 344 }
270 345
346 bool time_raster = false;
347 if (argc >= 2 && strcmp(argv[1], "--raster") == 0) {
348 --argc;
349 ++argv;
350 time_raster = true;
351 }
352
271 if (argc < 2) { 353 if (argc < 2) {
272 fprintf(stderr, 354 fprintf(stderr,
273 "Usage: %s [--color-correct] file [iterations] [packetSize]\n", 355 "Usage: %s [--color-correct] [--raster] file [iterations] "
356 "[packetSize]\n",
274 argv[0]); 357 argv[0]);
275 exit(1); 358 exit(1);
276 } 359 }
277 360
278 // Control decode bench iterations and packet size. 361 // Control decode bench iterations and packet size.
279 362
280 size_t iterations = 1; 363 size_t iterations = 1;
281 if (argc >= 3) { 364 if (argc >= 3) {
282 char* end = 0; 365 char* end = 0;
283 iterations = strtol(argv[2], &end, 10); 366 iterations = strtol(argv[2], &end, 10);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 // segments into one, contiguous block of memory. 398 // segments into one, contiguous block of memory.
316 399
317 RefPtr<SharedBuffer> data = ReadFile(argv[1]); 400 RefPtr<SharedBuffer> data = ReadFile(argv[1]);
318 if (!data.Get() || !data->size()) { 401 if (!data.Get() || !data->size()) {
319 fprintf(stderr, "Error reading image data from [%s]\n", argv[1]); 402 fprintf(stderr, "Error reading image data from [%s]\n", argv[1]);
320 exit(2); 403 exit(2);
321 } 404 }
322 405
323 data->Data(); 406 data->Data();
324 407
325 // Warm-up: throw out the first iteration for more consistent results.
scroggo_chromium 2017/05/15 15:59:04 Is this no longer necessary?
cblume 2017/05/19 16:47:58 If you only do 1 iteration then it'll pretty much
326
327 if (!DecodeImageData(data.Get(), apply_color_correction, packet_size)) {
328 fprintf(stderr, "Image decode failed [%s]\n", argv[1]);
329 exit(3);
330 }
331
332 // Image decode bench for iterations. 408 // Image decode bench for iterations.
333 409
334 double total_time = 0.0; 410 std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create(
335 411 data, true, ImageDecoder::kAlphaPremultiplied,
336 for (size_t i = 0; i < iterations; ++i) { 412 apply_color_correction ? ColorBehavior::TransformToTargetForTesting()
337 double start_time = GetCurrentTime(); 413 : ColorBehavior::Ignore());
338 bool decoded = 414 if (time_raster) {
339 DecodeImageData(data.Get(), apply_color_correction, packet_size); 415 blink::TimeRaster(decoder.get(), data.Get(), iterations);
340 double elapsed_time = GetCurrentTime() - start_time; 416 } else {
341 total_time += elapsed_time; 417 if (packet_size) {
342 if (!decoded) { 418 blink::TimePacketedDecode(decoder.get(), data.Get(), packet_size,
343 fprintf(stderr, "Image decode failed [%s]\n", argv[1]); 419 iterations);
344 exit(3); 420 } else {
421 blink::TimeDecode(decoder.get(), data.Get(), iterations);
345 } 422 }
346 } 423 }
347 424
348 // Results to stdout.
349
350 double average_time = total_time / static_cast<double>(iterations);
351 printf("%f %f\n", total_time, average_time);
scroggo_chromium 2017/05/15 15:59:04 Now that we do not print the average, is the expec
cblume 2017/05/19 16:47:58 I want to be able to visualize the data. It also l
scroggo_chromium 2017/05/19 21:04:15 I guess what I'm getting at is, what do you do to
cblume 2017/05/19 21:47:38 I'm printing out the data in a way that makes it c
352 return 0; 425 return 0;
353 } 426 }
354 427
355 } // namespace blink 428 } // namespace blink
356 429
357 int main(int argc, char* argv[]) { 430 int main(int argc, char* argv[]) {
358 return blink::Main(argc, argv); 431 return blink::Main(argc, argv);
359 } 432 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698