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.

225 lines
6.5 KiB

  1. #include <iostream>
  2. #include <random>
  3. #include <vector>
  4. #include <string>
  5. #include <omp.h>
  6. #include "cache.hpp"
  7. static constexpr size_t SIZE_64_MIB = 64 * 1024 * 1024;
  8. dsacache::Cache CACHE;
  9. void InitCache(const std::string& device) {
  10. if (device == "default") {
  11. auto cache_policy = [](const int numa_dst_node, const int numa_src_node, const size_t data_size) {
  12. return numa_dst_node;
  13. };
  14. auto copy_policy = [](const int numa_dst_node, const int numa_src_node, const size_t data_size) {
  15. return std::vector<int>{ numa_dst_node };
  16. };
  17. auto mem_alloc = [](const int numa_node, const size_t data_size) {
  18. return reinterpret_cast<uint8_t*>(malloc(data_size));
  19. };
  20. auto mem_free = [](uint8_t* ptr, const size_t data_size) {
  21. free(ptr);
  22. };
  23. CACHE.Init(cache_policy,copy_policy,mem_alloc,mem_free);
  24. }
  25. else {
  26. std::cerr << "Given device '" << device << "' not supported!" << std::endl;
  27. exit(-1);
  28. }
  29. }
  30. uint8_t* GetRandomArray(const size_t size) {
  31. uint8_t* array = new uint8_t[size];
  32. std::uniform_int_distribution<uint8_t> unif(std::numeric_limits<uint8_t>::min(), std::numeric_limits<uint8_t>::max());
  33. std::default_random_engine re;
  34. for (size_t i = 0; i < size; i++) {
  35. array[i] = unif(re);
  36. }
  37. return array;
  38. }
  39. bool IsEqual(const uint8_t* a, const uint8_t* b, const size_t size) {
  40. for (size_t i = 0; i < size; i++) {
  41. try {
  42. if (a[i] != b[i]) return false;
  43. }
  44. catch (...) {
  45. return false;
  46. }
  47. }
  48. return true;
  49. }
  50. std::unique_ptr<dsacache::CacheData> PerformAccessAndTest(uint8_t* src, const size_t size, const int tid) {
  51. std::unique_ptr<dsacache::CacheData> data_cache = CACHE.Access(
  52. reinterpret_cast<uint8_t *>(src),
  53. size * sizeof(uint8_t)
  54. );
  55. data_cache->SetFlags(dsacache::FLAG_WAIT_WEAK);
  56. data_cache->WaitOnCompletion();
  57. uint8_t* cached_imm = reinterpret_cast<uint8_t *>(data_cache->GetDataLocation());
  58. // check the value immediately just to see if ram or cache was returned
  59. if (src == cached_imm) {
  60. std::cout << "[" << tid << "] Caching did not immediately yield different data location." << std::endl;
  61. }
  62. else if (cached_imm == nullptr) {
  63. std::cout << "[" << tid << "] Immediately got nullptr." << std::endl;
  64. }
  65. else {
  66. std::cout << "[" << tid << "] Immediately got different data location." << std::endl;
  67. }
  68. // waits for the completion of the asynchronous caching operation
  69. data_cache->SetFlags(dsacache::FLAG_DEFAULT);
  70. data_cache->WaitOnCompletion();
  71. // gets the cache-data-location from the struct
  72. uint8_t* cached = reinterpret_cast<uint8_t *>(data_cache->GetDataLocation());
  73. // tests on the resulting value
  74. if (src == cached) {
  75. std::cout << "[" << tid << "] Caching did not affect data location." << std::endl;
  76. }
  77. else if (cached == nullptr) {
  78. std::cerr << "[" << tid << "] Got nullptr from cache." << std::endl;
  79. }
  80. else {
  81. std::cout << "[" << tid << "] Got different data location from cache." << std::endl;
  82. }
  83. if (IsEqual(src,cached,size)) {
  84. std::cout << "[" << tid << "] Cached data is correct." << std::endl;
  85. }
  86. else {
  87. std::cerr << "[" << tid << "] Cached data is wrong." << std::endl;
  88. }
  89. return std::move(data_cache);
  90. }
  91. void RunTestST(const size_t size) {
  92. uint8_t* data = GetRandomArray(size);
  93. static constexpr int tid = 0;
  94. std::cout << "[" << tid << "] first access --- " << std::endl;
  95. PerformAccessAndTest(data, size, tid);
  96. std::cout << "[" << tid << "] second access --- " << std::endl;
  97. PerformAccessAndTest(data, size, tid);
  98. std::cout << "[" << tid << "] end of application --- " << std::endl;
  99. }
  100. void RunTestMT(const size_t size) {
  101. uint8_t* data = GetRandomArray(size);
  102. #pragma omp parallel
  103. {
  104. const int tid = omp_get_thread_num();
  105. std::cout << "[" << tid << "] first access --- " << std::endl;
  106. PerformAccessAndTest(data, size, tid);
  107. std::cout << "[" << tid << "] second access --- " << std::endl;
  108. PerformAccessAndTest(data, size, tid);
  109. std::cout << "[" << tid << "] end of block --- " << std::endl;
  110. }
  111. }
  112. void RunTestFlush(const size_t size) {
  113. uint8_t* data1 = GetRandomArray(size);
  114. uint8_t* data2 = GetRandomArray(size);
  115. uint8_t* data3 = GetRandomArray(size);
  116. static constexpr int tid = 0;
  117. std::cout << "[" << tid << "] first access to data d1 and keepalive --- " << std::endl;
  118. const auto c1 = PerformAccessAndTest(data1, size, tid);
  119. std::cout << "[" << tid << "] second access to d2 lets d2 vanish --- " << std::endl;
  120. PerformAccessAndTest(data2, size, tid);
  121. std::cout << "[" << tid << "] third access to d3 should clear d2 --- " << std::endl;
  122. PerformAccessAndTest(data3, size, tid);
  123. std::cout << "[" << tid << "] end of block and test d1 == cache1 --- " << std::endl;
  124. if (IsEqual(data1, c1->GetDataLocation(), size)) {
  125. std::cout << "[" << tid << "] Cached d1 is still correct." << std::endl;
  126. }
  127. else {
  128. std::cerr << "[" << tid << "] Cached d1 is bad." << std::endl;
  129. }
  130. }
  131. int main(int argc, char **argv) {
  132. if (argc != 4) {
  133. std::cerr << "This application requires three parameters!" << std::endl;
  134. std::cout << "Please provide the following positional arguments: [device] [mode] [size]" << std::endl;
  135. std::cout << "[device] from { default, xeonmax } which influences cache and execution placement" << std::endl;
  136. std::cout << "[mode] from { st, mt, flt } or single and multi threaded and flushtest respectively" << std::endl;
  137. std::cout << "[size] positive integral number, amount of bytes in data array" << std::endl;
  138. std::cout << "for flushtest the given size should be 1/3 of the available cache size" << std::endl;
  139. exit(-1);
  140. }
  141. const std::string device = argv[1];
  142. const std::string mode = argv[2];
  143. const std::string size_s = argv[3];
  144. uint32_t size = 0;
  145. try {
  146. size = std::stoul(size_s);
  147. }
  148. catch (...) {
  149. std::cerr << "Given Size '" << size_s << "' caused error during conversion to number!" << std::endl;
  150. }
  151. InitCache(device);
  152. if (mode == "st") {
  153. RunTestST(size);
  154. }
  155. else if (mode == "mt") {
  156. RunTestMT(size);
  157. }
  158. else if (mode == "flt") {
  159. RunTestFlush(size);
  160. }
  161. else {
  162. std::cerr << "Given Mode '" << mode << "' not supported!" << std::endl;
  163. exit(-1);
  164. }
  165. }