|
Packit Service |
724aca |
/*
|
|
Packit Service |
724aca |
* Copyright (C) 2014 - 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 <algorithm> // sort
|
|
Packit Service |
724aca |
#include <math.h> // log2
|
|
Packit Service |
724aca |
#include <cassert>
|
|
Packit Service |
724aca |
#include <iostream>
|
|
Packit Service |
724aca |
#include "framework.hpp"
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
namespace performance_tests
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
namespace ch = std::chrono;
|
|
Packit Service |
724aca |
using std::cout;
|
|
Packit Service |
724aca |
using std::endl;
|
|
Packit Service |
724aca |
using std::unique_lock;
|
|
Packit Service |
724aca |
using std::mutex;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
#ifdef __DEBUG
|
|
Packit Service |
724aca |
mutex g_coutMutex;
|
|
Packit Service |
724aca |
int g_msgLevel = 1;
|
|
Packit Service |
724aca |
#endif
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void Barrier::wait()
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
unique_lock<mutex> lock(m_barrierMutex);
|
|
Packit Service |
724aca |
// Decrement number of threads awaited at the barrier
|
|
Packit Service |
724aca |
m_waiting--;
|
|
Packit Service |
724aca |
if (m_waiting == 0) {
|
|
Packit Service |
724aca |
// Called by the last expected thread - notify all waiting threads and exit
|
|
Packit Service |
724aca |
m_cVar.notify_all();
|
|
Packit Service |
724aca |
// Store the time when barrier was released
|
|
Packit Service |
724aca |
if (m_releasedAt.tv_sec == 0 && m_releasedAt.tv_nsec == 0) {
|
|
Packit Service |
724aca |
clock_gettime(CLOCK_MONOTONIC, &m_releasedAt);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
// Wait unitl the last expected thread calls wait() on Barrier instance, or timeout occurs
|
|
Packit Service |
724aca |
m_cVar.wait_until(lock, ch::system_clock::now() + ch::seconds(10), []() {
|
|
Packit Service |
724aca |
return GetInstance().m_waiting == 0;
|
|
Packit Service |
724aca |
});
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
// Worker class
|
|
Packit Service |
724aca |
Worker::Worker(
|
|
Packit Service |
724aca |
uint32_t actionsCount,
|
|
Packit Service |
724aca |
const vector<size_t> &allocationSizes,
|
|
Packit Service |
724aca |
Operation *freeOperation,
|
|
Packit Service |
724aca |
memkind_t kind)
|
|
Packit Service |
724aca |
: m_actionsCount(actionsCount)
|
|
Packit Service |
724aca |
, m_allocationSizes(allocationSizes)
|
|
Packit Service |
724aca |
, m_actions(vector<Action*>(actionsCount, nullptr))
|
|
Packit Service |
724aca |
, m_kind(kind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
assert(freeOperation->getName() == OperationName::Free);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
Worker::~Worker()
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
for (Action *action : m_actions) { //each action
|
|
Packit Service |
724aca |
delete action;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void Worker::init(const vector<Operation *> &testOperations,
|
|
Packit Service |
724aca |
Operation *&freeOperation)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
for(uint32_t i = 0 ; i < m_actionsCount ; i++) {
|
|
Packit Service |
724aca |
int bucketSize = rand() % Operation::MaxBucketSize;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
for (Operation *operation : testOperations) { //each operation
|
|
Packit Service |
724aca |
if (operation->checkCondition(bucketSize)) {
|
|
Packit Service |
724aca |
size_t size = m_allocationSizes[m_allocationSizes.size() > 1 ? rand() %
|
|
Packit Service |
724aca |
m_allocationSizes.size() : 0];
|
|
Packit Service |
724aca |
m_actions[i] = new Action(
|
|
Packit Service |
724aca |
operation,
|
|
Packit Service |
724aca |
freeOperation,
|
|
Packit Service |
724aca |
m_kind,
|
|
Packit Service |
724aca |
size,
|
|
Packit Service |
724aca |
log2(rand() % size),
|
|
Packit Service |
724aca |
sizeof(void *) * (1 << ((rand() % Operation::MemalignMaxMultiplier))));
|
|
Packit Service |
724aca |
break;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void Worker::run()
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
m_thread = new thread(&Worker::work, this);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
#ifdef __DEBUG
|
|
Packit Service |
724aca |
uint16_t Worker::getId()
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
return m_threadId;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
void Worker::setId(uint16_t threadId)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
m_threadId = threadId;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
#endif
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void Worker::finish()
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
if (m_thread != nullptr) {
|
|
Packit Service |
724aca |
m_thread->join();
|
|
Packit Service |
724aca |
delete m_thread;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void Worker::work()
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
EMIT(1, "Entering barrier " << m_threadId)
|
|
Packit Service |
724aca |
Barrier::GetInstance().wait();
|
|
Packit Service |
724aca |
EMIT(1, "Starting thread " << m_threadId)
|
|
Packit Service |
724aca |
for (Action *action : m_actions) {
|
|
Packit Service |
724aca |
action->alloc();
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void Worker::clean()
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
EMIT(2, "Cleaning thread " << m_threadId)
|
|
Packit Service |
724aca |
for (Action *action : m_actions) {
|
|
Packit Service |
724aca |
action->free();
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
EMIT(1, "Thread " << m_threadId << " finished")
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
// PerformanceTest class
|
|
Packit Service |
724aca |
PerformanceTest::PerformanceTest(
|
|
Packit Service |
724aca |
size_t repeatsCount,
|
|
Packit Service |
724aca |
size_t threadsCount,
|
|
Packit Service |
724aca |
size_t operationsCount)
|
|
Packit Service |
724aca |
: m_repeatsCount(repeatsCount)
|
|
Packit Service |
724aca |
, m_discardCount(repeatsCount * (distardPercent / 100.0))
|
|
Packit Service |
724aca |
, m_threadsCount(threadsCount)
|
|
Packit Service |
724aca |
, m_operationsCount(operationsCount)
|
|
Packit Service |
724aca |
, m_executionMode(ExecutionMode::SingleInteration)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void PerformanceTest::setAllocationSizes(const vector<size_t> &allocationSizes)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
m_allocationSizes = allocationSizes;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void PerformanceTest::setOperations(const vector<vector<Operation *>>
|
|
Packit Service |
724aca |
&testOperations, Operation *freeOperation)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
m_testOperations = testOperations;
|
|
Packit Service |
724aca |
m_freeOperation = freeOperation;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void PerformanceTest::setExecutionMode(ExecutionMode executionMode)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
m_executionMode = executionMode;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void PerformanceTest::setKind(const vector<memkind_t> &kinds)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
m_kinds = kinds;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
inline void PerformanceTest::runIteration()
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
timespec iterationStop, iterationStart;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
Barrier::GetInstance().reset(m_threadsCount);
|
|
Packit Service |
724aca |
for (Worker *worker : m_workers) {
|
|
Packit Service |
724aca |
worker->run();
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
for (Worker *worker : m_workers) {
|
|
Packit Service |
724aca |
worker->finish();
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
EMIT(1, "Alloc completed");
|
|
Packit Service |
724aca |
clock_gettime(CLOCK_MONOTONIC, &iterationStop);
|
|
Packit Service |
724aca |
iterationStart = Barrier::GetInstance().releasedAt();
|
|
Packit Service |
724aca |
m_durations.push_back(
|
|
Packit Service |
724aca |
(iterationStop.tv_sec * NanoSecInSec + iterationStop.tv_nsec) -
|
|
Packit Service |
724aca |
(iterationStart.tv_sec * NanoSecInSec + iterationStart.tv_nsec)
|
|
Packit Service |
724aca |
);
|
|
Packit Service |
724aca |
for (Worker *worker : m_workers) {
|
|
Packit Service |
724aca |
worker->clean();
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void PerformanceTest::prepareWorkers()
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
for (size_t threadId = 0; threadId < m_threadsCount; threadId++) {
|
|
Packit Service |
724aca |
m_workers.push_back(
|
|
Packit Service |
724aca |
new Worker(
|
|
Packit Service |
724aca |
m_operationsCount,
|
|
Packit Service |
724aca |
m_allocationSizes,
|
|
Packit Service |
724aca |
m_freeOperation,
|
|
Packit Service |
724aca |
m_kinds.size() > 0 ? m_kinds[threadId % m_kinds.size()] : nullptr)
|
|
Packit Service |
724aca |
);
|
|
Packit Service |
724aca |
#ifdef __DEBUG
|
|
Packit Service |
724aca |
m_workers.back()->setId(threadId);
|
|
Packit Service |
724aca |
#endif
|
|
Packit Service |
724aca |
if (m_executionMode == ExecutionMode::SingleInteration) {
|
|
Packit Service |
724aca |
// In ManyIterations mode, operations will be set for each thread at the beginning of each iteration
|
|
Packit Service |
724aca |
m_workers.back()->init(m_testOperations[threadId % m_testOperations.size()],
|
|
Packit Service |
724aca |
m_freeOperation);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
Metrics PerformanceTest::getMetrics()
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
uint64_t totalDuration = 0;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
std::sort(m_durations.begin(), m_durations.end());
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
m_durations.erase(m_durations.end() - m_discardCount, m_durations.end());
|
|
Packit Service |
724aca |
for (uint64_t &duration : m_durations) {
|
|
Packit Service |
724aca |
totalDuration += duration;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
Metrics metrics;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
metrics.executedOperations = m_durations.size() * m_threadsCount *
|
|
Packit Service |
724aca |
m_operationsCount;
|
|
Packit Service |
724aca |
metrics.totalDuration = totalDuration;
|
|
Packit Service |
724aca |
metrics.repeatDuration = (double) totalDuration /
|
|
Packit Service |
724aca |
((uint64_t)m_durations.size() * NanoSecInSec);
|
|
Packit Service |
724aca |
metrics.iterationDuration = metrics.repeatDuration;
|
|
Packit Service |
724aca |
if (m_executionMode == ExecutionMode::ManyIterations) {
|
|
Packit Service |
724aca |
metrics.executedOperations *= m_testOperations.size();
|
|
Packit Service |
724aca |
metrics.iterationDuration /= m_testOperations.size();
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
metrics.operationsPerSecond = (double) metrics.executedOperations *
|
|
Packit Service |
724aca |
NanoSecInSec / totalDuration;
|
|
Packit Service |
724aca |
metrics.avgOperationDuration = (double) totalDuration /
|
|
Packit Service |
724aca |
metrics.executedOperations;
|
|
Packit Service |
724aca |
assert(metrics.iterationDuration != 0.0);
|
|
Packit Service |
724aca |
return metrics;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void PerformanceTest::writeMetrics(const string &suiteName,
|
|
Packit Service |
724aca |
const string &caseName, const string &fileName)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
Metrics metrics = getMetrics();
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
// For thousands separation
|
|
Packit Service |
724aca |
setlocale(LC_ALL, "");
|
|
Packit Service |
724aca |
if (!fileName.empty()) {
|
|
Packit Service |
724aca |
FILE *f;
|
|
Packit Service |
724aca |
if((f = fopen(fileName.c_str(), "a+"))) {
|
|
Packit Service |
724aca |
fprintf(f,
|
|
Packit Service |
724aca |
"%s;%s;%zu;%zu;%lu;%f;%f;%f;%f\n",
|
|
Packit Service |
724aca |
suiteName.c_str(),
|
|
Packit Service |
724aca |
caseName.c_str(),
|
|
Packit Service |
724aca |
m_repeatsCount,
|
|
Packit Service |
724aca |
m_threadsCount,
|
|
Packit Service |
724aca |
metrics.executedOperations,
|
|
Packit Service |
724aca |
metrics.operationsPerSecond,
|
|
Packit Service |
724aca |
metrics.avgOperationDuration,
|
|
Packit Service |
724aca |
metrics.iterationDuration,
|
|
Packit Service |
724aca |
metrics.repeatDuration);
|
|
Packit Service |
724aca |
fclose(f);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
printf("Operations/sec:\t\t\t%'f\n"
|
|
Packit Service |
724aca |
"Avg. operation duration:\t%f nsec\n"
|
|
Packit Service |
724aca |
"Iteration duration:\t\t%f sec\n"
|
|
Packit Service |
724aca |
"Repeat duration:\t\t%f sec\n",
|
|
Packit Service |
724aca |
metrics.operationsPerSecond,
|
|
Packit Service |
724aca |
metrics.avgOperationDuration,
|
|
Packit Service |
724aca |
metrics.iterationDuration,
|
|
Packit Service |
724aca |
metrics.repeatDuration);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
int PerformanceTest::run()
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
if (m_testOperations.empty() ||
|
|
Packit Service |
724aca |
m_allocationSizes.empty() ||
|
|
Packit Service |
724aca |
m_freeOperation == nullptr) {
|
|
Packit Service |
724aca |
cout << "ERROR: Test not initialized" << endl;
|
|
Packit Service |
724aca |
return 1;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
// Create threads
|
|
Packit Service |
724aca |
prepareWorkers();
|
|
Packit Service |
724aca |
//warmup kinds
|
|
Packit Service |
724aca |
void *alloc = nullptr;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
for (const memkind_t &kind : m_kinds) {
|
|
Packit Service |
724aca |
m_testOperations[0][0]->perform(kind, alloc, 1e6);
|
|
Packit Service |
724aca |
m_freeOperation->perform(kind, alloc);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
for (size_t repeat = 0; repeat < m_repeatsCount; repeat++) {
|
|
Packit Service |
724aca |
EMIT(1, "Test run #" << repeat)
|
|
Packit Service |
724aca |
if (m_executionMode == ExecutionMode::SingleInteration) {
|
|
Packit Service |
724aca |
runIteration();
|
|
Packit Service |
724aca |
} else {
|
|
Packit Service |
724aca |
// Perform each operations list in separate iteration, for each thread
|
|
Packit Service |
724aca |
for (vector<Operation *> &ops : m_testOperations) {
|
|
Packit Service |
724aca |
for (Worker *worker : m_workers) {
|
|
Packit Service |
724aca |
worker->init(ops, m_freeOperation);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
runIteration();
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return 0;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void PerformanceTest::showInfo()
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
printf("Test parameters: %lu repeats, %lu threads, %d operations per thread\n",
|
|
Packit Service |
724aca |
m_repeatsCount,
|
|
Packit Service |
724aca |
m_threadsCount,
|
|
Packit Service |
724aca |
m_operationsCount);
|
|
Packit Service |
724aca |
printf("Thread memory allocation operations:\n");
|
|
Packit Service |
724aca |
for (unsigned long i = 0; i < m_testOperations.size(); i++) {
|
|
Packit Service |
724aca |
if (m_executionMode == ExecutionMode::SingleInteration) {
|
|
Packit Service |
724aca |
printf("\tThread %lu,%lu,...\n", i, i + (m_testOperations.size()));
|
|
Packit Service |
724aca |
} else {
|
|
Packit Service |
724aca |
printf("\tIteration %lu\n", i);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
for (const Operation *op : m_testOperations[i]) {
|
|
Packit Service |
724aca |
printf("\t\t %s (bucket size: %d)\n", op->getNameStr().c_str(),
|
|
Packit Service |
724aca |
op->getBucketSize());
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
printf("Memory free operation:\n\t\t%s\n",
|
|
Packit Service |
724aca |
m_freeOperation->getNameStr().c_str());
|
|
Packit Service |
724aca |
printf("Allocation sizes:\n");
|
|
Packit Service |
724aca |
for (size_t size : m_allocationSizes) {
|
|
Packit Service |
724aca |
printf("\t\t%lu bytes\n", size);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|