Blame test/memory_footprint_test.cpp

Packit Service 724aca
/*
Packit Service 724aca
 * Copyright (C) 2017 - 2018 Intel Corporation.
Packit Service 724aca
 * All rights reserved.
Packit Service 724aca
 *
Packit Service 724aca
 * Redistribution and use in source and binary forms, with or without
Packit Service 724aca
 * modification, are permitted provided that the following conditions are met:
Packit Service 724aca
 * 1. Redistributions of source code must retain the above copyright notice(s),
Packit Service 724aca
 *    this list of conditions and the following disclaimer.
Packit Service 724aca
 * 2. Redistributions in binary form must reproduce the above copyright notice(s),
Packit Service 724aca
 *    this list of conditions and the following disclaimer in the documentation
Packit Service 724aca
 *    and/or other materials provided with the distribution.
Packit Service 724aca
 *
Packit Service 724aca
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS
Packit Service 724aca
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
Packit Service 724aca
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
Packit Service 724aca
 * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit Service 724aca
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit Service 724aca
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
Packit Service 724aca
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
Packit Service 724aca
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
Packit Service 724aca
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
Packit Service 724aca
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit Service 724aca
 */
Packit Service 724aca
Packit Service 724aca
#include "common.h"
Packit Service 724aca
#include "random_sizes_allocator.h"
Packit Service 724aca
#include "proc_stat.h"
Packit Service 724aca
#include "allocator_perf_tool/GTestAdapter.hpp"
Packit Service 724aca
#include "allocator_perf_tool/Allocation_info.hpp"
Packit Service 724aca
Packit Service 724aca
#include <memkind.h>
Packit Service 724aca
Packit Service 724aca
#include <condition_variable>
Packit Service 724aca
#include <functional>
Packit Service 724aca
#include <mutex>
Packit Service 724aca
#include <random>
Packit Service 724aca
#include <thread>
Packit Service 724aca
Packit Service 724aca
class Worker
Packit Service 724aca
{
Packit Service 724aca
public:
Packit Service 724aca
    Worker(RandomSizesAllocator &&allocator, double malloc_probability)
Packit Service 724aca
        : allocator(std::move(allocator)), malloc_probability(malloc_probability)  {}
Packit Service 724aca
Packit Service 724aca
    void work()
Packit Service 724aca
    {
Packit Service 724aca
        if (allocator.empty() || get_random_bool(malloc_probability)) {
Packit Service 724aca
            requested_memory_sum += allocator.malloc_random_memory();
Packit Service 724aca
        } else {
Packit Service 724aca
            requested_memory_sum -= allocator.free_random_memory();
Packit Service 724aca
        }
Packit Service 724aca
    }
Packit Service 724aca
Packit Service 724aca
    size_t get_requested_memory_sum_bytes() const
Packit Service 724aca
    {
Packit Service 724aca
        return requested_memory_sum;
Packit Service 724aca
    }
Packit Service 724aca
Packit Service 724aca
private:
Packit Service 724aca
    bool get_random_bool(double probability)
Packit Service 724aca
    {
Packit Service 724aca
        std::bernoulli_distribution distribution(probability);
Packit Service 724aca
        return distribution(generator);
Packit Service 724aca
    }
Packit Service 724aca
Packit Service 724aca
    std::default_random_engine generator;
Packit Service 724aca
    RandomSizesAllocator allocator;
Packit Service 724aca
    size_t requested_memory_sum = 0;
Packit Service 724aca
    double malloc_probability;
Packit Service 724aca
};
Packit Service 724aca
Packit Service 724aca
Packit Service 724aca
class MemoryFootprintStats
Packit Service 724aca
{
Packit Service 724aca
public:
Packit Service 724aca
    void reset()
Packit Service 724aca
    {
Packit Service 724aca
        std::lock_guard<std::mutex> lk(sample_guard);
Packit Service 724aca
        initial_virtual_memory = proc_stat.get_virtual_memory_size_bytes();
Packit Service 724aca
        initial_physical_memory = proc_stat.get_physical_memory_size_bytes();
Packit Service 724aca
        vm_overhead_sum = 0;
Packit Service 724aca
        current_vm_overhead = 0;
Packit Service 724aca
        max_vm_overhead = 0;
Packit Service 724aca
Packit Service 724aca
        current_phys_overhead = 0;
Packit Service 724aca
        phys_overhead_sum = 0;
Packit Service 724aca
        max_phys_overhead = 0;
Packit Service 724aca
Packit Service 724aca
        requested_memory = 0;
Packit Service 724aca
        sample_count = 0;
Packit Service 724aca
    }
Packit Service 724aca
Packit Service 724aca
    void sample(long long requested_memory_bytes)
Packit Service 724aca
    {
Packit Service 724aca
        std::lock_guard<std::mutex> lk(sample_guard);
Packit Service 724aca
        current_vm = proc_stat.get_virtual_memory_size_bytes();
Packit Service 724aca
        current_phys = proc_stat.get_physical_memory_size_bytes();
Packit Service 724aca
Packit Service 724aca
        sample_count++;
Packit Service 724aca
Packit Service 724aca
        requested_memory = requested_memory_bytes;
Packit Service 724aca
Packit Service 724aca
        current_vm_overhead = current_vm - initial_virtual_memory - requested_memory;
Packit Service 724aca
        vm_overhead_sum += current_vm_overhead;
Packit Service 724aca
        max_vm_overhead = std::max(max_vm_overhead, current_vm_overhead);
Packit Service 724aca
Packit Service 724aca
        current_phys_overhead = current_phys - initial_physical_memory;
Packit Service 724aca
        phys_overhead_sum += current_phys_overhead;
Packit Service 724aca
        max_phys_overhead = std::max(max_phys_overhead, current_phys_overhead);
Packit Service 724aca
    }
Packit Service 724aca
Packit Service 724aca
    void log_data() const
Packit Service 724aca
    {
Packit Service 724aca
        std::lock_guard<std::mutex> lk(sample_guard);
Packit Service 724aca
        GTestAdapter::RecordProperty("avg_vm_overhead_per_operation_mb",
Packit Service 724aca
                                     convert_bytes_to_mb(vm_overhead_sum) / sample_count);
Packit Service 724aca
        GTestAdapter::RecordProperty("avg_vm_overhead_growth_per_operation_mb",
Packit Service 724aca
                                     convert_bytes_to_mb(current_vm_overhead) / sample_count);
Packit Service 724aca
        GTestAdapter::RecordProperty("max_vm_overhead_mb",
Packit Service 724aca
                                     convert_bytes_to_mb(max_vm_overhead));
Packit Service 724aca
        GTestAdapter::RecordProperty("avg_phys_overhead_per_operation_mb",
Packit Service 724aca
                                     convert_bytes_to_mb(phys_overhead_sum) / sample_count);
Packit Service 724aca
        GTestAdapter::RecordProperty("max_phys_overhead_mb",
Packit Service 724aca
                                     convert_bytes_to_mb(max_phys_overhead));
Packit Service 724aca
        GTestAdapter::RecordProperty("overhead_to_requested_memory_ratio_percent",
Packit Service 724aca
                                     100.f * current_vm_overhead / requested_memory);
Packit Service 724aca
        GTestAdapter::RecordProperty("requested_memory_mb",
Packit Service 724aca
                                     convert_bytes_to_mb(requested_memory));
Packit Service 724aca
    }
Packit Service 724aca
private:
Packit Service 724aca
    long long initial_virtual_memory;
Packit Service 724aca
    long long vm_overhead_sum = 0;
Packit Service 724aca
    long long current_vm_overhead = 0;
Packit Service 724aca
    long long max_vm_overhead = 0;
Packit Service 724aca
Packit Service 724aca
    long long initial_physical_memory;
Packit Service 724aca
    long long current_phys_overhead = 0;
Packit Service 724aca
    long long phys_overhead_sum = 0;
Packit Service 724aca
    long long max_phys_overhead = 0;
Packit Service 724aca
Packit Service 724aca
    long long requested_memory = 0;
Packit Service 724aca
    long long sample_count = 0;
Packit Service 724aca
Packit Service 724aca
    long long current_vm;
Packit Service 724aca
    long long current_phys;
Packit Service 724aca
Packit Service 724aca
    ProcStat proc_stat;
Packit Service 724aca
    mutable std::mutex sample_guard;
Packit Service 724aca
};
Packit Service 724aca
Packit Service 724aca
/* Execute func calling it n_calls times in n_threads threads.
Packit Service 724aca
 * The execution is multithreaded but the func calls order is sequential.
Packit Service 724aca
 * func takes thread id, and operation id as an argument,
Packit Service 724aca
 * and must return thread id of the next thread, where thread ids are in range <0, n_threads-1>.
Packit Service 724aca
 * init_thread_id specify the initial thread id.
Packit Service 724aca
 */
Packit Service 724aca
void run_multithreaded_seq_exec(unsigned n_threads, unsigned init_thread_id,
Packit Service 724aca
                                unsigned n_calls, std::function<unsigned(unsigned, unsigned)> func)
Packit Service 724aca
{
Packit Service 724aca
    std::vector<std::thread> threads;
Packit Service 724aca
    std::mutex mutex;
Packit Service 724aca
    std::condition_variable turns_holder;
Packit Service 724aca
    unsigned current_call = 0;
Packit Service 724aca
    unsigned current_tid = init_thread_id;
Packit Service 724aca
Packit Service 724aca
    threads.reserve(n_threads);
Packit Service 724aca
Packit Service 724aca
    mutex.lock();
Packit Service 724aca
Packit Service 724aca
    for(int tid=0; tid
Packit Service 724aca
        threads.emplace_back([ &, tid]() {
Packit Service 724aca
            while(current_call < n_calls) {
Packit Service 724aca
                std::unique_lock<std::mutex> lk(mutex);
Packit Service 724aca
                turns_holder.wait(lk, [ &,tid] {return current_tid == tid || current_call == n_calls;});
Packit Service 724aca
                if(current_call == n_calls) {
Packit Service 724aca
                    return;
Packit Service 724aca
                }
Packit Service 724aca
                current_tid = func(tid, current_call);
Packit Service 724aca
                ASSERT_LT(current_tid, n_threads) << "Incorrect thread id!";
Packit Service 724aca
                current_call++;
Packit Service 724aca
                lk.unlock();
Packit Service 724aca
                turns_holder.notify_all();
Packit Service 724aca
            }
Packit Service 724aca
        });
Packit Service 724aca
    }
Packit Service 724aca
Packit Service 724aca
    mutex.unlock();
Packit Service 724aca
Packit Service 724aca
    for(int i=0; i
Packit Service 724aca
        threads[i].join();
Packit Service 724aca
    }
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
/*
Packit Service 724aca
 * Create threads and measure the cost of maintaining allocations from threads.
Packit Service 724aca
 * Allocations order is sequential (otherwise the results might be very nondeterministic).
Packit Service 724aca
 */
Packit Service 724aca
void run_test(memkind_t kind, size_t min_size, size_t max_size,
Packit Service 724aca
              unsigned n_threads, double malloc_probability=1.0, unsigned n_calls=1000)
Packit Service 724aca
{
Packit Service 724aca
    Worker worker(RandomSizesAllocator(kind, min_size, max_size, n_calls),
Packit Service 724aca
                  malloc_probability);
Packit Service 724aca
Packit Service 724aca
    MemoryFootprintStats mem_footprint_stats;
Packit Service 724aca
Packit Service 724aca
    auto func = [&](unsigned tid, unsigned id) -> unsigned {
Packit Service 724aca
        if(id == 0)
Packit Service 724aca
        {
Packit Service 724aca
            mem_footprint_stats.reset();
Packit Service 724aca
        }
Packit Service 724aca
Packit Service 724aca
        worker.work();
Packit Service 724aca
        mem_footprint_stats.sample(worker.get_requested_memory_sum_bytes());
Packit Service 724aca
Packit Service 724aca
        return (tid + 1) % n_threads; //next thread id
Packit Service 724aca
    };
Packit Service 724aca
    run_multithreaded_seq_exec(n_threads, 0, n_calls, func);
Packit Service 724aca
    mem_footprint_stats.log_data();
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
class MemoryFootprintTest: public :: testing::Test
Packit Service 724aca
{};
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_DEFAULT_only_malloc_small_allocations_1_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_DEFAULT, 128, 15 * KB, 1);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_DEFAULT_only_malloc_small_allocations_10_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_DEFAULT, 128, 15 * KB, 10);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_DEFAULT_only_malloc_medium_allocations_1_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_DEFAULT, 16 * KB, 1 * MB, 1);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_DEFAULT_only_malloc_medium_allocations_10_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_DEFAULT, 16 * KB, 1 * MB, 10);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_DEFAULT_only_malloc_large_allocations_1_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_DEFAULT, 2 * MB, 10 * MB, 1, 1.0, 100);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_DEFAULT_only_malloc_large_allocations_10_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_DEFAULT, 2 * MB, 10 * MB, 10, 1.0, 100);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_DEFAULT_random_malloc80_free20_random_small_allocations_1_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_DEFAULT, 128, 15 * KB, 1, 0.8);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_DEFAULT_random_malloc80_free20_random_small_allocations_10_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_DEFAULT, 128, 15 * KB, 10, 0.8);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_DEFAULT_random_malloc80_free20_random_medium_allocations_1_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_DEFAULT, 16 * KB, 1 * MB, 1, 0.8);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_DEFAULT_random_malloc80_free20_random_large_allocations_10_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_DEFAULT, 2 * MB, 10 * MB,  10, 0.8, 100);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_HBW_only_malloc_small_allocations_1_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_HBW, 128, 15 * KB, 1);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_HBW_only_malloc_small_allocations_10_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_HBW, 128, 15 * KB, 10);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_HBW_only_malloc_medium_allocations_1_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_HBW, 16 * KB, 1 * MB, 1);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_HBW_only_malloc_medium_allocations_10_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_HBW, 16 * KB, 1 * MB, 10);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_HBW_only_malloc_large_allocations_1_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_HBW, 2 * MB, 10 * MB, 1, 100);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_HBW_only_malloc_large_allocations_10_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_HBW, 2 * MB, 10 * MB, 10, 100);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_HBW_random_malloc80_free20_random_small_allocations_1_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_HBW, 128, 15 * KB, 1, 0.8);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_HBW_random_malloc80_free20_random_small_allocations_10_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_HBW, 128, 15 * KB, 10, 0.8);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_HBW_random_malloc80_free20_random_medium_allocations_1_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_HBW, 16 * KB, 1 * MB, 1, 0.8);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_HBW_random_malloc80_free20_random_medium_allocations_10_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_HBW, 16 * KB, 1 * MB, 10, 0.8);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_HBW_random_malloc80_free20_random_large_allocations_1_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_HBW, 2 * MB, 10 * MB, 1, 0.8, 100);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
TEST_F(MemoryFootprintTest,
Packit Service 724aca
       test_TC_MEMKIND_HBW_random_malloc80_free20_random_large_allocations_10_thread)
Packit Service 724aca
{
Packit Service 724aca
    run_test(MEMKIND_HBW, 2 * MB, 10 * MB, 10, 0.8, 100);
Packit Service 724aca
}