Merge "Add LinearStdAllocator"
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 6f548bc..9fc3924 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -254,6 +254,7 @@
 LOCAL_STATIC_LIBRARIES := libbenchmark libbase
 
 LOCAL_SRC_FILES += \
-    microbench/DisplayListCanvasBench.cpp
+    microbench/DisplayListCanvasBench.cpp \
+    microbench/LinearAllocatorBench.cpp
 
 include $(BUILD_EXECUTABLE)
diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h
index 392bb3e..8f4ae3d 100644
--- a/libs/hwui/DisplayListCanvas.h
+++ b/libs/hwui/DisplayListCanvas.h
@@ -66,8 +66,7 @@
     virtual ~DisplayListCanvas();
 
     void reset(int width, int height);
-
-    DisplayListData* finishRecording();
+    __attribute__((warn_unused_result)) DisplayListData* finishRecording();
 
 // ----------------------------------------------------------------------------
 // HWUI Canvas state operations
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index ed299e5..8f44ff0 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -41,7 +41,7 @@
     virtual ~RecordingCanvas();
 
     void reset(int width, int height);
-    DisplayListData* finishRecording();
+    __attribute__((warn_unused_result)) DisplayListData* finishRecording();
 
 // ----------------------------------------------------------------------------
 // MISC HWUI OPERATIONS - TODO: CATEGORIZE
diff --git a/libs/hwui/microbench/DisplayListCanvasBench.cpp b/libs/hwui/microbench/DisplayListCanvasBench.cpp
index fd42adb..dccbe0b 100644
--- a/libs/hwui/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/microbench/DisplayListCanvasBench.cpp
@@ -15,7 +15,6 @@
  */
 
 #include <benchmark/Benchmark.h>
-#include <utils/Singleton.h>
 
 #include "DisplayList.h"
 #if HWUI_NEW_OPS
@@ -59,13 +58,13 @@
 BENCHMARK_NO_ARG(BM_DisplayListCanvas_record_empty);
 void BM_DisplayListCanvas_record_empty::Run(int iters) {
     TestCanvas canvas(100, 100);
-    canvas.finishRecording();
+    delete canvas.finishRecording();
 
     StartBenchmarkTiming();
     for (int i = 0; i < iters; ++i) {
         canvas.reset(100, 100);
         MicroBench::DoNotOptimize(&canvas);
-        canvas.finishRecording();
+        delete canvas.finishRecording();
     }
     StopBenchmarkTiming();
 }
@@ -73,7 +72,7 @@
 BENCHMARK_NO_ARG(BM_DisplayListCanvas_record_saverestore);
 void BM_DisplayListCanvas_record_saverestore::Run(int iters) {
     TestCanvas canvas(100, 100);
-    canvas.finishRecording();
+    delete canvas.finishRecording();
 
     StartBenchmarkTiming();
     for (int i = 0; i < iters; ++i) {
@@ -83,7 +82,7 @@
         MicroBench::DoNotOptimize(&canvas);
         canvas.restore();
         canvas.restore();
-        canvas.finishRecording();
+        delete canvas.finishRecording();
     }
     StopBenchmarkTiming();
 }
@@ -91,14 +90,14 @@
 BENCHMARK_NO_ARG(BM_DisplayListCanvas_record_translate);
 void BM_DisplayListCanvas_record_translate::Run(int iters) {
     TestCanvas canvas(100, 100);
-    canvas.finishRecording();
+    delete canvas.finishRecording();
 
     StartBenchmarkTiming();
     for (int i = 0; i < iters; ++i) {
         canvas.reset(100, 100);
         canvas.scale(10, 10);
         MicroBench::DoNotOptimize(&canvas);
-        canvas.finishRecording();
+        delete canvas.finishRecording();
     }
     StopBenchmarkTiming();
 }
diff --git a/libs/hwui/microbench/LinearAllocatorBench.cpp b/libs/hwui/microbench/LinearAllocatorBench.cpp
new file mode 100644
index 0000000..75f57cb
--- /dev/null
+++ b/libs/hwui/microbench/LinearAllocatorBench.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <benchmark/Benchmark.h>
+
+#include "utils/LinearAllocator.h"
+#include "microbench/MicroBench.h"
+
+#include <vector>
+
+using namespace android;
+using namespace android::uirenderer;
+
+BENCHMARK_NO_ARG(BM_LinearStdAllocator_vectorBaseline);
+void BM_LinearStdAllocator_vectorBaseline::Run(int iters) {
+    StartBenchmarkTiming();
+    for (int i = 0; i < iters; i++) {
+        std::vector<char> v;
+        for (int j = 0; j < 200; j++) {
+            v.push_back(j);
+        }
+        MicroBench::DoNotOptimize(&v);
+    }
+    StopBenchmarkTiming();
+}
+
+BENCHMARK_NO_ARG(BM_LinearStdAllocator_vector);
+void BM_LinearStdAllocator_vector::Run(int iters) {
+    StartBenchmarkTiming();
+    for (int i = 0; i < iters; i++) {
+        LinearAllocator la;
+        LinearStdAllocator<void*> stdAllocator(la);
+        std::vector<char, LinearStdAllocator<char> > v(stdAllocator);
+        for (int j = 0; j < 200; j++) {
+            v.push_back(j);
+        }
+        MicroBench::DoNotOptimize(&v);
+    }
+    StopBenchmarkTiming();
+}
diff --git a/libs/hwui/unit_tests/LinearAllocatorTests.cpp b/libs/hwui/unit_tests/LinearAllocatorTests.cpp
index b3959d1..02cd77a 100644
--- a/libs/hwui/unit_tests/LinearAllocatorTests.cpp
+++ b/libs/hwui/unit_tests/LinearAllocatorTests.cpp
@@ -106,3 +106,31 @@
     // Checking for a double-destroy case
     EXPECT_EQ(destroyed, false);
 }
+
+TEST(LinearStdAllocator, simpleAllocate) {
+    LinearAllocator la;
+    LinearStdAllocator<void*> stdAllocator(la);
+
+    std::vector<char, LinearStdAllocator<char> > v(stdAllocator);
+    v.push_back(0);
+    char* initialLocation = &v[0];
+    v.push_back(10);
+    v.push_back(20);
+    v.push_back(30);
+
+    // expect to have allocated (since no space reserved), so [0] will have moved to
+    // slightly further down in the same LinearAllocator page
+    EXPECT_LT(initialLocation, &v[0]);
+    EXPECT_GT(initialLocation + 20, &v[0]);
+
+    // expect to have allocated again inserting 4 more entries
+    char* lastLocation = &v[0];
+    v.push_back(40);
+    v.push_back(50);
+    v.push_back(60);
+    v.push_back(70);
+
+    EXPECT_LT(lastLocation, &v[0]);
+    EXPECT_GT(lastLocation + 20, &v[0]);
+
+}
diff --git a/libs/hwui/utils/LinearAllocator.cpp b/libs/hwui/utils/LinearAllocator.cpp
index 0abe88b..e6a4c03 100644
--- a/libs/hwui/utils/LinearAllocator.cpp
+++ b/libs/hwui/utils/LinearAllocator.cpp
@@ -52,8 +52,8 @@
 #define ALIGN_PTR(p) ((void*)(ALIGN((size_t)p)))
 
 #if LOG_NDEBUG
-#define ADD_ALLOCATION(size)
-#define RM_ALLOCATION(size)
+#define ADD_ALLOCATION()
+#define RM_ALLOCATION()
 #else
 #include <utils/Thread.h>
 #include <utils/Timers.h>
@@ -65,18 +65,18 @@
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
     if (now > s_nextLog) {
         s_nextLog = now + milliseconds_to_nanoseconds(10);
-        ALOGV("Total memory usage: %zu kb", s_totalAllocations / 1024);
+        ALOGV("Total pages allocated: %zu", s_totalAllocations);
     }
 }
 
-static void _addAllocation(size_t size) {
+static void _addAllocation(int count) {
     android::AutoMutex lock(s_mutex);
-    s_totalAllocations += size;
+    s_totalAllocations += count;
     _logUsageLocked();
 }
 
-#define ADD_ALLOCATION(size) _addAllocation(size);
-#define RM_ALLOCATION(size) _addAllocation(-size);
+#define ADD_ALLOCATION(size) _addAllocation(1);
+#define RM_ALLOCATION(size) _addAllocation(-1);
 #endif
 
 #define min(x,y) (((x) < (y)) ? (x) : (y))
@@ -134,7 +134,7 @@
         Page* next = p->next();
         p->~Page();
         free(p);
-        RM_ALLOCATION(mPageSize);
+        RM_ALLOCATION();
         p = next;
     }
 }
@@ -238,7 +238,7 @@
 
 LinearAllocator::Page* LinearAllocator::newPage(size_t pageSize) {
     pageSize = ALIGN(pageSize + sizeof(LinearAllocator::Page));
-    ADD_ALLOCATION(pageSize);
+    ADD_ALLOCATION();
     mTotalAllocated += pageSize;
     mPageCount++;
     void* buf = malloc(pageSize);
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index d90dd82..ade4ab3 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -134,6 +134,47 @@
     size_t mDedicatedPageCount;
 };
 
+template <class T>
+class LinearStdAllocator {
+public:
+    typedef T value_type; // needed to implement std::allocator
+    typedef T* pointer; // needed to implement std::allocator
+
+    LinearStdAllocator(LinearAllocator& allocator)
+            : linearAllocator(allocator) {}
+    LinearStdAllocator(const LinearStdAllocator& other)
+            : linearAllocator(other.linearAllocator) {}
+    ~LinearStdAllocator() {}
+
+    // rebind marks that allocators can be rebound to different types
+    template <class U>
+    struct rebind {
+        typedef LinearStdAllocator<U> other;
+    };
+    // enable allocators to be constructed from other templated types
+    template <class U>
+    LinearStdAllocator(const LinearStdAllocator<U>& other)
+            : linearAllocator(other.linearAllocator) {}
+
+    T* allocate(size_t num, const void* = 0) {
+        return (T*)(linearAllocator.alloc(num * sizeof(T)));
+    }
+
+    void deallocate(pointer p, size_t num) {
+        // attempt to rewind, but no guarantees
+        linearAllocator.rewindIfLastAlloc(p, num * sizeof(T));
+    }
+
+    // public so template copy constructor can access
+    LinearAllocator& linearAllocator;
+};
+
+// return that all specializations of LinearStdAllocator are interchangeable
+template <class T1, class T2>
+bool operator== (const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) { return true; }
+template <class T1, class T2>
+bool operator!= (const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) { return false; }
+
 }; // namespace uirenderer
 }; // namespace android