blob: 951632a63e54ae34e1062fb0ed4c30de70ae652e [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Provides a minimal wrapping of the Blink image decoders. Used to perform
// a non-threaded, memory-to-memory image decode using micro second accuracy
// clocks to measure image decode time.
//
// TODO(noel): Consider integrating this tool in Chrome telemetry for realz,
// using the image corpora used to assess Blink image decode performance. See
// http://crbug.com/398235#c103 and http://crbug.com/258324#c5
#include <chrono>
#include <fstream>
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/memory/scoped_refptr.h"
#include "base/message_loop/message_loop.h"
#include "mojo/core/embedder/embedder.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
#include "third_party/blink/renderer/platform/shared_buffer.h"
namespace blink {
namespace {
scoped_refptr<SharedBuffer> ReadFile(const char* name) {
std::string file;
if (base::ReadFileToString(base::FilePath::FromUTF8Unsafe(name), &file))
return SharedBuffer::Create(file.data(), file.size());
perror(name);
exit(2);
return SharedBuffer::Create();
}
struct ImageMeta {
const char* name;
int width;
int height;
int frames;
// Cumulative time in seconds to decode all frames.
double time;
};
void DecodeFailure(ImageMeta* image) {
fprintf(stderr, "Failed to decode image %s\n", image->name);
exit(3);
}
void DecodeImageData(SharedBuffer* data, ImageMeta* image) {
const bool all_data_received = true;
std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create(
data, all_data_received, ImageDecoder::kAlphaPremultiplied,
ImageDecoder::kDefaultBitDepth, ColorBehavior::Ignore());
auto start = std::chrono::steady_clock::now();
decoder->SetData(data, all_data_received);
size_t frame_count = decoder->FrameCount();
for (size_t index = 0; index < frame_count; ++index) {
if (!decoder->DecodeFrameBufferAtIndex(index))
DecodeFailure(image);
}
auto end = std::chrono::steady_clock::now();
if (!frame_count || decoder->Failed())
DecodeFailure(image);
image->time += std::chrono::duration<double>(end - start).count();
image->width = decoder->Size().Width();
image->height = decoder->Size().Height();
image->frames = frame_count;
}
} // namespace
void ImageDecodeBenchMain(int argc, char* argv[]) {
int option, iterations = 1;
auto usage_exit = [&] {
fprintf(stderr, "Usage: %s [-i iterations] file [file...]\n", argv[0]);
exit(1);
};
for (option = 1; option < argc; ++option) {
if (argv[option][0] != '-')
break; // End of optional arguments.
if (std::string(argv[option]) != "-i")
usage_exit();
iterations = (++option < argc) ? atoi(argv[option]) : 0;
if (iterations < 1)
usage_exit();
}
if (option >= argc)
usage_exit();
// Setup Blink platform.
std::unique_ptr<Platform> platform = std::make_unique<Platform>();
Platform::CreateMainThreadAndInitialize(platform.get());
// Bench each image file.
while (option < argc) {
const char* name = argv[option++];
// Read entire file content into |data| (a contiguous block of memory) then
// decode it to verify the image and record its ImageMeta data.
ImageMeta image = {name, 0, 0, 0, 0};
scoped_refptr<SharedBuffer> data = ReadFile(name);
DecodeImageData(data.get(), &image);
// Image decode bench for iterations.
double total_time = 0.0;
for (int i = 0; i < iterations; ++i) {
image.time = 0.0;
DecodeImageData(data.get(), &image);
total_time += image.time;
}
// Results to stdout.
double average_time = total_time / iterations;
printf("%f %f %s\n", total_time, average_time, name);
}
}
} // namespace blink
int main(int argc, char* argv[]) {
base::MessageLoop message_loop;
mojo::core::Init();
base::CommandLine::Init(argc, argv);
blink::ImageDecodeBenchMain(argc, argv);
return 0;
}