OLD | NEW |
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 & Skia raster. |
6 // a non-threaded, memory-to-memory image decode using micro second accuracy | 6 // Used to perform a non-threaded, memory-to-memory image decode/raster using |
7 // clocks to measure image decode time. Optionally applies color correction | 7 // micro second accuracy clocks to measure image decode time. Optionally |
8 // during image decoding on supported platforms (default off). Usage: | 8 // applies color correction during image decoding on supported platforms |
| 9 // (default off). Usage: |
9 // | 10 // |
10 // % ninja -C out/Release image_decode_bench && | 11 // % ninja -C out/Release image_decode_bench && |
11 // ./out/Release/image_decode_bench file [iterations] | 12 // ./out/Release/image_decode_bench file [iterations] |
12 // | 13 // |
13 // If --raw-output is specified, the output is formatted for use in a .csv file | 14 // If --raw-output is specified, the output is formatted for use in a .csv file |
14 // (comma-separated variable). | 15 // (comma-separated variable). |
15 // Each row represents successive frames in an animated image. | 16 // Each row represents successive frames in an animated image. |
16 // (frame 0, frame 1, frame 2...) | 17 // (frame 0, frame 1, frame 2...) |
17 // Each column represents a single frame decoded from successive iterations. | 18 // Each column represents a single frame decoded from successive iterations. |
18 // Iteration 0: (frame 0, frame 1, frame 2...) | 19 // Iteration 0: (frame 0, frame 1, frame 2...) |
19 // Iteration 1: (frame 0, frame 1, frame 2...) | 20 // Iteration 1: (frame 0, frame 1, frame 2...) |
20 // | 21 // |
21 // This means non-animated images will show up as one column. | 22 // This means non-animated images will show up as one column. |
| 23 // Raster timing also shows up as one column. |
22 // | 24 // |
23 // This .csv-formatted output is a common format for spreadsheet and data | 25 // This .csv-formatted output is a common format for spreadsheet and data |
24 // visualization programs. A user can take timings before and after a change, | 26 // visualization programs. A user can take timings before and after a change, |
25 // import the two .csv files, and overlay their line graphs ontop of each other | 27 // import the two .csv files, and overlay their line graphs ontop of each other |
26 // to see how the two measurements compare. | 28 // to see how the two measurements compare. |
27 // | 29 // |
28 // It should tell the user 1.) if the change was an improvement, 2.) if so, how | 30 // It should tell the user 1.) if the change was an improvement, 2.) if so, how |
29 // much, and 3.) if the measurements are noisy and thus reduce our trust in the | 31 // much, and 3.) if the measurements are noisy and thus reduce our trust in the |
30 // improvement. | 32 // improvement. |
31 // | 33 // |
(...skipping 10 matching lines...) Expand all Loading... |
42 | 44 |
43 #include <cmath> | 45 #include <cmath> |
44 #include <memory> | 46 #include <memory> |
45 #include <vector> | 47 #include <vector> |
46 #include "base/command_line.h" | 48 #include "base/command_line.h" |
47 #include "platform/SharedBuffer.h" | 49 #include "platform/SharedBuffer.h" |
48 #include "platform/image-decoders/ImageDecoder.h" | 50 #include "platform/image-decoders/ImageDecoder.h" |
49 #include "platform/wtf/PassRefPtr.h" | 51 #include "platform/wtf/PassRefPtr.h" |
50 #include "platform/wtf/PtrUtil.h" | 52 #include "platform/wtf/PtrUtil.h" |
51 #include "public/platform/Platform.h" | 53 #include "public/platform/Platform.h" |
| 54 #include "third_party/skia/include/core/SkCanvas.h" |
| 55 #include "third_party/skia/include/core/SkSurface.h" |
52 #include "ui/gfx/test/icc_profiles.h" | 56 #include "ui/gfx/test/icc_profiles.h" |
53 | 57 |
54 #if defined(_WIN32) | 58 #if defined(_WIN32) |
55 #include <mmsystem.h> | 59 #include <mmsystem.h> |
56 #include <sys/stat.h> | 60 #include <sys/stat.h> |
57 #include <time.h> | 61 #include <time.h> |
58 #define stat(x, y) _stat(x, y) | 62 #define stat(x, y) _stat(x, y) |
59 typedef struct _stat sttype; | 63 typedef struct _stat sttype; |
60 #else | 64 #else |
61 #include <sys/stat.h> | 65 #include <sys/stat.h> |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 ColorBehavior::Ignore()); | 304 ColorBehavior::Ignore()); |
301 size_t frame_count = frame_count_decoder->FrameCount(); | 305 size_t frame_count = frame_count_decoder->FrameCount(); |
302 | 306 |
303 IterationsOfFrameTimings timings(iterations, FrameTimings(frame_count, 0.0)); | 307 IterationsOfFrameTimings timings(iterations, FrameTimings(frame_count, 0.0)); |
304 | 308 |
305 for (size_t i = 0; i < iterations; ++i) { | 309 for (size_t i = 0; i < iterations; ++i) { |
306 std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create( | 310 std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create( |
307 data.Get(), true, ImageDecoder::kAlphaPremultiplied, | 311 data.Get(), true, ImageDecoder::kAlphaPremultiplied, |
308 apply_color_correction ? ColorBehavior::TransformToTargetForTesting() | 312 apply_color_correction ? ColorBehavior::TransformToTargetForTesting() |
309 : ColorBehavior::Ignore()); | 313 : ColorBehavior::Ignore()); |
310 constexpr bool all_data_received = true; | 314 bool all_data_received = true; |
311 decoder->SetData(data.Get(), all_data_received); | 315 decoder->SetData(data.Get(), all_data_received); |
312 for (size_t frame_index = 0; frame_index < frame_count; ++frame_index) { | 316 for (size_t frame_index = 0; frame_index < frame_count; ++frame_index) { |
313 double start_time = GetCurrentTime(); | 317 double start_time = GetCurrentTime(); |
314 ImageFrame* frame = decoder->FrameBufferAtIndex(frame_index); | 318 ImageFrame* frame = decoder->FrameBufferAtIndex(frame_index); |
315 double elapsed_time = GetCurrentTime() - start_time; | 319 double elapsed_time = GetCurrentTime() - start_time; |
316 if (frame->GetStatus() != ImageFrame::kFrameComplete) { | 320 if (frame->GetStatus() != ImageFrame::kFrameComplete) { |
317 fprintf(stderr, "Image decode failed\n"); | 321 fprintf(stderr, "Image decode failed\n"); |
318 exit(3); | 322 exit(3); |
319 } | 323 } |
320 timings[i][frame_index] = elapsed_time; | 324 timings[i][frame_index] = elapsed_time; |
321 } | 325 } |
322 } | 326 } |
323 | 327 |
324 return timings; | 328 return timings; |
325 } | 329 } |
326 | 330 |
327 // This function mimics deferred decoding in Chromium when not all data has been | 331 // This function mimics deferred decoding in Chromium when not all data has been |
328 // received yet. | 332 // received yet. |
329 IterationsOfFrameTimings TimePacketedDecode(PassRefPtr<SharedBuffer> data, | 333 IterationsOfFrameTimings TimePacketedDecode(PassRefPtr<SharedBuffer> data, |
330 bool apply_color_correction, | 334 bool apply_color_correction, |
331 size_t packet_size, | 335 size_t packet_size, |
332 size_t iterations) { | 336 size_t iterations) { |
333 // Find total frame count. | 337 // Find total frame count. |
334 // Doing this requires a decoder with full data (no packet size). | 338 // Doing this requires a decoder with full data (no packet size). |
335 std::unique_ptr<ImageDecoder> frame_count_decoder = | 339 std::unique_ptr<ImageDecoder> frame_count_decoder = |
336 ImageDecoder::Create(data.Get(), true, ImageDecoder::kAlphaPremultiplied, | 340 ImageDecoder::Create(data.Get(), true, ImageDecoder::kAlphaPremultiplied, |
337 ColorBehavior::Ignore()); | 341 ColorBehavior::Ignore()); |
338 | 342 |
339 constexpr bool total_all_data_received = true; | 343 bool total_all_data_received = true; |
340 frame_count_decoder->SetData(data.Get(), total_all_data_received); | 344 frame_count_decoder->SetData(data.Get(), total_all_data_received); |
341 size_t total_frame_count = frame_count_decoder->FrameCount(); | 345 size_t total_frame_count = frame_count_decoder->FrameCount(); |
342 | 346 |
343 IterationsOfFrameTimings timings(iterations, | 347 IterationsOfFrameTimings timings(iterations, |
344 FrameTimings(total_frame_count, 0.0)); | 348 FrameTimings(total_frame_count, 0.0)); |
345 | 349 |
346 RefPtr<SharedBuffer> packet_data = SharedBuffer::Create(); | 350 RefPtr<SharedBuffer> packet_data = SharedBuffer::Create(); |
347 size_t position = 0; | 351 size_t position = 0; |
348 size_t next_frame_to_decode = 0; | 352 size_t next_frame_to_decode = 0; |
349 while (true) { | 353 while (true) { |
(...skipping 28 matching lines...) Expand all Loading... |
378 if (all_data_received || decoder->Failed()) { | 382 if (all_data_received || decoder->Failed()) { |
379 fprintf(stderr, "Image decode failed\n"); | 383 fprintf(stderr, "Image decode failed\n"); |
380 exit(3); | 384 exit(3); |
381 } | 385 } |
382 } | 386 } |
383 } | 387 } |
384 | 388 |
385 return timings; | 389 return timings; |
386 } | 390 } |
387 | 391 |
| 392 IterationsOfFrameTimings TimeRaster(PassRefPtr<SharedBuffer> data, |
| 393 size_t iterations) { |
| 394 std::unique_ptr<ImageDecoder> decoder = |
| 395 ImageDecoder::Create(data.Get(), true, ImageDecoder::kAlphaPremultiplied, |
| 396 ColorBehavior::Ignore()); |
| 397 |
| 398 bool all_data_received = true; |
| 399 decoder->SetData(data.Get(), all_data_received); |
| 400 |
| 401 if (!decoder->IsSizeAvailable()) { |
| 402 fprintf(stderr, "failed to decode size\n"); |
| 403 exit(3); |
| 404 } |
| 405 |
| 406 size_t frame_count = decoder->FrameCount(); |
| 407 |
| 408 auto size = decoder->Size(); |
| 409 auto surface = SkSurface::MakeRasterN32Premul(size.Width(), size.Height()); |
| 410 auto canvas = surface->getCanvas(); |
| 411 |
| 412 IterationsOfFrameTimings timings(iterations, FrameTimings(frame_count, 0.0)); |
| 413 for (size_t i = 0; i < iterations; ++i) { |
| 414 for (size_t frame_index = 0; frame_index < frame_count; ++frame_index) { |
| 415 ImageFrame* frame = decoder->FrameBufferAtIndex(frame_index); |
| 416 if (frame->GetStatus() != ImageFrame::kFrameComplete) { |
| 417 fprintf(stderr, "failed to decode frame\n"); |
| 418 exit(3); |
| 419 } |
| 420 |
| 421 double start_time = GetCurrentTime(); |
| 422 canvas->drawBitmap(frame->Bitmap(), 0, 0, nullptr); |
| 423 double elapsed_time = GetCurrentTime() - start_time; |
| 424 timings[i][frame_index] = elapsed_time; |
| 425 } |
| 426 } |
| 427 |
| 428 return timings; |
| 429 } |
| 430 |
388 } // namespace | 431 } // namespace |
389 | 432 |
390 int Main(int argc, char* argv[]) { | 433 int Main(int argc, char* argv[]) { |
391 base::CommandLine::Init(argc, argv); | 434 base::CommandLine::Init(argc, argv); |
392 | 435 |
393 // If the platform supports color correction, allow it to be controlled. | 436 // If the platform supports color correction, allow it to be controlled. |
394 | 437 |
395 bool apply_color_correction = false; | 438 bool apply_color_correction = false; |
396 if (argc >= 2 && strcmp(argv[1], "--color-correct") == 0) { | 439 if (argc >= 2 && strcmp(argv[1], "--color-correct") == 0) { |
397 --argc; | 440 --argc; |
398 ++argv; | 441 ++argv; |
399 apply_color_correction = true; | 442 apply_color_correction = true; |
400 gfx::ICCProfile profile = gfx::ICCProfileForTestingColorSpin(); | 443 gfx::ICCProfile profile = gfx::ICCProfileForTestingColorSpin(); |
401 ColorBehavior::SetGlobalTargetColorProfile(profile); | 444 ColorBehavior::SetGlobalTargetColorProfile(profile); |
402 } | 445 } |
403 | 446 |
| 447 bool time_raster = false; |
| 448 if (argc >= 2 && strcmp(argv[1], "--raster") == 0) { |
| 449 --argc; |
| 450 ++argv; |
| 451 time_raster = true; |
| 452 } |
| 453 |
404 const char* raw_output_file = nullptr; | 454 const char* raw_output_file = nullptr; |
405 if (argc >= 2 && strcmp(argv[1], "--raw-output") == 0) { | 455 if (argc >= 2 && strcmp(argv[1], "--raw-output") == 0) { |
406 if (argc < 3) { | 456 if (argc < 3) { |
407 fprintf(stderr, | 457 fprintf(stderr, |
408 "--raw-output specified without also specifying a file after it"); | 458 "--raw-output specified without also specifying a file after it"); |
409 exit(1); | 459 exit(1); |
410 } | 460 } |
411 | 461 |
412 raw_output_file = argv[2]; | 462 raw_output_file = argv[2]; |
413 argc -= 2; | 463 argc -= 2; |
414 argv += 2; | 464 argv += 2; |
415 } | 465 } |
416 | 466 |
417 if (argc < 2) { | 467 if (argc < 2) { |
418 fprintf(stderr, | 468 fprintf(stderr, |
419 "Usage: %s [--color-correct] [--raw-output output_file] file " | 469 "Usage: %s [--color-correct] [--raw-output output_file] [--raster] " |
420 "[iterations] [packetSize]\n", | 470 "file [iterations] [packetSize]\n", |
421 argv[0]); | 471 argv[0]); |
422 exit(1); | 472 exit(1); |
423 } | 473 } |
424 | 474 |
425 // Control decode bench iterations and packet size. | 475 // Control decode bench iterations and packet size. |
426 | 476 |
427 size_t iterations = 1; | 477 size_t iterations = 1; |
428 if (argc >= 3) { | 478 if (argc >= 3) { |
429 char* end = 0; | 479 char* end = 0; |
430 iterations = strtol(argv[2], &end, 10); | 480 iterations = strtol(argv[2], &end, 10); |
(...skipping 13 matching lines...) Expand all Loading... |
444 if (*end != '\0') { | 494 if (*end != '\0') { |
445 fprintf(stderr, | 495 fprintf(stderr, |
446 "Third argument should be packet size. Default is " | 496 "Third argument should be packet size. Default is " |
447 "0, meaning to decode the entire image in one packet. You " | 497 "0, meaning to decode the entire image in one packet. You " |
448 "supplied %s\n", | 498 "supplied %s\n", |
449 argv[3]); | 499 argv[3]); |
450 exit(1); | 500 exit(1); |
451 } | 501 } |
452 } | 502 } |
453 | 503 |
| 504 if (time_raster && packet_size) { |
| 505 fprintf(stderr, |
| 506 "It does not make sense to specify a packet size when " |
| 507 "timing raster\n"); |
| 508 exit(1); |
| 509 } |
| 510 |
454 // Create a web platform. blink::Platform can't be used directly because its | 511 // Create a web platform. blink::Platform can't be used directly because its |
455 // constructor is protected. | 512 // constructor is protected. |
456 | 513 |
457 class WebPlatform : public blink::Platform {}; | 514 class WebPlatform : public blink::Platform {}; |
458 | 515 |
459 Platform::Initialize(new WebPlatform()); | 516 Platform::Initialize(new WebPlatform()); |
460 | 517 |
461 // Read entire file content to data, and consolidate the SharedBuffer data | 518 // Read entire file content to data, and consolidate the SharedBuffer data |
462 // segments into one, contiguous block of memory. | 519 // segments into one, contiguous block of memory. |
463 | 520 |
464 RefPtr<SharedBuffer> data = ReadFile(argv[1]); | 521 RefPtr<SharedBuffer> data = ReadFile(argv[1]); |
465 if (!data.Get() || !data->size()) { | 522 if (!data.Get() || !data->size()) { |
466 fprintf(stderr, "Error reading image data from [%s]\n", argv[1]); | 523 fprintf(stderr, "Error reading image data from [%s]\n", argv[1]); |
467 exit(2); | 524 exit(2); |
468 } | 525 } |
469 | 526 |
470 data->Data(); | 527 data->Data(); |
471 | 528 |
472 IterationsOfFrameTimings timings; | 529 IterationsOfFrameTimings timings; |
473 if (packet_size) { | 530 if (time_raster) { |
474 timings = TimePacketedDecode(data.Get(), apply_color_correction, | 531 timings = TimeRaster(data.Get(), iterations); |
475 packet_size, iterations); | |
476 } else { | 532 } else { |
477 timings = TimeDecode(data.Get(), apply_color_correction, iterations); | 533 if (packet_size) { |
| 534 timings = TimePacketedDecode(data.Get(), apply_color_correction, |
| 535 packet_size, iterations); |
| 536 } else { |
| 537 timings = TimeDecode(data.Get(), apply_color_correction, iterations); |
| 538 } |
478 } | 539 } |
479 | 540 |
480 if (raw_output_file) | 541 if (raw_output_file) |
481 Write2DResultsToFile(timings, raw_output_file); | 542 Write2DResultsToFile(timings, raw_output_file); |
482 | 543 |
483 double mean = GetMean(timings); | 544 double mean = GetMean(timings); |
484 double standard_deviation = GetStandardDeviation(timings, mean); | 545 double standard_deviation = GetStandardDeviation(timings, mean); |
485 | 546 |
486 printf("mean: %f standard deviation: %f\n", mean, standard_deviation); | 547 printf("mean: %f standard deviation: %f\n", mean, standard_deviation); |
487 | 548 |
488 return 0; | 549 return 0; |
489 } | 550 } |
490 | 551 |
491 } // namespace blink | 552 } // namespace blink |
492 | 553 |
493 int main(int argc, char* argv[]) { | 554 int main(int argc, char* argv[]) { |
494 return blink::Main(argc, argv); | 555 return blink::Main(argc, argv); |
495 } | 556 } |
OLD | NEW |