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

Side by Side Diff: third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp

Issue 2039673002: Track performance of toBlob and its complete timeout delay (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: minor clean up Created 4 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 unified diff | Download patch
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 #include "core/html/canvas/CanvasAsyncBlobCreator.h" 5 #include "core/html/canvas/CanvasAsyncBlobCreator.h"
6 6
7 #include "core/fileapi/Blob.h" 7 #include "core/fileapi/Blob.h"
8 #include "platform/Histogram.h"
8 #include "platform/ThreadSafeFunctional.h" 9 #include "platform/ThreadSafeFunctional.h"
9 #include "platform/graphics/ImageBuffer.h" 10 #include "platform/graphics/ImageBuffer.h"
10 #include "platform/image-encoders/JPEGImageEncoder.h" 11 #include "platform/image-encoders/JPEGImageEncoder.h"
11 #include "platform/image-encoders/PNGImageEncoder.h" 12 #include "platform/image-encoders/PNGImageEncoder.h"
12 #include "platform/threading/BackgroundTaskRunner.h" 13 #include "platform/threading/BackgroundTaskRunner.h"
13 #include "public/platform/Platform.h" 14 #include "public/platform/Platform.h"
14 #include "public/platform/WebScheduler.h" 15 #include "public/platform/WebScheduler.h"
15 #include "public/platform/WebTaskRunner.h" 16 #include "public/platform/WebTaskRunner.h"
16 #include "public/platform/WebThread.h" 17 #include "public/platform/WebThread.h"
17 #include "public/platform/WebTraceLocation.h" 18 #include "public/platform/WebTraceLocation.h"
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 } else if (mimeType == "image/webp") { 72 } else if (mimeType == "image/webp") {
72 mimeTypeEnum = CanvasAsyncBlobCreator::MimeTypeWebp; 73 mimeTypeEnum = CanvasAsyncBlobCreator::MimeTypeWebp;
73 } else { 74 } else {
74 mimeTypeEnum = CanvasAsyncBlobCreator::NumberOfMimeTypeSupported; 75 mimeTypeEnum = CanvasAsyncBlobCreator::NumberOfMimeTypeSupported;
75 } 76 }
76 return mimeTypeEnum; 77 return mimeTypeEnum;
77 } 78 }
78 79
79 } // anonymous namespace 80 } // anonymous namespace
80 81
81 CanvasAsyncBlobCreator* CanvasAsyncBlobCreator::create(DOMUint8ClampedArray* unp remultipliedRGBAImageData, const String& mimeType, const IntSize& size, BlobCall back* callback) 82 CanvasAsyncBlobCreator* CanvasAsyncBlobCreator::create(DOMUint8ClampedArray* unp remultipliedRGBAImageData, const String& mimeType, const IntSize& size, BlobCall back* callback, double startTime)
82 { 83 {
83 return new CanvasAsyncBlobCreator(unpremultipliedRGBAImageData, convertMimeT ypeStringToEnum(mimeType), size, callback); 84 return new CanvasAsyncBlobCreator(unpremultipliedRGBAImageData, convertMimeT ypeStringToEnum(mimeType), size, callback, startTime);
84 } 85 }
85 86
86 CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(DOMUint8ClampedArray* data, MimeT ype mimeType, const IntSize& size, BlobCallback* callback) 87 CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(DOMUint8ClampedArray* data, MimeT ype mimeType, const IntSize& size, BlobCallback* callback, double startTime)
87 : m_data(data) 88 : m_data(data)
88 , m_size(size) 89 , m_size(size)
89 , m_mimeType(mimeType) 90 , m_mimeType(mimeType)
90 , m_callback(callback) 91 , m_callback(callback)
92 , m_startTime(startTime)
91 { 93 {
92 ASSERT(m_data->length() == (unsigned) (size.height() * size.width() * 4)); 94 ASSERT(m_data->length() == (unsigned) (size.height() * size.width() * 4));
93 m_encodedImage = adoptPtr(new Vector<unsigned char>()); 95 m_encodedImage = adoptPtr(new Vector<unsigned char>());
94 m_pixelRowStride = size.width() * NumChannelsPng; 96 m_pixelRowStride = size.width() * NumChannelsPng;
95 m_idleTaskStatus = IdleTaskNotSupported; 97 m_idleTaskStatus = IdleTaskNotSupported;
96 m_numRowsCompleted = 0; 98 m_numRowsCompleted = 0;
97 } 99 }
98 100
99 CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator() 101 CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator()
100 { 102 {
(...skipping 10 matching lines...) Expand all
111 } else if (m_mimeType == MimeTypeJpeg) { 113 } else if (m_mimeType == MimeTypeJpeg) {
112 this->scheduleInitiateJpegEncoding(quality); 114 this->scheduleInitiateJpegEncoding(quality);
113 } else { 115 } else {
114 // Progressive encoding is only applicable to png and jpeg image for mat, 116 // Progressive encoding is only applicable to png and jpeg image for mat,
115 // and thus idle tasks scheduling can only be applied to these image formats. 117 // and thus idle tasks scheduling can only be applied to these image formats.
116 // TODO(xlai): Progressive encoding on webp image formats (crbug.com /571399) 118 // TODO(xlai): Progressive encoding on webp image formats (crbug.com /571399)
117 ASSERT_NOT_REACHED(); 119 ASSERT_NOT_REACHED();
118 } 120 }
119 // We post the below task to check if the above idle task isn't late. 121 // We post the below task to check if the above idle task isn't late.
120 // There's no risk of concurrency as both tasks are on main thread. 122 // There's no risk of concurrency as both tasks are on main thread.
121 this->postDelayedTaskToMainThread(BLINK_FROM_HERE, bind(&CanvasAsyncBlob Creator::idleTaskStartTimeoutEvent, this, quality), IdleTaskStartTimeoutDelay); 123 double startTime = WTF::monotonicallyIncreasingTime();
124 this->postDelayedTaskToMainThread(BLINK_FROM_HERE, bind(&CanvasAsyncBlob Creator::idleTaskStartTimeoutEvent, this, quality, startTime), IdleTaskStartTime outDelay);
122 } else if (m_mimeType == MimeTypeWebp) { 125 } else if (m_mimeType == MimeTypeWebp) {
123 BackgroundTaskRunner::TaskSize taskSize = (m_size.height() * m_size.widt h() >= LongTaskImageSizeThreshold) ? BackgroundTaskRunner::TaskSizeLongRunningTa sk : BackgroundTaskRunner::TaskSizeShortRunningTask; 126 BackgroundTaskRunner::TaskSize taskSize = (m_size.height() * m_size.widt h() >= LongTaskImageSizeThreshold) ? BackgroundTaskRunner::TaskSizeLongRunningTa sk : BackgroundTaskRunner::TaskSizeShortRunningTask;
124 BackgroundTaskRunner::postOnBackgroundThread(BLINK_FROM_HERE, threadSafe Bind(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, wrapCrossThreadPersist ent(this), quality), taskSize); 127 BackgroundTaskRunner::postOnBackgroundThread(BLINK_FROM_HERE, threadSafe Bind(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, wrapCrossThreadPersist ent(this), quality), taskSize);
125 } 128 }
126 } 129 }
127 130
128 void CanvasAsyncBlobCreator::scheduleInitiateJpegEncoding(const double& quality) 131 void CanvasAsyncBlobCreator::scheduleInitiateJpegEncoding(const double& quality)
129 { 132 {
130 Platform::current()->mainThread()->scheduler()->postIdleTask(BLINK_FROM_HERE , bind<double>(&CanvasAsyncBlobCreator::initiateJpegEncoding, this, quality)); 133 Platform::current()->mainThread()->scheduler()->postIdleTask(BLINK_FROM_HERE , bind<double>(&CanvasAsyncBlobCreator::initiateJpegEncoding, this, quality));
131 } 134 }
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 256
254 void CanvasAsyncBlobCreator::createBlobAndInvokeCallback() 257 void CanvasAsyncBlobCreator::createBlobAndInvokeCallback()
255 { 258 {
256 ASSERT(isMainThread()); 259 ASSERT(isMainThread());
257 Blob* resultBlob = Blob::create(m_encodedImage->data(), m_encodedImage->size (), convertMimeTypeEnumToString(m_mimeType)); 260 Blob* resultBlob = Blob::create(m_encodedImage->data(), m_encodedImage->size (), convertMimeTypeEnumToString(m_mimeType));
258 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H ERE, bind(&BlobCallback::handleEvent, m_callback, resultBlob)); 261 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H ERE, bind(&BlobCallback::handleEvent, m_callback, resultBlob));
259 // Since toBlob is done, timeout events are no longer needed. So we clear 262 // Since toBlob is done, timeout events are no longer needed. So we clear
260 // non-GC members to allow teardown of CanvasAsyncBlobCreator. 263 // non-GC members to allow teardown of CanvasAsyncBlobCreator.
261 m_data.clear(); 264 m_data.clear();
262 m_callback.clear(); 265 m_callback.clear();
266 double elapsedTime = WTF::monotonicallyIncreasingTime() - m_startTime;
267 if (m_mimeType == MimeTypePng) {
268 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, toBlobPNGCounter, new CustomCountHistogram("Blink.Canvas.ToBlob.PNG", 0, 10000000, 50));
269 toBlobPNGCounter.count(elapsedTime * 1000000.0);
270 } else if (m_mimeType == MimeTypeJpeg) {
271 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, toBlobJPEGCounter, new CustomCountHistogram("Blink.Canvas.ToBlob.JPEG", 0, 10000000, 50));
272 toBlobJPEGCounter.count(elapsedTime * 1000000.0);
273 } else {
274 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, toBlobWEBPCounter, new CustomCountHistogram("Blink.Canvas.ToBlob.WEBP", 0, 10000000, 50));
275 toBlobWEBPCounter.count(elapsedTime * 1000000.0);
276 }
263 } 277 }
264 278
265 void CanvasAsyncBlobCreator::createNullAndInvokeCallback() 279 void CanvasAsyncBlobCreator::createNullAndInvokeCallback()
266 { 280 {
267 ASSERT(isMainThread()); 281 ASSERT(isMainThread());
268 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H ERE, bind(&BlobCallback::handleEvent, m_callback, nullptr)); 282 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H ERE, bind(&BlobCallback::handleEvent, m_callback, nullptr));
269 // Since toBlob is done (failed), timeout events are no longer needed. So we 283 // Since toBlob is done (failed), timeout events are no longer needed. So we
270 // clear non-GC members to allow teardown of CanvasAsyncBlobCreator. 284 // clear non-GC members to allow teardown of CanvasAsyncBlobCreator.
271 m_data.clear(); 285 m_data.clear();
272 m_callback.clear(); 286 m_callback.clear();
(...skipping 25 matching lines...) Expand all
298 bool CanvasAsyncBlobCreator::initializeJpegStruct(double quality) 312 bool CanvasAsyncBlobCreator::initializeJpegStruct(double quality)
299 { 313 {
300 m_jpegEncoderState = JPEGImageEncoderState::create(m_size, quality, m_encode dImage.get()); 314 m_jpegEncoderState = JPEGImageEncoderState::create(m_size, quality, m_encode dImage.get());
301 if (!m_jpegEncoderState) { 315 if (!m_jpegEncoderState) {
302 this->createNullAndInvokeCallback(); 316 this->createNullAndInvokeCallback();
303 return false; 317 return false;
304 } 318 }
305 return true; 319 return true;
306 } 320 }
307 321
308 void CanvasAsyncBlobCreator::idleTaskStartTimeoutEvent(double quality) 322 void CanvasAsyncBlobCreator::recordTimeoutSwitch(IdleTaskTimeoutType type)
309 { 323 {
324 if (m_mimeType == MimeTypePng) {
325 DEFINE_THREAD_SAFE_STATIC_LOCAL(EnumerationHistogram, idleTaskTimeoutSwi tchPNG, new EnumerationHistogram("Canvas.ToBlob.IdleTaskTimeoutSwitch.PNG", Idle TaskTimeoutSupported));
326 idleTaskTimeoutSwitchPNG.count(type);
327 } else {
328 DEFINE_THREAD_SAFE_STATIC_LOCAL(EnumerationHistogram, idleTaskTimeoutSwi tchJPEG, new EnumerationHistogram("Canvas.ToBlob.IdleTaskTimeoutSwitch.JPEG", Id leTaskTimeoutSupported));
329 idleTaskTimeoutSwitchJPEG.count(type);
330 }
331 }
332
333 void CanvasAsyncBlobCreator::idleTaskStartTimeoutEvent(double quality, double st artTime)
334 {
335 double elapsedTime = WTF::monotonicallyIncreasingTime() - startTime;
336 if (m_mimeType == MimeTypePng) {
337 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, toBlobPNGStartTime outCounter, new CustomCountHistogram("Blink.Canvas.ToBlobTimeoutDuration.PNG.Sta rt", 0, 10000000, 50));
338 toBlobPNGStartTimeoutCounter.count(elapsedTime * 1000000.0);
339 } else if (m_mimeType == MimeTypeJpeg) {
340 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, toBlobJPEGStartTim eoutCounter, new CustomCountHistogram("Blink.Canvas.ToBlobTimeoutDuration.JPEG.S tart", 0, 10000000, 50));
341 toBlobJPEGStartTimeoutCounter.count(elapsedTime * 1000000.0);
342 } else {
343 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, toBlobWEBPStartTim eoutCounter, new CustomCountHistogram("Blink.Canvas.ToBlobTimeoutDuration.WEBP.S tart", 0, 10000000, 50));
344 toBlobWEBPStartTimeoutCounter.count(elapsedTime * 1000000.0);
345 }
xidachen 2016/06/07 20:46:29 Is this recording meaningful now that we change to
346
310 if (m_idleTaskStatus == IdleTaskStarted) { 347 if (m_idleTaskStatus == IdleTaskStarted) {
311 // Even if the task started quickly, we still want to ensure completion 348 // Even if the task started quickly, we still want to ensure completion
312 this->postDelayedTaskToMainThread(BLINK_FROM_HERE, bind(&CanvasAsyncBlob Creator::idleTaskCompleteTimeoutEvent, this), IdleTaskCompleteTimeoutDelay); 349 startTime = WTF::monotonicallyIncreasingTime();
350 this->postDelayedTaskToMainThread(BLINK_FROM_HERE, bind(&CanvasAsyncBlob Creator::idleTaskCompleteTimeoutEvent, this, startTime), IdleTaskCompleteTimeout Delay);
313 } else if (m_idleTaskStatus == IdleTaskNotStarted) { 351 } else if (m_idleTaskStatus == IdleTaskNotStarted) {
314 // If the idle task does not start after a delay threshold, we will 352 // If the idle task does not start after a delay threshold, we will
315 // force it to happen on main thread (even though it may cause more 353 // force it to happen on main thread (even though it may cause more
316 // janks) to prevent toBlob being postponed forever in extreme cases. 354 // janks) to prevent toBlob being postponed forever in extreme cases.
317 m_idleTaskStatus = IdleTaskSwitchedToMainThreadTask; 355 m_idleTaskStatus = IdleTaskSwitchedToMainThreadTask;
318 signalTaskSwitchInStartTimeoutEventForTesting(); 356 signalTaskSwitchInStartTimeoutEventForTesting();
319 357
320 if (m_mimeType == MimeTypePng) { 358 if (m_mimeType == MimeTypePng) {
321 if (initializePngStruct()) { 359 if (initializePngStruct()) {
360 recordTimeoutSwitch(IdleTaskStartTimeout);
322 Platform::current()->mainThread()->getWebTaskRunner()->postTask( BLINK_FROM_HERE, bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, this)) ; 361 Platform::current()->mainThread()->getWebTaskRunner()->postTask( BLINK_FROM_HERE, bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, this)) ;
323 } else { 362 } else {
324 // Failing in initialization of png struct 363 // Failing in initialization of png struct
325 this->signalAlternativeCodePathFinishedForTesting(); 364 this->signalAlternativeCodePathFinishedForTesting();
326 } 365 }
327 } else { 366 } else {
328 ASSERT(m_mimeType == MimeTypeJpeg); 367 ASSERT(m_mimeType == MimeTypeJpeg);
329 if (initializeJpegStruct(quality)) { 368 if (initializeJpegStruct(quality)) {
369 recordTimeoutSwitch(IdleTaskStartTimeout);
330 Platform::current()->mainThread()->getWebTaskRunner()->postTask( BLINK_FROM_HERE, bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, this) ); 370 Platform::current()->mainThread()->getWebTaskRunner()->postTask( BLINK_FROM_HERE, bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, this) );
331 } else { 371 } else {
332 // Failing in initialization of jpeg struct 372 // Failing in initialization of jpeg struct
333 this->signalAlternativeCodePathFinishedForTesting(); 373 this->signalAlternativeCodePathFinishedForTesting();
334 } 374 }
335 } 375 }
336 } else { 376 } else {
337 ASSERT(m_idleTaskStatus == IdleTaskFailed || m_idleTaskStatus == IdleTas kCompleted); 377 ASSERT(m_idleTaskStatus == IdleTaskFailed || m_idleTaskStatus == IdleTas kCompleted);
338 this->signalAlternativeCodePathFinishedForTesting(); 378 this->signalAlternativeCodePathFinishedForTesting();
339 } 379 }
340 380
341 } 381 }
342 382
343 void CanvasAsyncBlobCreator::idleTaskCompleteTimeoutEvent() 383 void CanvasAsyncBlobCreator::idleTaskCompleteTimeoutEvent(double startTime)
344 { 384 {
345 ASSERT(m_idleTaskStatus != IdleTaskNotStarted); 385 ASSERT(m_idleTaskStatus != IdleTaskNotStarted);
386 double elapsedTime = WTF::monotonicallyIncreasingTime() - startTime;
387 if (m_mimeType == MimeTypePng) {
388 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, toBlobPNGCompleteT imeoutCounter, new CustomCountHistogram("Blink.Canvas.ToBlobTimeoutDuration.PNG. Complete", 0, 10000000, 50));
389 toBlobPNGCompleteTimeoutCounter.count(elapsedTime * 1000000.0);
390 } else if (m_mimeType == MimeTypeJpeg) {
391 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, toBlobJPEGComplete TimeoutCounter, new CustomCountHistogram("Blink.Canvas.ToBlobTimeoutDuration.JPE G.Complete", 0, 10000000, 50));
392 toBlobJPEGCompleteTimeoutCounter.count(elapsedTime * 1000000.0);
393 } else {
394 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, toBlobWEBPComplete TimeoutCounter, new CustomCountHistogram("Blink.Canvas.ToBlobTimeoutDuration.WEB P.Complete", 0, 10000000, 50));
395 toBlobWEBPCompleteTimeoutCounter.count(elapsedTime * 1000000.0);
396 }
346 397
347 if (m_idleTaskStatus == IdleTaskStarted) { 398 if (m_idleTaskStatus == IdleTaskStarted) {
348 // It has taken too long to complete for the idle task. 399 // It has taken too long to complete for the idle task.
349 m_idleTaskStatus = IdleTaskSwitchedToMainThreadTask; 400 m_idleTaskStatus = IdleTaskSwitchedToMainThreadTask;
350 signalTaskSwitchInCompleteTimeoutEventForTesting(); 401 signalTaskSwitchInCompleteTimeoutEventForTesting();
351 402
352 if (m_mimeType == MimeTypePng) { 403 if (m_mimeType == MimeTypePng) {
404 recordTimeoutSwitch(IdleTaskCompleteTimeout);
353 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLIN K_FROM_HERE, bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, this)); 405 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLIN K_FROM_HERE, bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, this));
354 } else { 406 } else {
355 ASSERT(m_mimeType == MimeTypeJpeg); 407 ASSERT(m_mimeType == MimeTypeJpeg);
408 recordTimeoutSwitch(IdleTaskCompleteTimeout);
356 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLIN K_FROM_HERE, bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, this)); 409 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLIN K_FROM_HERE, bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, this));
357 } 410 }
358 } else { 411 } else {
359 ASSERT(m_idleTaskStatus == IdleTaskFailed || m_idleTaskStatus == IdleTas kCompleted); 412 ASSERT(m_idleTaskStatus == IdleTaskFailed || m_idleTaskStatus == IdleTas kCompleted);
360 this->signalAlternativeCodePathFinishedForTesting(); 413 this->signalAlternativeCodePathFinishedForTesting();
361 } 414 }
362 } 415 }
363 416
364 void CanvasAsyncBlobCreator::postDelayedTaskToMainThread(const WebTraceLocation& location, std::unique_ptr<SameThreadClosure> task, double delayMs) 417 void CanvasAsyncBlobCreator::postDelayedTaskToMainThread(const WebTraceLocation& location, std::unique_ptr<SameThreadClosure> task, double delayMs)
365 { 418 {
366 DCHECK(isMainThread()); 419 DCHECK(isMainThread());
367 Platform::current()->mainThread()->getWebTaskRunner()->postDelayedTask(locat ion, std::move(task), delayMs); 420 Platform::current()->mainThread()->getWebTaskRunner()->postDelayedTask(locat ion, std::move(task), delayMs);
368 } 421 }
369 422
370 } // namespace blink 423 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698