Bug 1411984 - Use buffered IO in the content process when writing print data for IPC; r=haik
authorAlex Gaynor <agaynor@mozilla.com>
Thu, 26 Oct 2017 15:08:39 -0400
changeset 443176 19903553695c71e3b9df500e1255b83834d4eaa1
parent 443175 b0d6deea2bca0a798a2966630f7cfc25e494507c
child 443177 d89d6c2186448de68ed9ccc3abb8c902322cf527
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershaik
bugs1411984
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1411984 - Use buffered IO in the content process when writing print data for IPC; r=haik MozReview-Commit-ID: DJuOP2wtku5
layout/printing/DrawEventRecorder.h
--- a/layout/printing/DrawEventRecorder.h
+++ b/layout/printing/DrawEventRecorder.h
@@ -2,70 +2,117 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layout_printing_DrawEventRecorder_h
 #define mozilla_layout_printing_DrawEventRecorder_h
 
+#include <memory>
+
 #include "mozilla/gfx/DrawEventRecorder.h"
 #include "mozilla/gfx/RecordingTypes.h"
 #include "prio.h"
 
 namespace mozilla {
 namespace layout {
 
 class PRFileDescStream : public mozilla::gfx::EventStream {
+  // Most writes, as seen in the print IPC use case, are very small (<32 bytes),
+  // with a small number of very large (>40KB) writes. Writes larger than this
+  // value are not buffered.
+  static const size_t kBufferSize = 1024;
 public:
-  PRFileDescStream() : mFd(nullptr), mGood(true) {}
+  PRFileDescStream() : mFd(nullptr), mBuffer(nullptr), mBufferPos(0),
+                       mGood(true) {}
 
   void OpenFD(PRFileDesc* aFd) {
     MOZ_ASSERT(!IsOpen());
     mFd = aFd;
     mGood = true;
+    mBuffer.reset(new uint8_t[kBufferSize]);
+    mBufferPos = 0;
   }
 
   void Close() {
+    Flush();
     PR_Close(mFd);
     mFd = nullptr;
+    mBuffer.reset();
+    mBufferPos = 0;
   }
 
   bool IsOpen() {
     return mFd != nullptr;
   }
 
   void Flush() {
-    // For std::ostream this flushes any internal buffers. PRFileDesc's IO isn't
-    // buffered, so nothing to do here.
+    // We need to be API compatible with std::ostream, and so we silently handle
+    // flushes on a closed FD.
+    if (IsOpen() && mBufferPos > 0) {
+      PR_Write(mFd, static_cast<const void*>(mBuffer.get()), mBufferPos);
+      mBufferPos = 0;
+    }
   }
 
   void Seek(PRInt32 aOffset, PRSeekWhence aWhence) {
+    Flush();
     PR_Seek(mFd, aOffset, aWhence);
   }
 
   void write(const char* aData, size_t aSize) {
-    // We need to be API compatible with std::ostream, and so we silently handle
-    // writes on a closed FD.
+    // See comment in Flush().
     if (IsOpen()) {
-      PR_Write(mFd, static_cast<const void*>(aData), aSize);
+      // If we're writing more data than could ever fit in our buffer, flush the
+      // buffer and write directly.
+      if (aSize > kBufferSize) {
+        Flush();
+        PR_Write(mFd, static_cast<const void*>(aData), aSize);
+      // If our write could fit in our buffer, but doesn't because the buffer is
+      // partially full, write to the buffer, flush the buffer, and then write
+      // the rest of the data to the buffer.
+      } else if (aSize > AvailableBufferSpace()) {
+        size_t length = AvailableBufferSpace();
+        WriteToBuffer(aData, length);
+        Flush();
+
+        MOZ_ASSERT(aSize <= kBufferSize);
+        WriteToBuffer(aData + length, aSize - length);
+      // Write fits in the buffer.
+      } else {
+        WriteToBuffer(aData, aSize);
+      }
     }
   }
 
   void read(char* aOut, size_t aSize) {
+    Flush();
     PRInt32 res = PR_Read(mFd, static_cast<void*>(aOut), aSize);
     mGood = res >= 0 && ((size_t)res == aSize);
   }
 
   bool good() {
     return mGood;
   }
 
 private:
+  size_t AvailableBufferSpace() {
+    return kBufferSize - mBufferPos;
+  }
+
+  void WriteToBuffer(const char* aData, size_t aSize) {
+    MOZ_ASSERT(aSize <= AvailableBufferSpace());
+    memcpy(mBuffer.get() + mBufferPos, aData, aSize);
+    mBufferPos += aSize;
+  }
+
   PRFileDesc* mFd;
+  std::unique_ptr<uint8_t[]> mBuffer;
+  size_t mBufferPos;
   bool mGood;
 };
 
 class DrawEventRecorderPRFileDesc : public gfx::DrawEventRecorderPrivate
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderPRFileDesc, override)
   explicit DrawEventRecorderPRFileDesc() { };