OSDN Git Service

Yet another disk performance benchmark.
authorRiley Andrews <riandrews@google.com>
Fri, 4 Sep 2015 00:25:14 +0000 (17:25 -0700)
committerMark Salyzyn <salyzyn@google.com>
Fri, 18 Sep 2015 20:08:42 +0000 (13:08 -0700)
This does memory mapped i/o on huge files, and thus requires
a 64 bit device.

Change-Id: Id91dd59b8c32751b6cb14f166affbd57912f8d28

mmap-perf/Android.mk [new file with mode: 0644]
mmap-perf/mmapPerf.cpp [new file with mode: 0644]

diff --git a/mmap-perf/Android.mk b/mmap-perf/Android.mk
new file mode 100644 (file)
index 0000000..f9a4a96
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2014 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := mmapPerf
+LOCAL_SRC_FILES := mmapPerf.cpp
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -g -Wall -Werror -std=c++11 -Wno-missing-field-initializers -Wno-sign-compare -O3
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_CXX_STL := libc++_static
+LOCAL_STATIC_LIBRARIES := libc
+include $(BUILD_EXECUTABLE)
diff --git a/mmap-perf/mmapPerf.cpp b/mmap-perf/mmapPerf.cpp
new file mode 100644 (file)
index 0000000..16e0c76
--- /dev/null
@@ -0,0 +1,163 @@
+#include <string>
+#include <cstring>
+#include <cstdlib>
+#include <cstdio>
+#include <iostream>
+#include <vector>
+#include <tuple>
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+using namespace std;
+static const size_t pageSize = 4096;
+
+class Fd {
+    int m_fd = -1;
+public:
+    int get() { return m_fd; }
+    void set(int fd) { m_fd = fd; }
+    Fd() {}
+    Fd(int fd) : m_fd{fd} {}
+    ~Fd() {
+        if (m_fd >= 0)
+            close(m_fd);
+    }
+};
+
+int dummy = 0;
+
+void fillPageJunk(void *ptr)
+{
+    uint64_t seed = (unsigned long long)rand() | ((unsigned long long)rand() << 32);
+    uint64_t *target = (uint64_t*)ptr;
+    for (int i = 0; i < pageSize / sizeof(uint64_t); i++) {
+        *target = seed ^ (uint64_t)(uintptr_t)target;
+        seed = (seed << 1) | ((seed >> 63) & 1);
+        target++;
+    }
+}
+
+class FileMap {
+    string m_name;
+    size_t m_size;
+    void *m_ptr = nullptr;
+    Fd m_fileFd;
+public:
+    enum Hint {
+       FILE_MAP_HINT_NONE,
+       FILE_MAP_HINT_RAND,
+       FILE_MAP_HINT_LINEAR,
+    };
+    FileMap(const string &name, size_t size, Hint hint = FILE_MAP_HINT_NONE) : m_name{name}, m_size{size} {
+        int fd = open(name.c_str(), O_CREAT | O_RDWR, S_IRWXU);
+        if (fd < 0) {
+            cerr << "open failed: " << fd << endl;
+            return;
+        }
+        m_fileFd.set(fd);
+        fallocate(m_fileFd.get(), 0, 0, size);
+        unlink(name.c_str());
+        m_ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fileFd.get(), 0);
+        if ((int)(uintptr_t)m_ptr == -1) {
+            cerr << "mmap failed: " << (int)(uintptr_t)m_ptr << endl;
+            m_ptr = nullptr;
+            return;
+        }
+        switch (hint) {
+        case FILE_MAP_HINT_NONE: break;
+        case FILE_MAP_HINT_RAND:
+            madvise(m_ptr, m_size, MADV_RANDOM);
+            break;
+        case FILE_MAP_HINT_LINEAR:
+            madvise(m_ptr, m_size, MADV_SEQUENTIAL);
+            break;
+        }
+        for (int i = 0; i < m_size / pageSize; i++) {
+            uint8_t *targetPtr = (uint8_t*)m_ptr + 4096ull * i;
+            fillPageJunk(targetPtr);
+        }
+    }
+    void benchRandom(bool write) {
+        size_t pagesTotal = m_size / pageSize;
+        size_t pagesToHit = pagesTotal / 128;
+        uint64_t nsTotal = 0;
+
+        chrono::time_point<chrono::high_resolution_clock> start, end;
+        start = chrono::high_resolution_clock::now();
+        for (int j = 0; j < pagesToHit; j++) {
+            int targetPage = rand() % pagesTotal;
+            uint8_t *targetPtr = (uint8_t*)m_ptr + 4096ull * targetPage;
+            if (write) {
+                *targetPtr = dummy;
+            }
+            else {
+                dummy += *targetPtr;
+            }
+        }
+        end = chrono::high_resolution_clock::now();
+        nsTotal += chrono::duration_cast<chrono::nanoseconds>(end - start).count();
+        //cout << "random: " << nsTotal / 1000.0 / (pagesToHit) << "us/page" << endl;
+        cout << "random " << (write ? "write" : "read") << ": " << ((4096.0 * pagesToHit) / (1 << 20)) / (nsTotal / 1.0E9) << "MB/s" << endl;
+    }
+    void benchLinear(bool write) {
+        int pagesTotal = m_size / pageSize;
+        int iterations = 4;
+        uint64_t nsTotal = 0;
+
+        chrono::time_point<chrono::high_resolution_clock> start, end;
+        start = chrono::high_resolution_clock::now();
+        for (int i = 0; i < iterations; i++) {
+            for (int j = 0; j < pagesTotal; j++) {
+                uint8_t *targetPtr = (uint8_t*)m_ptr + 4096ull * j;
+                if (write) {
+                    *targetPtr = dummy;
+                }
+                else {
+                    dummy += *targetPtr;
+                }
+            }
+        }
+        end = chrono::high_resolution_clock::now();
+        nsTotal += chrono::duration_cast<chrono::nanoseconds>(end - start).count();
+        //cout << "linear: " << nsTotal / 1000.0 / (pagesTotal * iterations) << "us/page" << endl;
+        cout << "linear " << (write ? "write" : "read") << ": " << ((4096.0 * pagesTotal * iterations) / (1 << 20)) / (nsTotal / 1.0E9 ) << "MB/s" << endl;
+    }
+    void dropCache() {
+        int ret1 = msync(m_ptr, m_size, MS_SYNC | MS_INVALIDATE);
+        madvise(m_ptr, m_size, MADV_DONTNEED);
+        (void)ret1;
+    }
+    ~FileMap() {
+        if (m_ptr)
+            munmap(m_ptr, m_size);
+    }
+
+};
+
+int main(int argc, char *argv[])
+{
+    (void)argc;
+    (void)argv;
+    srand(0);
+
+    {
+        FileMap file{"/data/local/tmp/mmap_test", 16000 * (1ull << 20)};
+        file.benchRandom(false);
+    }
+    {
+        FileMap file{"/data/local/tmp/mmap_test", 16000 * (1ull << 20)};
+        file.benchLinear(false);
+    }
+    {
+        FileMap file{"/data/local/tmp/mmap_test", 16000 * (1ull << 20)};
+        file.benchRandom(true);
+    }
+    {
+        FileMap file{"/data/local/tmp/mmap_test", 16000 * (1ull << 20)};
+        file.benchLinear(true);
+    }
+    return 0;
+}