Blame test/performance/framework.hpp

Packit 345191
/*
Packit 345191
* Copyright (C) 2014 - 2019 Intel Corporation.
Packit 345191
* All rights reserved.
Packit 345191
*
Packit 345191
* Redistribution and use in source and binary forms, with or without
Packit 345191
* modification, are permitted provided that the following conditions are met:
Packit 345191
* 1. Redistributions of source code must retain the above copyright notice(s),
Packit 345191
*    this list of conditions and the following disclaimer.
Packit 345191
* 2. Redistributions in binary form must reproduce the above copyright notice(s),
Packit 345191
*    this list of conditions and the following disclaimer in the documentation
Packit 345191
*    and/or other materials provided with the distribution.
Packit 345191
*
Packit 345191
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS
Packit 345191
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
Packit 345191
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
Packit 345191
* EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit 345191
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit 345191
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
Packit 345191
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
Packit 345191
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
Packit 345191
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
Packit 345191
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 345191
*/
Packit 345191
Packit 345191
#pragma once
Packit 345191
Packit 345191
#include <memkind.h>
Packit 345191
Packit 345191
#include <thread>
Packit 345191
#include <vector>
Packit 345191
#include <mutex>
Packit 345191
#include <condition_variable>
Packit 345191
// Malloc, jemalloc, memkind jemalloc and memkind memory operations definitions
Packit 345191
#include "operations.hpp"
Packit 345191
Packit 345191
/* Framework for testing memory allocators pefromance */
Packit 345191
namespace performance_tests
Packit 345191
{
Packit 345191
// Nanoseconds in second
Packit 345191
    const uint32_t NanoSecInSec = 1e9;
Packit 345191
Packit 345191
    // Simple barrier implementation
Packit 345191
    class Barrier
Packit 345191
    {
Packit 345191
        // Barrier mutex
Packit 345191
        std::mutex m_barrierMutex;
Packit 345191
        // Contitional variable
Packit 345191
        std::condition_variable m_cVar;
Packit 345191
        // Number of threads expected to enter the barrier
Packit 345191
        size_t m_waiting;
Packit 345191
        timespec m_releasedAt;
Packit 345191
Packit 345191
    public:
Packit 345191
        // Called by each thread entering the barrier; returns control to caller
Packit 345191
        // only after been called from the last thread expected at the barrier
Packit 345191
        void wait();
Packit 345191
Packit 345191
        // (Re)Initializes the barrier
Packit 345191
        void reset(unsigned waiting)
Packit 345191
        {
Packit 345191
            m_releasedAt.tv_sec = m_releasedAt.tv_nsec = 0;
Packit 345191
            m_waiting = waiting;
Packit 345191
        }
Packit 345191
Packit 345191
        // Get time when barrier was released
Packit 345191
        timespec &releasedAt()
Packit 345191
        {
Packit 345191
            return m_releasedAt;
Packit 345191
        }
Packit 345191
Packit 345191
        // Singleton
Packit 345191
        static Barrier &GetInstance()
Packit 345191
        {
Packit 345191
            // Automatically created and deleted one and only instance
Packit 345191
            static Barrier instance;
Packit 345191
            return instance;
Packit 345191
        }
Packit 345191
    private:
Packit 345191
        Barrier()
Packit 345191
        {
Packit 345191
            reset(0);
Packit 345191
        }
Packit 345191
        // Cannot be used with singleton, so prevent compiler from creating them automatically
Packit 345191
        Barrier(Barrier const &)        = delete;
Packit 345191
        void operator=(Barrier const &) = delete;
Packit 345191
    };
Packit 345191
Packit 345191
    // Data of a single test action, that is, memory operation (malloc, calloc, etc.)
Packit 345191
    // to perform and its parameters (size, alignment etc.)
Packit 345191
    class Action
Packit 345191
    {
Packit 345191
    protected:
Packit 345191
        Operation *m_operation;
Packit 345191
        Operation *m_freeOperation;
Packit 345191
        const memkind_t m_kind;
Packit 345191
        void *m_allocation;
Packit 345191
        const size_t m_size;
Packit 345191
        const size_t m_offset;
Packit 345191
        const size_t m_alignment;
Packit 345191
Packit 345191
    public:
Packit 345191
        Action(
Packit 345191
            Operation *operation,
Packit 345191
            Operation *freeOperation,
Packit 345191
            const memkind_t kind,
Packit 345191
            const size_t size,
Packit 345191
            const size_t offset,
Packit 345191
            const size_t alignment)
Packit 345191
            : m_operation(operation)
Packit 345191
            , m_freeOperation(freeOperation)
Packit 345191
            , m_kind(kind)
Packit 345191
            , m_allocation(nullptr)
Packit 345191
            , m_size(size)
Packit 345191
            , m_offset(offset)
Packit 345191
            , m_alignment(alignment)
Packit 345191
        {}
Packit 345191
Packit 345191
        Action(
Packit 345191
            Operation *operation,
Packit 345191
            Operation *freeOperation,
Packit 345191
            const memkind_t kind)
Packit 345191
            : Action(operation, freeOperation, kind, 0, 0, 0)
Packit 345191
        {
Packit 345191
        }
Packit 345191
Packit 345191
        void alloc()
Packit 345191
        {
Packit 345191
            m_operation->perform(m_kind, m_allocation, m_size, m_offset, m_alignment);
Packit 345191
        }
Packit 345191
Packit 345191
        void free()
Packit 345191
        {
Packit 345191
            m_freeOperation->perform(m_kind, m_allocation);
Packit 345191
        }
Packit 345191
Packit 345191
    };
Packit 345191
Packit 345191
    // Performs and tracks requested memory operations in a separate thread
Packit 345191
    class Worker
Packit 345191
    {
Packit 345191
    protected:
Packit 345191
#ifdef __DEBUG
Packit 345191
        uint16_t m_threadId;
Packit 345191
#endif
Packit 345191
        // Requested number of test actions
Packit 345191
        const uint32_t m_actionsCount;
Packit 345191
        // List of memory block sizes - for each memory allocation operation actual value is chosen randomly
Packit 345191
        const vector<size_t> &m_allocationSizes;
Packit 345191
        // List of test actions
Packit 345191
        vector<Action *> m_actions;
Packit 345191
        // Memory free action
Packit 345191
        Action *m_freeAction;
Packit 345191
        // Operation kind (useful for memkind only)
Packit 345191
        memkind_t m_kind;
Packit 345191
        // Working thread
Packit 345191
        thread *m_thread;
Packit 345191
Packit 345191
    public:
Packit 345191
        Worker(
Packit 345191
            uint32_t actionsCount,
Packit 345191
            const vector<size_t> &allocationSizes,
Packit 345191
            Operation *freeOperation,
Packit 345191
            memkind_t kind);
Packit 345191
Packit 345191
        ~Worker();
Packit 345191
Packit 345191
        // Set operations list for the worker
Packit 345191
        void init(const vector<Operation *> &testOperations, Operation *&freeOperation);
Packit 345191
Packit 345191
        // Create & start thread
Packit 345191
        void run();
Packit 345191
Packit 345191
#ifdef __DEBUG
Packit 345191
        // Get thread id
Packit 345191
        uint16_t getId();
Packit 345191
Packit 345191
        // Set thread id
Packit 345191
        void setId(uint16_t threadId);
Packit 345191
#endif
Packit 345191
Packit 345191
        // Finish thread and free all allocations made
Packit 345191
        void finish();
Packit 345191
Packit 345191
        // Free allocated memory
Packit 345191
        virtual void clean();
Packit 345191
Packit 345191
    private:
Packit 345191
        // Actual thread function (allow inheritance)
Packit 345191
        virtual void work();
Packit 345191
    };
Packit 345191
Packit 345191
    enum ExecutionMode {
Packit 345191
        SingleInteration, // Single iteration, operations listS will be distributed among threads sequentially
Packit 345191
        ManyIterations    // Each operations list will be run in separate iteration by each thread
Packit 345191
    };
Packit 345191
Packit 345191
    struct Metrics {
Packit 345191
        uint64_t executedOperations;
Packit 345191
        uint64_t totalDuration;
Packit 345191
        double operationsPerSecond;
Packit 345191
        double avgOperationDuration;
Packit 345191
        double iterationDuration;
Packit 345191
        double repeatDuration;
Packit 345191
    };
Packit 345191
Packit 345191
    // Performance test parameters class
Packit 345191
    class PerformanceTest
Packit 345191
    {
Packit 345191
    protected:
Packit 345191
        // empirically determined % of worst results needed to be discarded
Packit 345191
        // to eliminate malloc() performance results skewness
Packit 345191
        static constexpr double distardPercent = 20.0;
Packit 345191
    protected:
Packit 345191
        // Number of test repeats
Packit 345191
        size_t                      m_repeatsCount;
Packit 345191
        // Number of test repeats with worst results to be discarded
Packit 345191
        size_t                      m_discardCount;
Packit 345191
        // Number of threads
Packit 345191
        size_t                      m_threadsCount;
Packit 345191
        // Number of memory operations in each thread
Packit 345191
        uint32_t                    m_operationsCount;
Packit 345191
        // List of allocation sizes
Packit 345191
        vector<size_t>              m_allocationSizes;
Packit 345191
        // List of list of allocation operations, utlization depends on execution mode
Packit 345191
        vector<vector<Operation *>> m_testOperations;
Packit 345191
        // Free operation
Packit 345191
        Operation                  *m_freeOperation;
Packit 345191
        // List of memory kinds (for memkind allocation only)
Packit 345191
        // distributed among threads sequentially
Packit 345191
        vector<memkind_t>           m_kinds;
Packit 345191
        // List of thread workers
Packit 345191
        vector<Worker *>            m_workers;
Packit 345191
        // Time measurement
Packit 345191
        vector<uint64_t>            m_durations;
Packit 345191
        // Execution mode
Packit 345191
        ExecutionMode               m_executionMode;
Packit 345191
Packit 345191
    public:
Packit 345191
        // Create test
Packit 345191
        PerformanceTest(
Packit 345191
            size_t repeatsCount,
Packit 345191
            size_t threadsCount,
Packit 345191
            size_t operationsCount);
Packit 345191
Packit 345191
        virtual ~PerformanceTest() {}
Packit 345191
Packit 345191
        // Set list of block sizes
Packit 345191
        void setAllocationSizes(const vector<size_t> &allocationSizes);
Packit 345191
Packit 345191
        // Set list of operations per thread/per iteration (depending on execution mode)
Packit 345191
        void setOperations(const vector<vector<Operation *>> &testOperations,
Packit 345191
                           Operation *freeOperation);
Packit 345191
Packit 345191
        // Set per-thread list of memory kinds
Packit 345191
        void setKind(const vector<memkind_t> &kinds);
Packit 345191
Packit 345191
        // Set execution mode (different operations per each thread/same operations for each thread, but many iterations)
Packit 345191
        void setExecutionMode(ExecutionMode operationMode);
Packit 345191
Packit 345191
        // Execute test
Packit 345191
        int run();
Packit 345191
Packit 345191
        // Print test parameters
Packit 345191
        virtual void showInfo();
Packit 345191
Packit 345191
        // Write test metrics
Packit 345191
        void writeMetrics(const string &suiteName, const string &caseName,
Packit 345191
                          const string &fileName = "");
Packit 345191
Packit 345191
        Metrics getMetrics();
Packit 345191
    private:
Packit 345191
Packit 345191
        // Run single iteration
Packit 345191
        void runIteration();
Packit 345191
Packit 345191
        // Setup thread workers
Packit 345191
        void prepareWorkers();
Packit 345191
Packit 345191
    };
Packit 345191
}