OSDN Git Service

Add memcpy perf test + graphing script.
authorRiley Andrews <riandrews@google.com>
Mon, 17 Aug 2015 23:42:26 +0000 (16:42 -0700)
committerRiley Andrews <riandrews@google.com>
Tue, 18 Aug 2015 01:32:48 +0000 (18:32 -0700)
Change-Id: Iaaac90f4d91dbe6023b64af6e8924f6b9f61e58b

memcpy-perf/Android.mk [new file with mode: 0644]
memcpy-perf/graph_memcpy.py [new file with mode: 0644]
memcpy-perf/memcpy-perf.cpp [new file with mode: 0644]
memcpy-perf/test-funcs.cpp [new file with mode: 0644]

diff --git a/memcpy-perf/Android.mk b/memcpy-perf/Android.mk
new file mode 100644 (file)
index 0000000..55ac927
--- /dev/null
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_CLANG := true
+LOCAL_MODULE := memcpy-perf
+LOCAL_CFLAGS += -g -Wall -Werror -std=c++11 -Wno-missing-field-initializers -Wno-sign-compare -O3
+LOCAL_SRC_FILES := memcpy-perf.cpp test-funcs.cpp
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_CXX_STL := libc++_static
+LOCAL_STATIC_LIBRARIES := libc
+include $(BUILD_EXECUTABLE)
diff --git a/memcpy-perf/graph_memcpy.py b/memcpy-perf/graph_memcpy.py
new file mode 100644 (file)
index 0000000..7c64d99
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/python
+import subprocess
+import matplotlib.pyplot as plt
+import time
+import argparse
+
+parser = argparse.ArgumentParser(description="Graph memcpy perf")
+parser.add_argument("--files", nargs='+', type=str, help="files to graph", default=None)
+args = parser.parse_args()
+
+fig, ax = plt.subplots(nrows=1)
+ax.set_xscale('log')
+
+plt.xlabel("size in bytes")
+plt.ylabel("BW in GB/s")
+plt.title("size vs. bw")
+plt.tight_layout()
+
+for arg in args.files:
+       f = open(arg)
+       size = []
+       perf = []
+       for line in f:
+               # size: 11430912, perf: 6.76051GB/s, iter: 5
+               line_split = line.split(",")
+               size.append(float(line_split[0].split(":")[1]))
+               perf.append(float(line_split[1].split(":")[1].split("G")[0]))
+
+       line, = ax.plot(size, perf, '-',  linewidth=0.2, label=arg)
+
+legend = plt.legend()
+plt.show()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/memcpy-perf/memcpy-perf.cpp b/memcpy-perf/memcpy-perf.cpp
new file mode 100644 (file)
index 0000000..20d060b
--- /dev/null
@@ -0,0 +1,105 @@
+#include <iostream>
+#include <chrono>
+#include <vector>
+#include <algorithm>
+#include <numeric>
+#include <stdlib.h>
+#include <memory>
+#include <cmath>
+#include <string>
+
+using namespace std;
+
+const size_t size_start = 64;
+const size_t size_end = 16 * (1ull << 20);
+const size_t samples = 2048;
+size_t size_per_test = 64 * (1ull << 20);
+size_t tot_sum = 0;
+
+void __attribute__((noinline)) memcpy_noinline(void *dst, void *src, size_t size);
+void __attribute__((noinline)) memset_noinline(void *dst, int value, size_t size);
+uint64_t __attribute__((noinline)) sum(volatile void *src, size_t size);
+
+enum BenchType {
+    MemcpyBench,
+    MemsetBench,
+    SumBench,
+};
+
+int main(int argc, char *argv[])
+{
+    BenchType type;
+    if (argc <= 1) {
+        cerr << "memcpy_perf [--memcpy|--memset|--sum]" << endl;
+        return 0;
+    }
+    if (string(argv[1]) == string("--memcpy")) {
+        type = MemcpyBench;
+    } else if (string(argv[1]) == string("--memset")) {
+        type = MemsetBench;
+    } else if (string(argv[1]) == string("--sum")) {
+        type = SumBench;
+    } else {
+        type = MemcpyBench;
+    }
+
+    unique_ptr<uint8_t[]> src(new uint8_t[size_end]);
+    unique_ptr<uint8_t[]> dst(new uint8_t[size_end]);
+    memset(src.get(), 1, size_end);
+
+    double start_pow = log10(size_start);
+    double end_pow = log10(size_end);
+    double pow_inc = (end_pow - start_pow) / samples;
+
+    //cout << "src: " << (uintptr_t)src.get() << endl;
+    //cout << "dst: " <<  (uintptr_t)dst.get() << endl;
+
+    for (double cur_pow = start_pow; cur_pow <= end_pow; cur_pow += pow_inc) {
+        chrono::time_point<chrono::high_resolution_clock> copy_start, copy_end;
+
+        size_t cur_size = (size_t)pow(10.0, cur_pow);
+        size_t iter_per_size = size_per_test / cur_size;
+
+        // run benchmark
+        switch (type) {
+            case MemsetBench: {
+                memcpy_noinline(src.get(), dst.get(), cur_size);
+                memset_noinline(dst.get(), 0xdeadbeef, cur_size);
+                copy_start = chrono::high_resolution_clock::now();
+                for (int i = 0; i < iter_per_size; i++) {
+                    memset_noinline(dst.get(), 0xdeadbeef, cur_size);
+                }
+                copy_end = chrono::high_resolution_clock::now();
+                break;
+            }
+            case MemcpyBench: {
+                memcpy_noinline(dst.get(), src.get(), cur_size);
+                memcpy_noinline(src.get(), dst.get(), cur_size);
+                copy_start = chrono::high_resolution_clock::now();
+                for (int i = 0; i < iter_per_size; i++) {
+                    memcpy_noinline(dst.get(), src.get(), cur_size);
+                }
+                copy_end = chrono::high_resolution_clock::now();
+                break;
+            }
+            case SumBench: {
+                uint64_t s = 0;
+                s += sum(src.get(), cur_size);
+                copy_start = chrono::high_resolution_clock::now();
+                for (int i = 0; i < iter_per_size; i++) {
+                    s += sum(src.get(), cur_size);
+                }
+                copy_end = chrono::high_resolution_clock::now();
+                tot_sum += s;
+                break;
+            }
+        }
+
+        double ns_per_copy = chrono::duration_cast<chrono::nanoseconds>(copy_end - copy_start).count() / double(iter_per_size);
+        double gb_per_sec = ((double)cur_size / (1ull<<30)) / (ns_per_copy / 1.0E9);
+        if (type == MemcpyBench)
+            gb_per_sec *= 2.0;
+        cout << "size: " << cur_size << ", perf: " << gb_per_sec << "GB/s, iter: " << iter_per_size << endl;
+    }
+    return 0;
+}
diff --git a/memcpy-perf/test-funcs.cpp b/memcpy-perf/test-funcs.cpp
new file mode 100644 (file)
index 0000000..9c992fa
--- /dev/null
@@ -0,0 +1,21 @@
+#include <string>
+
+void __attribute__((noinline)) memcpy_noinline(void *dst, void *src, size_t size)
+{
+    memcpy(dst,src,size);
+}
+
+void __attribute__((noinline)) memset_noinline(void *dst, int value, size_t size)
+{
+    memset(dst, value, size);
+}
+
+uint64_t __attribute__((noinline)) sum(volatile void *src, size_t size)
+{
+    uint64_t *src_ptr = (uint64_t*)src;
+    uint64_t sum = 0;
+    size_t len = size / sizeof(uint64_t);
+    for (size_t i = 0; i < len; i+=1)
+        sum += src_ptr[i];
+    return sum;
+}