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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/platform/testing/DeferredImageDecodeBench.cpp
diff --git a/third_party/WebKit/Source/platform/testing/DeferredImageDecodeBench.cpp b/third_party/WebKit/Source/platform/testing/DeferredImageDecodeBench.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9f8108fe79e367bdd0dd2c642a762006c5557f7c
--- /dev/null
+++ b/third_party/WebKit/Source/platform/testing/DeferredImageDecodeBench.cpp
@@ -0,0 +1,473 @@
+// 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 deferred image decoders. Used to
+// perform a non-threaded/non-threaded, memory-to-memory image decode using
+// micro second accuracy clocks to measure image decode time. Optionally applies
+// color correction during image decoding on supported platforms (default off).
+// Usage:
+//
+// % ninja -C out/Release deferred_image_decode_bench &&
+// ./out/Release/deferred_image_decode_bench file [iterations]
+//
+// TODO(noel): Consider adding md5 checksum support to WTF. Use it to compute
+// the decoded image frame md5 and output that value.
+//
+// TODO(noel): Consider integrating this tool in Chrome telemetry for realz,
+// using the image corpii used to assess Blink image decode performance. Refer
+// to http://crbug.com/398235#c103 and http://crbug.com/258324#c5
+
+#include <memory>
+#include <thread>
+
+#include "base/command_line.h"
+#include "base/test/test_discardable_memory_allocator.h"
+#include "platform/SharedBuffer.h"
+#include "platform/graphics/DeferredImageDecoder.h"
+#include "platform/image-decoders/ImageDecoder.h"
+#include "platform/wtf/PassRefPtr.h"
+#include "platform/wtf/PtrUtil.h"
+#include "platform/wtf/WTF.h"
+#include "platform/wtf/allocator/Partitions.h"
+#include "public/platform/Platform.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkImage.h"
+#include "ui/gfx/test/icc_profiles.h"
+
+#include <sys/stat.h>
+
+#if defined(_WIN32)
+#include <mmsystem.h>
+#include <time.h>
+#define stat(x, y) _stat(x, y)
+typedef struct _stat sttype;
+#else
+#include <sys/time.h>
+typedef struct stat sttype;
+#endif
+
+namespace blink {
+
+namespace {
+
+#if defined(_WIN32)
+
+// There is no real platform support herein, so adopt the WIN32 performance
+// counter from WTF
+// http://trac.webkit.org/browser/trunk/Source/WTF/wtf/CurrentTime.cpp?rev=152438
+
+static double LowResUTCTime() {
+ FILETIME file_time;
+ GetSystemTimeAsFileTime(&file_time);
+
+ // As per Windows documentation for FILETIME, copy the resulting FILETIME
+ // structure to a ULARGE_INTEGER structure using memcpy (using memcpy instead
+ // of direct assignment can prevent alignment faults on 64-bit Windows).
+ ULARGE_INTEGER date_time;
+ memcpy(&date_time, &file_time, sizeof(date_time));
+
+ // Number of 100 nanosecond between January 1, 1601 and January 1, 1970.
+ static const ULONGLONG kEpochBias = 116444736000000000ULL;
+ // Windows file times are in 100s of nanoseconds.
+ static const double kHundredsOfNanosecondsPerMillisecond = 10000;
+ return (date_time.QuadPart - kEpochBias) /
+ kHundredsOfNanosecondsPerMillisecond;
+}
+
+static LARGE_INTEGER g_qpc_frequency;
+static bool g_synced_time;
+
+static double HighResUpTime() {
+ // We use QPC, but only after sanity checking its result, due to bugs:
+ // http://support.microsoft.com/kb/274323
+ // http://support.microsoft.com/kb/895980
+ // http://msdn.microsoft.com/en-us/library/ms644904.aspx ("you can get
+ // different results on different processors due to bugs in the basic
+ // input/output system (BIOS) or the hardware abstraction layer (HAL).").
+
+ static LARGE_INTEGER qpc_last;
+ static DWORD tick_count_last;
+ static bool inited;
+
+ LARGE_INTEGER qpc;
+ QueryPerformanceCounter(&qpc);
+ DWORD tick_count = GetTickCount();
+
+ if (inited) {
+ __int64 qpc_elapsed =
+ ((qpc.QuadPart - qpc_last.QuadPart) * 1000) / g_qpc_frequency.QuadPart;
+ __int64 tick_count_elapsed;
+ if (tick_count >= tick_count_last) {
+ tick_count_elapsed = (tick_count - tick_count_last);
+ } else {
+ __int64 tick_count_large = tick_count + 0x100000000I64;
+ tick_count_elapsed = tick_count_large - tick_count_last;
+ }
+
+ // Force a re-sync if QueryPerformanceCounter differs from GetTickCount() by
+ // more than 500ms. (The 500ms value is from
+ // http://support.microsoft.com/kb/274323).
+ __int64 diff = tick_count_elapsed - qpc_elapsed;
+ if (diff > 500 || diff < -500)
+ g_synced_time = false;
+ } else {
+ inited = true;
+ }
+
+ qpc_last = qpc;
+ tick_count_last = tick_count;
+
+ return (1000.0 * qpc.QuadPart) /
+ static_cast<double>(g_qpc_frequency.QuadPart);
+}
+
+static bool QpcAvailable() {
+ static bool available;
+ static bool checked;
+
+ if (checked)
+ return available;
+
+ available = QueryPerformanceFrequency(&g_qpc_frequency);
+ checked = true;
+ return available;
+}
+
+static double GetCurrentTime() {
+ // Use a combination of ftime and QueryPerformanceCounter.
+ // ftime returns the information we want, but doesn't have sufficient
+ // resolution. QueryPerformanceCounter has high resolution, but is only
+ // usable to measure time intervals. To combine them, we call ftime and
+ // QueryPerformanceCounter initially. Later calls will use
+ // QueryPerformanceCounter by itself, adding the delta to the saved ftime. We
+ // periodically re-sync to correct for drift.
+ static double sync_low_res_utc_time;
+ static double sync_high_res_up_time;
+ static double last_utc_time;
+
+ double low_res_time = LowResUTCTime();
+ if (!QpcAvailable())
+ return low_res_time * (1.0 / 1000.0);
+
+ double high_res_time = HighResUpTime();
+ if (!g_synced_time) {
+ timeBeginPeriod(1); // increase time resolution around low-res time getter
+ sync_low_res_utc_time = low_res_time = LowResUTCTime();
+ timeEndPeriod(1); // restore time resolution
+ sync_high_res_up_time = high_res_time;
+ g_synced_time = true;
+ }
+
+ double high_res_elapsed = high_res_time - sync_high_res_up_time;
+ double utc = sync_low_res_utc_time + high_res_elapsed;
+
+ // Force a clock re-sync if we've drifted.
+ double low_res_elapsed = low_res_time - sync_low_res_utc_time;
+ const double kMaximumAllowedDriftMsec =
+ 15.625 * 2.0; // 2x the typical low-res accuracy
+ if (fabs(high_res_elapsed - low_res_elapsed) > kMaximumAllowedDriftMsec)
+ g_synced_time = false;
+
+ // Make sure time doesn't run backwards (only correct if the difference is < 2
+ // seconds, since DST or clock changes could occur).
+ const double kBackwardTimeLimit = 2000.0;
+ if (utc < last_utc_time && (last_utc_time - utc) < kBackwardTimeLimit)
+ return last_utc_time * (1.0 / 1000.0);
+
+ last_utc_time = utc;
+ return utc * (1.0 / 1000.0);
+}
+
+#else
+
+static double GetCurrentTime() {
+ struct timeval now;
+ gettimeofday(&now, 0);
+ return now.tv_sec + now.tv_usec * (1.0 / 1000000.0);
+}
+
+#endif
+
+PassRefPtr<SharedBuffer> ReadFile(const char* file_name) {
+ FILE* fp = fopen(file_name, "rb");
+ if (!fp) {
+ fprintf(stderr, "Can't open file %s\n", file_name);
+ exit(2);
+ }
+
+ sttype s;
+ stat(file_name, &s);
+ size_t file_size = s.st_size;
+ if (s.st_size <= 0)
+ return SharedBuffer::Create();
+
+ std::unique_ptr<unsigned char[]> buffer =
+ WrapArrayUnique(new unsigned char[file_size]);
+ if (file_size != fread(buffer.get(), 1, file_size, fp)) {
+ fprintf(stderr, "Error reading file %s\n", file_name);
+ exit(2);
+ }
+
+ fclose(fp);
+ return SharedBuffer::Create(buffer.get(), file_size);
+}
+
+bool ReadPixels(SkImage* image) {
+ SkBitmap bitmap;
+ bitmap.allocPixels(
+ SkImageInfo::MakeN32Premul(image->width(), image->width()));
+ return image->readPixels(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes(),
+ 0, 0);
+}
+
+struct RealDecodeImages {
+ sk_sp<SkImage>* images;
+ size_t* frame_index_arr;
+ size_t count;
+ size_t avail;
+};
+
+void RealDecode(RealDecodeImages* real_decoded_images) {
+ size_t to_decod_index = 0;
+ size_t current_frame_index = 0;
+
+ while (true) {
+ bool ret = true;
+ bool need_decode = false;
+
+ for (size_t i = to_decod_index; i < real_decoded_images->avail; i++) {
+ if (real_decoded_images->frame_index_arr[i] != current_frame_index) {
+ current_frame_index = real_decoded_images->frame_index_arr[i];
+ break;
+ }
+ need_decode = true;
+ to_decod_index = i;
+ }
+
+ if (need_decode) {
+ sk_sp<SkImage>* image = real_decoded_images->images + to_decod_index;
+ if (image->get()) {
+ ret = ReadPixels(image->get());
+ }
+ ++to_decod_index;
+ }
+
+ if (to_decod_index == real_decoded_images->count) {
+ if (!ret) {
+ fprintf(stderr, "RealDecode failed!\n");
+ exit(3);
+ }
+ break;
+ }
+ }
+}
+
+bool DecodeImageData(SharedBuffer* data,
+ bool color_correction,
+ size_t packet_size) {
+ std::unique_ptr<ImageDecoder> info_decoder = ImageDecoder::Create(
+ data, true, ImageDecoder::kAlphaPremultiplied,
+ color_correction ? ColorBehavior::TransformToTargetForTesting()
+ : ColorBehavior::Ignore());
+ bool all_data_received = true;
+ info_decoder->SetData(data, all_data_received);
+
+ int frame_count = info_decoder->FrameCount();
+
+ if (!packet_size) {
+ std::unique_ptr<DeferredImageDecoder> decoder =
+ DeferredImageDecoder::Create(
+ data, false, ImageDecoder::kAlphaPremultiplied,
+ color_correction ? ColorBehavior::TransformToTargetForTesting()
+ : ColorBehavior::Ignore());
+
+ bool all_data_received = true;
+ decoder->SetData(data, all_data_received);
+
+ int frame_count = decoder->FrameCount();
+ for (int i = 0; i < frame_count; ++i) {
+ sk_sp<SkImage> image = decoder->CreateFrameAtIndex(i);
+ if (!image)
+ return false;
+ bool ret = ReadPixels(image.get());
+ if (!ret) {
+ fprintf(stderr, "DecodeImageData failed!\n");
+ exit(3);
+ }
+ }
+
+ return true;
+ }
+
+ size_t cirle_count = data->size() / packet_size + data->size() % packet_size;
+ size_t images_count = frame_count * cirle_count;
+ sk_sp<SkImage>* images = new sk_sp<SkImage>[images_count];
+ size_t* frame_index_arr = new size_t[images_count];
+ memset(frame_index_arr, 0, sizeof(size_t[images_count]));
+ size_t image_index = 0;
+
+ RealDecodeImages real_decode_images{images, frame_index_arr, images_count, 0};
+
+ std::thread real_decode_thread(RealDecode, &real_decode_images);
+
+ RefPtr<SharedBuffer> packet_data = SharedBuffer::Create();
+ size_t position = 0;
+ size_t next_frame_to_decode = 0;
+
+ std::unique_ptr<DeferredImageDecoder> pakcet_decoder;
+
+ while (true) {
+ const char* packet;
+ size_t length = data->GetSomeData(packet, position);
+
+ length = std::min(length, packet_size);
+ packet_data->Append(packet, length);
+ position += length;
+
+ bool all_data_received = position == data->size();
+ if (!pakcet_decoder) {
+ pakcet_decoder = DeferredImageDecoder::Create(
+ packet_data, false, ImageDecoder::kAlphaPremultiplied,
+ color_correction ? ColorBehavior::TransformToTargetForTesting()
+ : ColorBehavior::Ignore());
+ }
+ if (!pakcet_decoder) {
+ continue;
+ }
+
+ pakcet_decoder->SetData(packet_data.Get(), all_data_received);
+
+ size_t frame_count = pakcet_decoder->FrameCount();
+ for (size_t i = next_frame_to_decode; i < frame_count; ++i) {
+ images[image_index] = pakcet_decoder->CreateFrameAtIndex(i);
+ frame_index_arr[image_index] = i;
+ ++image_index;
+ if (pakcet_decoder->FrameIsCompleteAtIndex(i)) {
+ next_frame_to_decode = i + 1;
+ real_decode_images.avail = image_index;
+ }
+ }
+
+ if (all_data_received)
+ break;
+ }
+
+ real_decode_images.count = real_decode_images.avail;
+
+ real_decode_thread.join();
+
+ delete[] images;
+ delete[] frame_index_arr;
+
+ return true;
+}
+
+} // namespace
+
+int Main(int argc, char* argv[]) {
+ base::CommandLine::Init(argc, argv);
+
+ base::TestDiscardableMemoryAllocator memoryAllocator;
+ base::DiscardableMemoryAllocator::SetInstance(&memoryAllocator);
+
+ WTF::Partitions::Initialize(nullptr);
+
+ // If the platform supports color correction, allow it to be controlled.
+
+ bool apply_color_correction = false;
+
+ if (argc >= 2 && strcmp(argv[1], "--color-correct") == 0) {
+ apply_color_correction = (--argc, ++argv, true);
+ gfx::ICCProfile profile = gfx::ICCProfileForTestingColorSpin();
+ ColorBehavior::SetGlobalTargetColorProfile(profile);
+ }
+
+ if (argc < 2) {
+ fprintf(stderr,
+ "Usage: %s [--color-correct] file [iterations] [packetSize]\n",
+ argv[0]);
+ exit(1);
+ }
+
+ // Control decode bench iterations and packet size.
+
+ size_t iterations = 1;
+ if (argc >= 3) {
+ char* end = 0;
+ iterations = strtol(argv[2], &end, 10);
+ if (*end != '\0' || !iterations) {
+ fprintf(stderr,
+ "Second argument should be number of iterations. "
+ "The default is 1. You supplied %s\n",
+ argv[2]);
+ exit(1);
+ }
+ }
+
+ size_t packet_size = 0;
+ if (argc >= 4) {
+ char* end = 0;
+ packet_size = strtol(argv[3], &end, 10);
+ if (*end != '\0') {
+ fprintf(stderr,
+ "Third argument should be packet size. Default is "
+ "0, meaning to decode the entire image in one packet. You "
+ "supplied %s\n",
+ argv[3]);
+ exit(1);
+ }
+ }
+
+ // Create a web platform. blink::Platform can't be used directly because its
+ // constructor is protected.
+
+ class WebPlatform : public blink::Platform {};
+
+ Platform::Initialize(new WebPlatform());
+
+ // Read entire file content to data, and consolidate the SharedBuffer data
+ // segments into one, contiguous block of memory.
+
+ RefPtr<SharedBuffer> data = ReadFile(argv[1]);
+ if (!data.Get() || !data->size()) {
+ fprintf(stderr, "Error reading image data from [%s]\n", argv[1]);
+ exit(2);
+ }
+
+ data->Data();
+
+ // Warm-up: throw out the first iteration for more consistent results.
+
+ if (!DecodeImageData(data.Get(), apply_color_correction, packet_size)) {
+ fprintf(stderr, "Image decode failed [%s]\n", argv[1]);
+ exit(3);
+ }
+
+ // Image decode bench for iterations.
+
+ double total_time = 0.0;
+
+ for (size_t i = 0; i < iterations; ++i) {
+ double start_time = GetCurrentTime();
+ bool decoded =
+ DecodeImageData(data.Get(), apply_color_correction, packet_size);
+ double elapsed_time = GetCurrentTime() - start_time;
+ total_time += elapsed_time;
+ if (!decoded) {
+ fprintf(stderr, "Image decode failed [%s]\n", argv[1]);
+ exit(3);
+ }
+ }
+
+ // Results to stdout.
+ double average_time = total_time / static_cast<double>(iterations);
+ printf("%f %f\n", total_time, average_time);
+ return 0;
+}
+
+} // namespace blink
+
+int main(int argc, char* argv[]) {
+ return blink::Main(argc, argv);
+}
« 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