| /* |
| * Copyright (C) 2014 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "Benchmark.h" |
| #include "CPUCount.h" |
| #include "stress.h" |
| #include <array> |
| #include <cassert> |
| #include <chrono> |
| #include <cstdlib> |
| #include <memory> |
| #include <stddef.h> |
| #include <vector> |
| |
| #include "mbmalloc.h" |
| |
| static const size_t kB = 1024; |
| static const size_t MB = kB * kB; |
| |
| struct Object { |
| Object(void* pointer, size_t size, long uuid) |
| : pointer(pointer) |
| , size(size) |
| , uuid(uuid) |
| { |
| } |
| |
| void* pointer; |
| size_t size; |
| long uuid; |
| }; |
| |
| class SizeStream { |
| public: |
| SizeStream() |
| : m_state(Small) |
| , m_count(0) |
| { |
| } |
| |
| size_t next() |
| { |
| switch (m_state) { |
| case Small: { |
| if (++m_count == smallCount) { |
| m_state = Medium; |
| m_count = 0; |
| } |
| return random() % smallMax; |
| } |
| |
| case Medium: { |
| if (++m_count == mediumCount) { |
| m_state = Large; |
| m_count = 0; |
| } |
| return random() % mediumMax; |
| } |
| |
| case Large: { |
| if (++m_count == largeCount) { |
| m_state = Small; |
| m_count = 0; |
| } |
| return random() % largeMax; |
| } |
| } |
| assert(0); |
| return 0; |
| } |
| |
| private: |
| static const size_t smallCount = 1000; |
| static const size_t smallMax = 16 * kB; |
| |
| static const size_t mediumCount = 100; |
| static const size_t mediumMax = 512 * kB; |
| |
| static const size_t largeCount = 10; |
| static const size_t largeMax = 4 * MB; |
| |
| enum { Small, Medium, Large } m_state; |
| size_t m_count; |
| }; |
| |
| Object allocate(size_t size) |
| { |
| Object object(mbmalloc(size), size, random()); |
| for (size_t i = 0; i < size / sizeof(long); ++i) |
| (static_cast<long*>(object.pointer))[i] = object.uuid; |
| return object; |
| } |
| |
| void deallocate(const Object& object) |
| { |
| for (size_t i = 0; i < object.size / sizeof(long); ++i) { |
| if ((static_cast<long*>(object.pointer))[i] != object.uuid) |
| abort(); |
| } |
| |
| mbfree(object.pointer, object.size); |
| } |
| |
| void benchmark_stress(CommandLine&) |
| { |
| const size_t heapSize = 100 * MB; |
| const size_t churnSize = .05 * heapSize; |
| const size_t churnCount = 100; |
| |
| srandom(1); // For consistency between runs. |
| |
| std::vector<Object> objects; |
| |
| SizeStream sizeStream; |
| |
| size_t size = 0; |
| for (size_t remaining = heapSize; remaining; remaining -= std::min(remaining, size)) { |
| size = sizeStream.next(); |
| objects.push_back(allocate(size)); |
| } |
| |
| for (size_t i = 0; i < churnCount; ++i) { |
| std::vector<Object> objectsToFree; |
| for (size_t remaining = churnSize; remaining; remaining -= std::min(remaining, size)) { |
| size = sizeStream.next(); |
| Object object = allocate(size); |
| |
| size_t index = random() % objects.size(); |
| objectsToFree.push_back(objects[index]); |
| objects[index] = object; |
| } |
| |
| for (auto& object : objectsToFree) |
| deallocate(object); |
| |
| mbscavenge(); |
| } |
| |
| for (auto& object : objects) |
| mbfree(object.pointer, object.size); |
| } |