Mandel.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. #include "Mandel.h"
  2. #include "Fixed.h"
  3. #include "CpuGenerators.h"
  4. #include "ClGenerators.h"
  5. #include "OpenClInternal.h"
  6. #include "OpenClCode.h"
  7. #ifdef WITH_ASMJIT
  8. #include <asmjit/asmjit.h>
  9. #endif // WITH_ASMJIT
  10. #include <map>
  11. using mnd::MandelDevice;
  12. using mnd::MandelContext;
  13. using mnd::MandelGenerator;
  14. using mnd::AdaptiveGenerator;
  15. template<typename T, typename U>
  16. static std::map<U, T> invertMap(const std::map<T, U>& m)
  17. {
  18. std::map<U, T> res;
  19. std::transform(m.begin(), m.end(), std::inserter(res, res.end()), [](auto& pair) {
  20. return std::pair{ pair.second, pair.first };
  21. });
  22. return res;
  23. }
  24. static const std::map<mnd::GeneratorType, std::string> typeNames =
  25. {
  26. { mnd::GeneratorType::FLOAT, "float" },
  27. { mnd::GeneratorType::FLOAT_SSE2, "float SSE2" },
  28. { mnd::GeneratorType::FLOAT_AVX, "float AVX" },
  29. { mnd::GeneratorType::FLOAT_AVX_FMA, "float AVX+FMA" },
  30. { mnd::GeneratorType::FLOAT_AVX512, "float AVX512" },
  31. { mnd::GeneratorType::FLOAT_NEON, "float NEON" },
  32. { mnd::GeneratorType::DOUBLE_FLOAT, "double float" },
  33. { mnd::GeneratorType::DOUBLE, "double" },
  34. { mnd::GeneratorType::DOUBLE_SSE2, "double SSE2" },
  35. { mnd::GeneratorType::DOUBLE_AVX, "double AVX" },
  36. { mnd::GeneratorType::DOUBLE_AVX_FMA, "double AVX+FMA" },
  37. { mnd::GeneratorType::DOUBLE_AVX512, "double AVX512" },
  38. { mnd::GeneratorType::DOUBLE_NEON, "double NEON" },
  39. { mnd::GeneratorType::DOUBLE_DOUBLE, "double double" },
  40. { mnd::GeneratorType::DOUBLE_DOUBLE_AVX, "double double AVX" },
  41. { mnd::GeneratorType::DOUBLE_DOUBLE_AVX_FMA, "double double AVX+FMA" },
  42. { mnd::GeneratorType::DOUBLE_DOUBLE_NEON, "double double NEON" },
  43. { mnd::GeneratorType::TRIPLE_DOUBLE, "triple double" },
  44. { mnd::GeneratorType::QUAD_DOUBLE, "quad double" },
  45. { mnd::GeneratorType::QUAD_DOUBLE_AVX_FMA, "quad double AVX+FMA" },
  46. { mnd::GeneratorType::FLOAT128, "float128" },
  47. { mnd::GeneratorType::FLOAT256, "float256" },
  48. { mnd::GeneratorType::FIXED64, "fixed64" },
  49. { mnd::GeneratorType::FIXED128, "fixed128" },
  50. { mnd::GeneratorType::FIXED512, "fixed512" },
  51. };
  52. static const std::map<std::string, mnd::GeneratorType> nameTypes = invertMap(typeNames);
  53. namespace mnd
  54. {
  55. const std::string& getGeneratorName(mnd::GeneratorType type)
  56. {
  57. return typeNames.at(type);
  58. }
  59. mnd::GeneratorType getTypeFromName(const std::string& name)
  60. {
  61. return nameTypes.at(name);
  62. }
  63. }
  64. MandelContext mnd::initializeContext(void)
  65. {
  66. return MandelContext();
  67. }
  68. MandelDevice::MandelDevice(mnd::ClDeviceWrapper device, const std::string& platformName) :
  69. clDevice{ std::make_unique<ClDeviceWrapper>(std::move(device)) },
  70. platformName{ platformName }
  71. {
  72. extensions = clDevice->device.getInfo<CL_DEVICE_EXTENSIONS>();
  73. name = clDevice->device.getInfo<CL_DEVICE_NAME>();
  74. vendor = clDevice->device.getInfo<CL_DEVICE_VENDOR>();
  75. }
  76. mnd::MandelGenerator* MandelDevice::getGenerator(mnd::GeneratorType type) const
  77. {
  78. auto it = mandelGenerators.find(type);
  79. if (it != mandelGenerators.end())
  80. return it->second.get();
  81. else
  82. return nullptr;
  83. }
  84. std::vector<mnd::GeneratorType> MandelDevice::getSupportedTypes(void) const
  85. {
  86. std::vector<GeneratorType> types;
  87. for (auto& [type, gen] : mandelGenerators) {
  88. types.push_back(type);
  89. }
  90. return types;
  91. }
  92. bool MandelDevice::supportsDouble(void) const
  93. {
  94. return extensions.find("cl_khr_fp64") != std::string::npos;
  95. }
  96. MandelContext::MandelContext(void)
  97. #ifdef WITH_ASMJIT
  98. : jitRuntime{ std::make_unique<asmjit::JitRuntime>() }
  99. #endif // WITH_ASMJIT
  100. {
  101. #if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
  102. # if defined(WITH_AVX512)
  103. if (cpuInfo.hasAvx512()) {
  104. auto fl = std::make_unique<CpuGenerator<float, mnd::X86_AVX_512, true>>();
  105. auto db = std::make_unique<CpuGenerator<double, mnd::X86_AVX_512, true>>();
  106. cpuGenerators.insert({ GeneratorType::FLOAT_AVX512, std::move(fl) });
  107. cpuGenerators.insert({ GeneratorType::DOUBLE_AVX512, std::move(db) });
  108. }
  109. # endif
  110. if (cpuInfo.hasAvx()) {
  111. auto fl = std::make_unique<CpuGenerator<float, mnd::X86_AVX, true>>();
  112. auto db = std::make_unique<CpuGenerator<double, mnd::X86_AVX, true>>();
  113. auto ddb = std::make_unique<CpuGenerator<DoubleDouble, mnd::X86_AVX, true>>();
  114. cpuGenerators.insert({ GeneratorType::FLOAT_AVX, std::move(fl) });
  115. cpuGenerators.insert({ GeneratorType::DOUBLE_AVX, std::move(db) });
  116. cpuGenerators.insert({ GeneratorType::DOUBLE_DOUBLE_AVX, std::move(ddb) });
  117. }
  118. if (cpuInfo.hasAvx2() && cpuInfo.hasFma()) {
  119. auto favxfma = std::make_unique<CpuGenerator<float, mnd::X86_AVX_FMA, true>>();
  120. auto davxfma = std::make_unique<CpuGenerator<double, mnd::X86_AVX_FMA, true>>();
  121. auto ddavxfma = std::make_unique<CpuGenerator<DoubleDouble, mnd::X86_AVX_FMA, true>>();
  122. auto qdavxfma = std::make_unique<CpuGenerator<QuadDouble, mnd::X86_AVX_FMA, true>>();
  123. cpuGenerators.insert({ GeneratorType::FLOAT_AVX_FMA, std::move(favxfma) });
  124. cpuGenerators.insert({ GeneratorType::DOUBLE_AVX_FMA, std::move(davxfma) });
  125. cpuGenerators.insert({ GeneratorType::DOUBLE_DOUBLE_AVX_FMA, std::move(ddavxfma) });
  126. cpuGenerators.insert({ GeneratorType::QUAD_DOUBLE_AVX_FMA, std::move(qdavxfma) });
  127. }
  128. if (cpuInfo.hasSse2()) {
  129. auto fl = std::make_unique<CpuGenerator<float, mnd::X86_SSE2, true>>();
  130. auto db = std::make_unique<CpuGenerator<double, mnd::X86_SSE2, true>>();
  131. cpuGenerators.insert({ GeneratorType::FLOAT_SSE2, std::move(fl) });
  132. cpuGenerators.insert({ GeneratorType::DOUBLE_SSE2, std::move(db) });
  133. }
  134. #elif defined(__arm__) || defined(__aarch64__) || defined(_M_ARM)
  135. if (cpuInfo.hasNeon()) {
  136. auto fl = std::make_unique<CpuGenerator<float, mnd::ARM_NEON, true>>();
  137. auto db = std::make_unique<CpuGenerator<double, mnd::ARM_NEON, true>>();
  138. auto ddb = std::make_unique<CpuGenerator<mnd::DoubleDouble, mnd::ARM_NEON, true>>();
  139. cpuGenerators.insert({ GeneratorType::FLOAT_NEON, std::move(fl) });
  140. cpuGenerators.insert({ GeneratorType::DOUBLE_NEON, std::move(db) });
  141. cpuGenerators.insert({ GeneratorType::DOUBLE_DOUBLE_NEON, std::move(ddb) });
  142. }
  143. #endif
  144. {
  145. auto fl = std::make_unique<CpuGenerator<float, mnd::NONE, true>>();
  146. auto db = std::make_unique<CpuGenerator<double, mnd::NONE, true>>();
  147. cpuGenerators.insert({ GeneratorType::FLOAT, std::move(fl) });
  148. cpuGenerators.insert({ GeneratorType::DOUBLE, std::move(db) });
  149. auto fx64 = std::make_unique<CpuGenerator<Fixed64, mnd::NONE, true>>();
  150. auto fx128 = std::make_unique<CpuGenerator<Fixed128, mnd::NONE, true>>();
  151. cpuGenerators.insert({ GeneratorType::FIXED64, std::move(fx64) });
  152. cpuGenerators.insert({ GeneratorType::FIXED128, std::move(fx128) });
  153. }
  154. #ifdef WITH_BOOST
  155. auto quad = std::make_unique<CpuGenerator<Float128, mnd::NONE, true>>();
  156. auto oct = std::make_unique<CpuGenerator<Float256, mnd::NONE, true>>();
  157. cpuGenerators.insert({ GeneratorType::FLOAT128, std::move(quad) });
  158. cpuGenerators.insert({ GeneratorType::FLOAT256, std::move(oct) });
  159. #endif // WITH_BOOST
  160. auto dd = std::make_unique<CpuGenerator<DoubleDouble, mnd::NONE, true>>();
  161. auto qd = std::make_unique<CpuGenerator<QuadDouble, mnd::NONE, true>>();
  162. cpuGenerators.insert({ GeneratorType::DOUBLE_DOUBLE, std::move(dd) });
  163. cpuGenerators.insert({ GeneratorType::QUAD_DOUBLE, std::move(qd) });
  164. auto td = std::make_unique<CpuGenerator<TripleDouble, mnd::NONE, true>>();
  165. cpuGenerators.insert({ GeneratorType::TRIPLE_DOUBLE, std::move(td) });
  166. auto fix512 = std::make_unique<CpuGenerator<Fixed512, mnd::NONE, true>>();
  167. cpuGenerators.insert({ GeneratorType::FIXED512, std::move(fix512) });
  168. devices = createDevices();
  169. adaptiveGenerator = createAdaptiveGenerator();
  170. }
  171. std::unique_ptr<mnd::AdaptiveGenerator> MandelContext::createAdaptiveGenerator(void)
  172. {
  173. auto* floatGen = getCpuGenerator(GeneratorType::FLOAT);
  174. auto* doubleGen = getCpuGenerator(GeneratorType::DOUBLE);
  175. auto* doubleDoubleGen = getCpuGenerator(GeneratorType::DOUBLE_DOUBLE);
  176. auto* tripleDoubleGen = getCpuGenerator(GeneratorType::TRIPLE_DOUBLE);
  177. auto* quadDoubleGen = getCpuGenerator(GeneratorType::QUAD_DOUBLE);
  178. auto* f256Gen = getCpuGenerator(GeneratorType::FLOAT256);
  179. auto* fix512 = getCpuGenerator(GeneratorType::FIXED512);
  180. if (cpuInfo.hasAvx()) {
  181. floatGen = getCpuGenerator(GeneratorType::FLOAT_AVX);
  182. doubleGen = getCpuGenerator(GeneratorType::DOUBLE_AVX);
  183. }
  184. else if (cpuInfo.hasSse2()) {
  185. floatGen = getCpuGenerator(GeneratorType::FLOAT_SSE2);
  186. doubleGen = getCpuGenerator(GeneratorType::DOUBLE_SSE2);
  187. }
  188. if (cpuInfo.hasAvx2() && cpuInfo.hasFma()) {
  189. floatGen = getCpuGenerator(GeneratorType::FLOAT_AVX_FMA);
  190. doubleGen = getCpuGenerator(GeneratorType::DOUBLE_AVX_FMA);
  191. doubleDoubleGen = getCpuGenerator(GeneratorType::DOUBLE_DOUBLE_AVX_FMA);
  192. quadDoubleGen = getCpuGenerator(GeneratorType::QUAD_DOUBLE_AVX_FMA);
  193. }
  194. if (cpuInfo.hasAvx512()) {
  195. floatGen = getCpuGenerator(GeneratorType::FLOAT_AVX512);
  196. doubleGen = getCpuGenerator(GeneratorType::DOUBLE_AVX512);
  197. }
  198. if (cpuInfo.hasNeon()) {
  199. floatGen = getCpuGenerator(GeneratorType::FLOAT_NEON);
  200. doubleGen = getCpuGenerator(GeneratorType::DOUBLE_NEON);
  201. doubleDoubleGen = getCpuGenerator(GeneratorType::DOUBLE_DOUBLE_NEON);
  202. }
  203. if (!devices.empty()) {
  204. auto& device = devices[0];
  205. auto* fGen = device->getGenerator(GeneratorType::FLOAT);
  206. auto* dGen = device->getGenerator(GeneratorType::DOUBLE);
  207. auto* ddGen = device->getGenerator(GeneratorType::DOUBLE_DOUBLE);
  208. auto* tdGen = device->getGenerator(GeneratorType::TRIPLE_DOUBLE);
  209. auto* qdGen = device->getGenerator(GeneratorType::QUAD_DOUBLE);
  210. if (fGen)
  211. floatGen = fGen;
  212. if (dGen)
  213. doubleGen = dGen;
  214. if (ddGen)
  215. doubleDoubleGen = ddGen;
  216. if (tdGen)
  217. tripleDoubleGen = tdGen;
  218. if (qdGen)
  219. quadDoubleGen = qdGen;
  220. }
  221. auto ag = std::make_unique<AdaptiveGenerator>();
  222. ag->addGenerator(getPrecision<float>(), *floatGen);
  223. ag->addGenerator(getPrecision<double>(), *doubleGen);
  224. ag->addGenerator(getPrecision<DoubleDouble>(), *doubleDoubleGen);
  225. ag->addGenerator(getPrecision<TripleDouble>(), *tripleDoubleGen);
  226. ag->addGenerator(getPrecision<QuadDouble>(), *quadDoubleGen);
  227. ag->addGenerator(getPrecision<Float256>(), *f256Gen);
  228. ag->addGenerator(Precision::INF_PREC, *fix512);
  229. return ag;
  230. }
  231. std::vector<std::unique_ptr<MandelDevice>> MandelContext::createDevices(void)
  232. {
  233. std::vector<std::unique_ptr<MandelDevice>> mandelDevices;
  234. #ifdef WITH_OPENCL
  235. std::vector<cl::Platform> platforms;
  236. cl::Platform::get(&platforms);
  237. //platforms.erase(platforms.begin() + 1);
  238. for (auto& platform : platforms) {
  239. std::string platformName = platform.getInfo<CL_PLATFORM_NAME>();
  240. std::string profile = platform.getInfo<CL_PLATFORM_PROFILE>();
  241. //printf("using opencl platform: %s\n", platformName.c_str());
  242. std::string ext = platform.getInfo<CL_PLATFORM_EXTENSIONS>();
  243. //printf("Platform extensions: %s\n", ext.c_str());
  244. //printf("Platform: %s, %s\n", platformName.c_str(), profile.c_str());
  245. std::vector<cl::Device> devices;
  246. platform.getDevices(CL_DEVICE_TYPE_GPU, &devices);
  247. auto onError = [] (const char* errinfo,
  248. const void* private_info,
  249. size_t cb,
  250. void* user_data) {
  251. printf("opencl error: %s\n", errinfo);
  252. };
  253. cl::Context context{ devices, nullptr, onError };
  254. for (auto& device : devices) {
  255. //printf("Device: %s\n", device.getInfo<CL_DEVICE_NAME>().c_str());
  256. //printf("preferred float width: %d\n", device.getInfo<CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT>());
  257. //printf("vendor: %s\n", device.getInfo<CL_DEVICE_VENDOR>().c_str());
  258. //printf("Device extensions: %s\n", ext.c_str());
  259. auto mandelDevice = std::make_unique<mnd::MandelDevice>(
  260. ClDeviceWrapper{ device, context }, platformName);
  261. MandelDevice& md = *mandelDevice;
  262. auto supportsDouble = md.supportsDouble();
  263. //printf("clock: %d", device.getInfo<CL_DEVICE_MAX_CLOCK_FREQUENCY>());
  264. //printf(" using opencl device: %s\n", md.name.c_str());
  265. try {
  266. md.mandelGenerators.insert({ GeneratorType::FLOAT, std::make_unique<ClGeneratorFloat>(md) });
  267. md.mandelGenerators.insert({ GeneratorType::FIXED64, std::make_unique<ClGenerator64>(md) });
  268. //md.mandelGenerators.insert({ GeneratorType::FIXED128, std::make_unique<ClGenerator128>(md) });
  269. }
  270. catch (const std::string& err) {
  271. printf("err: %s", err.c_str());
  272. }
  273. try {
  274. md.mandelGenerators.insert({ GeneratorType::DOUBLE_FLOAT, std::make_unique<ClGeneratorDoubleFloat>(md) });
  275. }
  276. catch (const std::string& err) {
  277. printf("err: %s", err.c_str());
  278. }
  279. if (supportsDouble) {
  280. try {
  281. md.mandelGenerators.insert({ GeneratorType::DOUBLE, std::make_unique<ClGeneratorDouble>(md) });
  282. md.mandelGenerators.insert({ GeneratorType::DOUBLE_DOUBLE, std::make_unique<ClGeneratorDoubleDouble>(md) });
  283. md.mandelGenerators.insert({ GeneratorType::TRIPLE_DOUBLE, std::make_unique<ClGeneratorTripleDouble>(md) });
  284. md.mandelGenerators.insert({ GeneratorType::QUAD_DOUBLE, std::make_unique<ClGeneratorQuadDouble>(md) });
  285. }
  286. catch (const std::string& err) {
  287. printf("err: %s", err.c_str());
  288. fflush(stdout);
  289. }
  290. }
  291. try {
  292. //md.generator128 = std::make_unique<ClGenerator128>(device);
  293. }
  294. catch (const std::string& /*err*/) {
  295. //fprintf(stderr, "error creating 128bit cl generator: %s\n", err.c_str());
  296. }
  297. mandelDevices.push_back(std::move(mandelDevice));
  298. }
  299. }
  300. #endif // WITH_OPENCL
  301. return mandelDevices;
  302. }
  303. MandelContext::~MandelContext(void)
  304. {
  305. }
  306. AdaptiveGenerator& MandelContext::getDefaultGenerator(void)
  307. {
  308. return *adaptiveGenerator;
  309. }
  310. std::vector<std::unique_ptr<mnd::MandelDevice>>& MandelContext::getDevices(void)
  311. {
  312. return devices;
  313. }
  314. asmjit::JitRuntime& MandelContext::getJitRuntime(void)
  315. {
  316. return *jitRuntime;
  317. }
  318. MandelGenerator* MandelContext::getCpuGenerator(mnd::GeneratorType type)
  319. {
  320. auto it = cpuGenerators.find(type);
  321. if (it != cpuGenerators.end())
  322. return it->second.get();
  323. else
  324. return nullptr;
  325. }
  326. std::vector<mnd::GeneratorType> MandelContext::getSupportedTypes(void) const
  327. {
  328. std::vector<GeneratorType> types;
  329. for (auto& [type, gen] : cpuGenerators) {
  330. types.push_back(type);
  331. }
  332. return types;
  333. }