| 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 |