This contains my bachelors thesis and associated tex files, code snippets and maybe more. Topic: Data Movement in Heterogeneous Memories with Intel Data Streaming Accelerator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

193 lines
5.6 KiB

#include <iostream>
#include <random>
#include <vector>
#include <string>
#include <omp.h>
#include "cache.hpp"
dsacache::Cache CACHE;
void InitCache(const std::string& device) {
if (device == "default") {
auto cache_policy = [](const int numa_dst_node, const int numa_src_node, const size_t data_size) {
return numa_dst_node;
};
auto copy_policy = [](const int numa_dst_node, const int numa_src_node) {
return std::vector<int>{ numa_src_node, numa_dst_node };
};
CACHE.Init(cache_policy,copy_policy);
}
else if (device == "xeonmax") {
auto cache_policy = [](const int numa_dst_node, const int numa_src_node, const size_t data_size) {
return numa_dst_node < 8 ? numa_dst_node + 8 : numa_dst_node;
};
auto copy_policy = [](const int numa_dst_node, const int numa_src_node) {
const bool same_socket = ((numa_dst_node ^ numa_src_node) & 4) == 0;
if (same_socket) {
const bool socket_number = numa_dst_node >> 2;
if (socket_number == 0) return std::vector<int>{ 0, 1, 2, 3 };
else return std::vector<int>{ 4, 5, 6, 7 };
}
else return std::vector<int>{ numa_src_node, numa_dst_node };
};
CACHE.Init(cache_policy,copy_policy);
}
else {
std::cerr << "Given device '" << device << "' not supported!" << std::endl;
exit(-1);
}
}
double* GetRandomArray(const size_t size) {
double* array = new double[size];
std::uniform_real_distribution<double> unif(std::numeric_limits<double>::min(), std::numeric_limits<double>::max());
std::default_random_engine re;
for (size_t i = 0; i < size; i++) {
array[i] = unif(re);
}
return array;
}
bool IsEqual(const double* a, const double* b, const size_t size) {
for (size_t i = 0; i < size; i++) {
try {
if (a[i] != b[i]) return false;
}
catch (...) {
return false;
}
}
return true;
}
void PerformAccessAndTest(double* src, const size_t size, const int tid) {
std::unique_ptr<dsacache::CacheData> data_cache = CACHE.Access(
reinterpret_cast<uint8_t *>(src),
size * sizeof(double)
);
double* cached_imm = reinterpret_cast<double *>(data_cache->GetDataLocation());
// check the value immediately just to see if ram or cache was returned
if (src == cached_imm) {
std::cout << "[" << tid << "] Caching did not immediately yield different data location." << std::endl;
}
else if (cached_imm == nullptr) {
std::cout << "[" << tid << "] Immediately got nullptr." << std::endl;
}
else {
std::cout << "[" << tid << "] Immediately got different data location." << std::endl;
}
// waits for the completion of the asynchronous caching operation
data_cache->WaitOnCompletion();
// gets the cache-data-location from the struct
double* cached = reinterpret_cast<double *>(data_cache->GetDataLocation());
// tests on the resulting value
if (src == cached) {
std::cout << "[" << tid << "] Caching did not affect data location." << std::endl;
}
else if (cached == nullptr) {
std::cerr << "[" << tid << "] Got nullptr from cache." << std::endl;
}
else {
std::cout << "[" << tid << "] Got different data location from cache." << std::endl;
}
if (IsEqual(src,cached,size)) {
std::cout << "[" << tid << "] Cached data is correct." << std::endl;
}
else {
std::cerr << "[" << tid << "] Cached data is wrong." << std::endl;
}
}
void RunTestST(const size_t size) {
double* data = GetRandomArray(size);
static constexpr int tid = 0;
std::cout << "[" << tid << "] first access --- " << std::endl;
PerformAccessAndTest(data, size, tid);
std::cout << "[" << tid << "] second access --- " << std::endl;
PerformAccessAndTest(data, size, tid);
std::cout << "[" << tid << "] end of application --- " << std::endl;
}
void RunTestMT(const size_t size) {
double* data = GetRandomArray(size);
#pragma omp parallel
{
const int tid = omp_get_thread_num();
std::cout << "[" << tid << "] first access --- " << std::endl;
PerformAccessAndTest(data, size, tid);
std::cout << "[" << tid << "] second access --- " << std::endl;
PerformAccessAndTest(data, size, tid);
std::cout << "[" << tid << "] end of block --- " << std::endl;
}
}
int main(int argc, char **argv) {
if (argc != 4) {
std::cerr << "This application requires four parameters!" << std::endl;
std::cout << "Please provide the following positional arguments: [device] [mode] [size]" << std::endl;
std::cout << "[device] from { default, xeonmax } which influences cache and execution placement" << std::endl;
std::cout << "[mode] from { st, mt } or single and multi threaded respectively" << std::endl;
std::cout << "[size] positive integral number, amount of float64 in data array" << std::endl;
exit(-1);
}
const std::string device = argv[1];
const std::string mode = argv[2];
const std::string size_s = argv[3];
uint32_t size = 0;
try {
size = std::stoul(size_s);
}
catch (...) {
std::cerr << "Given Size '" << size_s << "' caused error during conversion to number!" << std::endl;
}
InitCache(device);
if (mode == "st") {
RunTestST(size);
}
else if (mode == "mt") {
RunTestMT(size);
}
else {
std::cerr << "Given Mode '" << mode << "' not supported!" << std::endl;
exit(-1);
}
}