SkDynamicMemoryWStream::detachAsData more memory efficent
authorHal Canary <halcanary@google.com>
Tue, 14 Mar 2017 19:52:12 +0000 (15:52 -0400)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Wed, 15 Mar 2017 12:54:49 +0000 (12:54 +0000)
I did some testing with very large datasets, and the difference in max
RSS is measurable and significant.

Change-Id: I6bb2f795d5b4f6ebdba42c3089dc85a278355d48
Reviewed-on: https://skia-review.googlesource.com/9686
Commit-Queue: Hal Canary <halcanary@google.com>
Reviewed-by: Ben Wagner <bungeman@google.com>
include/core/SkStream.h
src/core/SkStream.cpp
tests/StreamTest.cpp

index 10929a8..8df59af 100644 (file)
@@ -376,6 +376,9 @@ public:
     void copyTo(void* dst) const;
     void writeToStream(SkWStream* dst) const;
 
+    /** Equivalent to copyTo() followed by reset(), but may save memory use. */
+    void copyToAndReset(void* dst);
+
     /** Return the contents as SkData, and then reset the stream. */
     sk_sp<SkData> detachAsData();
 
index 1435dab..133df83 100644 (file)
@@ -570,15 +570,31 @@ void SkDynamicMemoryWStream::padToAlign4() {
     }
 }
 
+
+void SkDynamicMemoryWStream::copyToAndReset(void* ptr) {
+    // By looping through the source and freeing as we copy, we
+    // can reduce real memory use with large streams.
+    char* dst = reinterpret_cast<char*>(ptr);
+    Block* block = fHead;
+    while (block != nullptr) {
+        size_t len = block->written();
+        memcpy(dst, block->start(), len);
+        dst += len;
+        Block* next = block->fNext;
+        sk_free(block);
+        block = next;
+    }
+    fHead = fTail = nullptr;
+    fBytesWrittenBeforeTail = 0;
+}
+
 sk_sp<SkData> SkDynamicMemoryWStream::detachAsData() {
     const size_t size = this->bytesWritten();
     if (0 == size) {
         return SkData::MakeEmpty();
     }
-
     sk_sp<SkData> data = SkData::MakeUninitialized(size);
-    this->copyTo(data->writable_data());
-    this->reset(); // this is the "detach" part
+    this->copyToAndReset(data->writable_data());
     return data;
 }
 
index 2e476a1..8b5b2ae 100644 (file)
@@ -410,6 +410,26 @@ static void stream_copy_test(skiatest::Reporter* reporter,
     }
 }
 
+DEF_TEST(DynamicMemoryWStream_detachAsData, r) {
+    const char az[] = "abcdefghijklmnopqrstuvwxyz";
+    const unsigned N = 40000;
+    SkDynamicMemoryWStream dmws;
+    for (unsigned i = 0; i < N; ++i) {
+        dmws.writeText(az);
+    }
+    REPORTER_ASSERT(r, dmws.bytesWritten() == N * strlen(az));
+    auto data = dmws.detachAsData();
+    REPORTER_ASSERT(r, data->size() == N * strlen(az));
+    const uint8_t* ptr = data->bytes();
+    for (unsigned i = 0; i < N; ++i) {
+        if (0 != memcmp(ptr, az, strlen(az))) {
+            ERRORF(r, "detachAsData() memcmp failed");
+            return;
+        }
+        ptr += strlen(az);
+    }
+}
+
 DEF_TEST(StreamCopy, reporter) {
     SkRandom random(123456);
     static const int N = 10000;