Mandel.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. #include "Mandel.h"
  2. #include "Fixed.h"
  3. #include "CpuGenerators.h"
  4. #include "ClGenerators.h"
  5. #include <map>
  6. using mnd::MandelDevice;
  7. using mnd::MandelContext;
  8. using mnd::Generator;
  9. using mnd::AdaptiveGenerator;
  10. template<typename T, typename U>
  11. static std::map<U, T> invertMap(const std::map<T, U>& m)
  12. {
  13. std::map<U, T> res;
  14. std::transform(m.begin(), m.end(), std::inserter(res, res.end()), [](auto& pair) {
  15. return std::pair{ pair.second, pair.first };
  16. });
  17. return res;
  18. }
  19. static const std::map<mnd::GeneratorType, std::string> typeNames =
  20. {
  21. { mnd::GeneratorType::FLOAT, "float" },
  22. { mnd::GeneratorType::FLOAT_SSE2, "float SSE2" },
  23. { mnd::GeneratorType::FLOAT_AVX, "float AVX" },
  24. { mnd::GeneratorType::FLOAT_AVX512, "float AVX512" },
  25. { mnd::GeneratorType::FLOAT_NEON, "float Neon" },
  26. { mnd::GeneratorType::DOUBLE, "double" },
  27. { mnd::GeneratorType::DOUBLE_SSE2, "double SSE2" },
  28. { mnd::GeneratorType::DOUBLE_AVX, "double AVX" },
  29. { mnd::GeneratorType::DOUBLE_AVX512, "double AVX512" },
  30. { mnd::GeneratorType::DOUBLE_NEON, "double Neon" },
  31. { mnd::GeneratorType::DOUBLE_DOUBLE, "double double" },
  32. { mnd::GeneratorType::DOUBLE_DOUBLE_AVX, "double double AVX" },
  33. { mnd::GeneratorType::DOUBLE_DOUBLE_AVX_FMA, "double double AVX+FMA" },
  34. { mnd::GeneratorType::QUAD_DOUBLE, "quad double" },
  35. { mnd::GeneratorType::FLOAT128, "float128" },
  36. { mnd::GeneratorType::FLOAT256, "float256" },
  37. { mnd::GeneratorType::FIXED512, "fixed512" },
  38. };
  39. static const std::map<std::string, mnd::GeneratorType> nameTypes = invertMap(typeNames);
  40. namespace mnd
  41. {
  42. const std::string& getGeneratorName(mnd::GeneratorType type)
  43. {
  44. return typeNames.at(type);
  45. }
  46. mnd::GeneratorType getTypeFromName(const std::string& name)
  47. {
  48. return nameTypes.at(name);
  49. }
  50. }
  51. MandelContext mnd::initializeContext(void)
  52. {
  53. MandelContext context = MandelContext();
  54. return context;
  55. }
  56. MandelDevice::MandelDevice(void)
  57. {
  58. }
  59. mnd::Generator* MandelDevice::getGenerator(mnd::GeneratorType type) const
  60. {
  61. auto it = generators.find(type);
  62. if (it != generators.end())
  63. return it->second.get();
  64. else
  65. return nullptr;
  66. }
  67. std::vector<mnd::GeneratorType> MandelDevice::getSupportedTypes(void) const
  68. {
  69. std::vector<GeneratorType> types;
  70. for (auto& [type, gen] : generators) {
  71. types.push_back(type);
  72. }
  73. return types;
  74. }
  75. MandelContext::MandelContext(void)
  76. {
  77. #if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
  78. if (cpuInfo.hasAvx()) {
  79. auto fl = std::make_unique<CpuGenerator<float, mnd::X86_AVX, true>>();
  80. auto db = std::make_unique<CpuGenerator<double, mnd::X86_AVX, true>>();
  81. auto ddb = std::make_unique<CpuGenerator<DoubleDouble, mnd::X86_AVX, true>>();
  82. cpuGenerators.insert({ GeneratorType::FLOAT_AVX, std::move(fl) });
  83. cpuGenerators.insert({ GeneratorType::DOUBLE_AVX, std::move(db) });
  84. cpuGenerators.insert({ GeneratorType::DOUBLE_DOUBLE_AVX, std::move(ddb) });
  85. if (cpuInfo.hasFma()) {
  86. auto ddavx = std::make_unique<CpuGenerator<DoubleDouble, mnd::X86_AVX_FMA, true>>();
  87. cpuGenerators.insert({ GeneratorType::DOUBLE_DOUBLE_AVX_FMA, std::move(ddavx) });
  88. }
  89. }
  90. if (cpuInfo.hasSse2()) {
  91. auto fl = std::make_unique<CpuGenerator<float, mnd::X86_SSE2, true>>();
  92. auto db = std::make_unique<CpuGenerator<double, mnd::X86_SSE2, true>>();
  93. cpuGenerators.insert({ GeneratorType::FLOAT_SSE2, std::move(fl) });
  94. cpuGenerators.insert({ GeneratorType::DOUBLE_SSE2, std::move(db) });
  95. }
  96. #elif defined(__aarch64__)
  97. if (cpuInfo.hasNeon()) {
  98. auto fl = std::make_unique<CpuGenerator<float, mnd::ARM_NEON, true>>();
  99. auto db = std::make_unique<CpuGenerator<double, mnd::ARM_NEON, true>>();
  100. cpuGenerators.insert({ GeneratorType::FLOAT_NEON, std::move(fl) });
  101. cpuGenerators.insert({ GeneratorType::DOUBLE_NEON, std::move(db) });
  102. }
  103. #endif
  104. {
  105. auto fl = std::make_unique<CpuGenerator<float, mnd::NONE, true>>();
  106. auto db = std::make_unique<CpuGenerator<double, mnd::NONE, true>>();
  107. cpuGenerators.insert({ GeneratorType::FLOAT, std::move(fl) });
  108. cpuGenerators.insert({ GeneratorType::DOUBLE, std::move(db) });
  109. }
  110. #ifdef WITH_BOOST
  111. auto quad = std::make_unique<CpuGenerator<Float128, mnd::NONE, true>>();
  112. auto oct = std::make_unique<CpuGenerator<Float256, mnd::NONE, true>>();
  113. cpuGenerators.insert({ GeneratorType::FLOAT128, std::move(quad) });
  114. cpuGenerators.insert({ GeneratorType::FLOAT256, std::move(oct) });
  115. #endif // WITH_BOOST
  116. #ifdef WITH_QD
  117. auto dd = std::make_unique<CpuGenerator<DoubleDouble, mnd::NONE, true>>();
  118. auto qd = std::make_unique<CpuGenerator<QuadDouble, mnd::NONE, true>>();
  119. cpuGenerators.insert({ GeneratorType::DOUBLE_DOUBLE, std::move(dd) });
  120. cpuGenerators.insert({ GeneratorType::QUAD_DOUBLE, std::move(qd) });
  121. #endif // WITH_QD
  122. auto fix512 = std::make_unique<CpuGenerator<Fixed512, mnd::NONE, true>>();
  123. cpuGenerators.insert({ GeneratorType::FIXED512, std::move(fix512) });
  124. devices = createDevices();
  125. adaptiveGenerator = createAdaptiveGenerator();
  126. }
  127. std::unique_ptr<mnd::AdaptiveGenerator> MandelContext::createAdaptiveGenerator(void)
  128. {
  129. auto* floatGen = getCpuGenerator(GeneratorType::FLOAT);
  130. auto* doubleGen = getCpuGenerator(GeneratorType::DOUBLE);
  131. auto* doubleDoubleGen = getCpuGenerator(GeneratorType::DOUBLE_DOUBLE);
  132. auto* quadDoubleGen = getCpuGenerator(GeneratorType::QUAD_DOUBLE);
  133. auto* f256Gen = getCpuGenerator(GeneratorType::FLOAT256);
  134. if (cpuInfo.hasAvx()) {
  135. floatGen = getCpuGenerator(GeneratorType::FLOAT_AVX);
  136. doubleGen = getCpuGenerator(GeneratorType::DOUBLE_AVX);
  137. }
  138. else if (cpuInfo.hasSse2()) {
  139. floatGen = getCpuGenerator(GeneratorType::FLOAT_SSE2);
  140. doubleGen = getCpuGenerator(GeneratorType::DOUBLE_SSE2);
  141. }
  142. if (cpuInfo.hasAvx() && cpuInfo.hasFma()) {
  143. doubleDoubleGen = getCpuGenerator(GeneratorType::DOUBLE_DOUBLE_AVX_FMA);
  144. }
  145. if (!devices.empty()) {
  146. auto& device = devices[0];
  147. auto* fGen = device.getGenerator(GeneratorType::FLOAT);
  148. auto* dGen = device.getGenerator(GeneratorType::DOUBLE);
  149. auto* ddGen = device.getGenerator(GeneratorType::DOUBLE_DOUBLE);
  150. if (fGen)
  151. floatGen = fGen;
  152. if (dGen)
  153. doubleGen = dGen;
  154. if (ddGen)
  155. doubleDoubleGen = ddGen;
  156. }
  157. auto ag = std::make_unique<AdaptiveGenerator>();
  158. ag->addGenerator(Precision::FLOAT, *floatGen);
  159. ag->addGenerator(Precision::DOUBLE, *doubleGen);
  160. ag->addGenerator(Precision::DOUBLE_DOUBLE, *doubleDoubleGen);
  161. ag->addGenerator(Precision::QUAD_DOUBLE, *quadDoubleGen);
  162. ag->addGenerator(Precision::FLOAT256, *f256Gen);
  163. ag->addGenerator(Precision::INF_PREC, *f256Gen);
  164. return ag;
  165. }
  166. std::vector<MandelDevice> MandelContext::createDevices(void)
  167. {
  168. std::vector<MandelDevice> mandelDevices;
  169. #ifdef WITH_OPENCL
  170. std::vector<cl::Platform> platforms;
  171. cl::Platform::get(&platforms);
  172. //platforms.erase(platforms.begin() + 1);
  173. for (auto& platform : platforms) {
  174. std::string name = platform.getInfo<CL_PLATFORM_NAME>();
  175. std::string profile = platform.getInfo<CL_PLATFORM_PROFILE>();
  176. //printf("using opencl platform: %s\n", name.c_str());
  177. //std::string ext = platform.getInfo<CL_PLATFORM_EXTENSIONS>();
  178. //printf("Platform extensions: %s\n", ext.c_str());
  179. //printf("Platform: %s, %s\n", name.c_str(), profile.c_str());
  180. std::vector<cl::Device> devices;
  181. platform.getDevices(CL_DEVICE_TYPE_GPU, &devices);
  182. for (auto& device : devices) {
  183. //printf("Device: %s\n", device.getInfo<CL_DEVICE_NAME>().c_str());
  184. //printf("preferred float width: %d\n", device.getInfo<CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT>());
  185. //printf("vendor: %s\n", device.getInfo<CL_DEVICE_VENDOR>().c_str());
  186. std::string extensions = device.getInfo<CL_DEVICE_EXTENSIONS>();
  187. auto supportsDouble = extensions.find("cl_khr_fp64") != std::string::npos;
  188. //printf("Device extensions: %s\n", ext.c_str());
  189. MandelDevice md;
  190. //printf("clock: %d", device.getInfo<CL_DEVICE_MAX_CLOCK_FREQUENCY>());
  191. md.name = device.getInfo<CL_DEVICE_NAME>();
  192. md.vendor = device.getInfo<CL_DEVICE_VENDOR>();
  193. //printf(" using opencl device: %s\n", md.name.c_str());
  194. try {
  195. md.generators.insert({ GeneratorType::FLOAT, std::make_unique<ClGeneratorFloat>(device) });
  196. }
  197. catch (const std::string& err) {
  198. printf("err: %s", err.c_str());
  199. }
  200. if (supportsDouble) {
  201. try {
  202. md.generators.insert({ GeneratorType::DOUBLE, std::make_unique<ClGeneratorDouble>(device) });
  203. md.generators.insert({ GeneratorType::DOUBLE_DOUBLE, std::make_unique<ClGeneratorDoubleDouble>(device) });
  204. md.generators.insert({ GeneratorType::QUAD_DOUBLE, std::make_unique<ClGeneratorQuadDouble>(device) });
  205. }
  206. catch (const std::string& err) {
  207. printf("err: %s", err.c_str());
  208. fflush(stdout);
  209. }
  210. }
  211. try {
  212. //md.generator128 = std::make_unique<ClGenerator128>(device);
  213. }
  214. catch (const std::string& err) {
  215. //fprintf(stderr, "error creating 128bit cl generator: %s\n", err.c_str());
  216. }
  217. mandelDevices.push_back(std::move(md));
  218. }
  219. }
  220. #endif // WITH_OPENCL
  221. return mandelDevices;
  222. }
  223. AdaptiveGenerator& MandelContext::getDefaultGenerator(void)
  224. {
  225. return *adaptiveGenerator;
  226. }
  227. const std::vector<MandelDevice>& MandelContext::getDevices(void)
  228. {
  229. return devices;
  230. }
  231. Generator* MandelContext::getCpuGenerator(mnd::GeneratorType type)
  232. {
  233. auto it = cpuGenerators.find(type);
  234. if (it != cpuGenerators.end())
  235. return it->second.get();
  236. else
  237. return nullptr;
  238. }
  239. std::vector<mnd::GeneratorType> MandelContext::getSupportedTypes(void) const
  240. {
  241. std::vector<GeneratorType> types;
  242. for (auto& [type, gen] : cpuGenerators) {
  243. types.push_back(type);
  244. }
  245. return types;
  246. }