diff --git a/rai/core_test/node.cpp b/rai/core_test/node.cpp index 4e5cc3ad..04130d5e 100644 --- a/rai/core_test/node.cpp +++ b/rai/core_test/node.cpp @@ -19,7 +19,7 @@ TEST (node, block_store_path_failure) auto service (boost::make_shared ()); rai::alarm alarm (*service); rai::logging logging; - rai::work_pool work (false); + rai::work_pool work (nullptr); auto node (std::make_shared (init, *service, 0, rai::unique_path (), alarm, logging, work)); ASSERT_TRUE (node->wallets.items.empty ()); node->stop (); @@ -31,7 +31,7 @@ TEST (node, inactive_supply) auto service (boost::make_shared ()); rai::alarm alarm (*service); rai::node_config config; - rai::work_pool work (false); + rai::work_pool work (nullptr); config.inactive_supply = 10; auto node (std::make_shared (init, *service, rai::unique_path (), alarm, config, work)); ASSERT_EQ (10, node->ledger.inactive_supply); @@ -43,7 +43,7 @@ TEST (node, password_fanout) auto service (boost::make_shared ()); rai::alarm alarm (*service); rai::node_config config; - rai::work_pool work (false); + rai::work_pool work (nullptr); config.password_fanout = 10; auto node (std::make_shared (init, *service, rai::unique_path (), alarm, config, work)); auto wallet (node->wallets.create (100)); diff --git a/rai/core_test/work_pool.cpp b/rai/core_test/work_pool.cpp index a29dd4b7..ab6c0721 100644 --- a/rai/core_test/work_pool.cpp +++ b/rai/core_test/work_pool.cpp @@ -4,7 +4,7 @@ TEST (work, one) { - rai::work_pool pool (false); + rai::work_pool pool (nullptr); rai::change_block block (1, 1, rai::keypair ().prv, 3, 4); block.block_work_set (pool.generate (block.root ())); ASSERT_FALSE (pool.work_validate (block)); @@ -12,7 +12,7 @@ TEST (work, one) TEST (work, validate) { - rai::work_pool pool (false); + rai::work_pool pool (nullptr); rai::send_block send_block (1, 1, 2, rai::keypair ().prv, 4, 6); ASSERT_TRUE (pool.work_validate (send_block)); send_block.block_work_set (pool.generate (send_block.root ())); @@ -21,7 +21,7 @@ TEST (work, validate) TEST (work, cancel) { - rai::work_pool pool (false); + rai::work_pool pool (nullptr); rai::uint256_union key (1); bool exited (false); std::thread thread ([&pool, &key, &exited] () @@ -41,7 +41,9 @@ TEST (work, cancel) TEST (work, opencl) { - rai::work_pool pool (true); + auto work (rai::opencl_work::create (true, 0, 1)); + ASSERT_NE (nullptr, work); + rai::work_pool pool (std::move (work)); ASSERT_NE (nullptr, pool.opencl); rai::uint256_union root; for (auto i (0); i < 1; ++i) diff --git a/rai/node/node.cpp b/rai/node/node.cpp index 708b49e9..a16f3c17 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -2968,7 +2968,7 @@ bool rai::handle_node_options (boost::program_options::variables_map & vm) rai::inactive_node::inactive_node () : service (boost::make_shared ()), alarm (*service), -work (false) +work (nullptr) { auto working (rai::working_path ()); boost::filesystem::create_directories (working); diff --git a/rai/node/node.hpp b/rai/node/node.hpp index 59017a47..21aa9410 100644 --- a/rai/node/node.hpp +++ b/rai/node/node.hpp @@ -308,6 +308,8 @@ public: unsigned io_threads; unsigned work_threads; bool opencl_work; + unsigned opencl_platform; + unsigned opencl_device; static std::chrono::seconds constexpr keepalive_period = std::chrono::seconds (60); static std::chrono::seconds constexpr keepalive_cutoff = keepalive_period * 5; static std::chrono::minutes constexpr wallet_backup_interval = std::chrono::minutes (5); diff --git a/rai/node/openclwork.cpp b/rai/node/openclwork.cpp index 605a0cf3..f108e894 100644 --- a/rai/node/openclwork.cpp +++ b/rai/node/openclwork.cpp @@ -396,15 +396,16 @@ rai::opencl_environment::opencl_environment (bool & error_a) clGetPlatformIDs (platformIdCount, platformIds.data(), nullptr); for (auto i (platformIds.begin ()), n (platformIds.end ()); i != n; ++i) { - auto & devices_container (devices [*i]); + rai::opencl_platform platform; cl_uint deviceIdCount = 0; clGetDeviceIDs (*i, CL_DEVICE_TYPE_ALL, 0, nullptr, &deviceIdCount); std::vector deviceIds (deviceIdCount); clGetDeviceIDs (*i, CL_DEVICE_TYPE_ALL, deviceIdCount, deviceIds.data (), nullptr); for (auto j (deviceIds.begin ()), m (deviceIds.end ()); j != m; ++j) { - devices_container.push_back (*j); + platform.devices.push_back (*j); } + platforms.push_back (platform); } } @@ -412,27 +413,27 @@ void rai::opencl_environment::dump () { auto index (0); auto device_count (0); - for (auto & i: devices) + for (auto & i: platforms) { - device_count += i.second.size (); + device_count += i.devices.size (); } - std::cout << boost::str (boost::format ("Found %1% platforms and %2% devices\n") % devices.size () % device_count); - for (auto i (devices.begin ()), n (devices.end ()); i != n; ++i, ++index) + std::cout << boost::str (boost::format ("Found %1% platforms and %2% devices\n") % platforms.size () % device_count); + for (auto i (platforms.begin ()), n (platforms.end ()); i != n; ++i, ++index) { std::vector queries = {CL_PLATFORM_PROFILE, CL_PLATFORM_VERSION, CL_PLATFORM_NAME, CL_PLATFORM_VENDOR, CL_PLATFORM_EXTENSIONS}; std::cout << "Platform: " << index << std::endl; for (auto j (queries.begin ()), m (queries.end ()); j != m; ++j) { size_t platformInfoCount = 0; - clGetPlatformInfo(i->first, *j, 0, nullptr, &platformInfoCount); + clGetPlatformInfo(i->platform, *j, 0, nullptr, &platformInfoCount); std::vector info (platformInfoCount); - clGetPlatformInfo(i->first, *j, info.size (), info.data (), nullptr); + clGetPlatformInfo(i->platform, *j, info.size (), info.data (), nullptr); std::cout << info.data () << std::endl; } - for (auto j (i->second.begin ()), m (i->second.end ()); j != m; ++j) + for (auto j (i->devices.begin ()), m (i->devices.end ()); j != m; ++j) { std::vector queries = {CL_DEVICE_NAME, CL_DEVICE_VENDOR, CL_DEVICE_PROFILE}; - std::cout << "Device: " << j - i->second.begin () << std::endl; + std::cout << "Device: " << j - i->devices.begin () << std::endl; for (auto k (queries.begin ()), o (queries.end ()); k != o; ++k) { size_t platformInfoCount = 0; @@ -483,95 +484,101 @@ void rai::opencl_environment::dump () } } -rai::opencl_work::opencl_work (bool & error_a, rai::opencl_environment & environment_a, rai::work_pool & pool_a) : +rai::opencl_work::opencl_work (bool & error_a, unsigned platform_a, unsigned device_a, rai::opencl_environment & environment_a) : context (0), attempt_buffer (0), result_buffer (0), item_buffer (0), program (0), kernel (0), -queue (0), -pool (pool_a) +queue (0) { - rai::random_pool.GenerateBlock (reinterpret_cast (rand.s.data ()), rand.s.size () * sizeof (decltype (rand.s)::value_type)); - auto i (environment_a.devices.begin ()); - auto selected_platform (i->first); - std::array selected_devices; - selected_devices [0] = i->second [0]; - cl_context_properties contextProperties [] = - { - CL_CONTEXT_PLATFORM, - reinterpret_cast (selected_platform), - 0, 0 - }; - cl_int createContextError (0); - context = clCreateContext (contextProperties, selected_devices.size (), selected_devices.data (), nullptr, nullptr, &createContextError); - error_a |= createContextError != CL_SUCCESS; + error_a |= platform_a >= environment_a.platforms.size (); if (!error_a) { - cl_int queue_error (0); - queue = clCreateCommandQueue (context, selected_devices [0], 0, &queue_error); - error_a |= queue_error != CL_SUCCESS; - if (!error_a) + auto & platform (environment_a.platforms [platform_a]); + error_a |= device_a >= platform.devices.size (); + if (error_a) { - cl_int attempt_error (0); - attempt_buffer = clCreateBuffer (context, 0, sizeof (uint64_t), nullptr, &attempt_error); - error_a |= attempt_error != CL_SUCCESS; + rai::random_pool.GenerateBlock (reinterpret_cast (rand.s.data ()), rand.s.size () * sizeof (decltype (rand.s)::value_type)); + std::array selected_devices; + selected_devices [0] = platform.devices [device_a]; + cl_context_properties contextProperties [] = + { + CL_CONTEXT_PLATFORM, + reinterpret_cast (platform.platform), + 0, 0 + }; + cl_int createContextError (0); + context = clCreateContext (contextProperties, selected_devices.size (), selected_devices.data (), nullptr, nullptr, &createContextError); + error_a |= createContextError != CL_SUCCESS; if (!error_a) { - cl_int result_error (0); - result_buffer = clCreateBuffer (context, 0, sizeof (uint64_t), nullptr, &result_error); - error_a |= result_error != CL_SUCCESS; + cl_int queue_error (0); + queue = clCreateCommandQueue (context, selected_devices [0], 0, &queue_error); + error_a |= queue_error != CL_SUCCESS; if (!error_a) { - cl_int item_error (0); - size_t item_size (sizeof (rai::uint256_union)); - item_buffer = clCreateBuffer (context, 0, item_size, nullptr, &item_error); - error_a |= item_error != CL_SUCCESS; + cl_int attempt_error (0); + attempt_buffer = clCreateBuffer (context, 0, sizeof (uint64_t), nullptr, &attempt_error); + error_a |= attempt_error != CL_SUCCESS; if (!error_a) { - cl_int program_error (0); - char const * program_data (opencl_program.data ()); - size_t program_length (opencl_program.size ()); - program = clCreateProgramWithSource (context, 1, &program_data, &program_length, &program_error); - error_a |= program_error != CL_SUCCESS; + cl_int result_error (0); + result_buffer = clCreateBuffer (context, 0, sizeof (uint64_t), nullptr, &result_error); + error_a |= result_error != CL_SUCCESS; if (!error_a) { - auto clBuildProgramError(clBuildProgram(program, selected_devices.size(), selected_devices.data(), "-D __APPLE__", nullptr, nullptr)); - error_a |= clBuildProgramError != CL_SUCCESS; + cl_int item_error (0); + size_t item_size (sizeof (rai::uint256_union)); + item_buffer = clCreateBuffer (context, 0, item_size, nullptr, &item_error); + error_a |= item_error != CL_SUCCESS; if (!error_a) { - cl_int kernel_error (0); - kernel = clCreateKernel (program, "raiblocks_work", &kernel_error); - error_a |= kernel_error != CL_SUCCESS; + cl_int program_error (0); + char const * program_data (opencl_program.data ()); + size_t program_length (opencl_program.size ()); + program = clCreateProgramWithSource (context, 1, &program_data, &program_length, &program_error); + error_a |= program_error != CL_SUCCESS; if (!error_a) { - cl_int arg0_error (clSetKernelArg (kernel, 0, sizeof (attempt_buffer), &attempt_buffer)); - error_a |= arg0_error != CL_SUCCESS; + auto clBuildProgramError(clBuildProgram(program, selected_devices.size(), selected_devices.data(), "-D __APPLE__", nullptr, nullptr)); + error_a |= clBuildProgramError != CL_SUCCESS; if (!error_a) { - cl_int arg1_error (clSetKernelArg (kernel, 1, sizeof (result_buffer), &result_buffer)); - error_a |= arg1_error != CL_SUCCESS; + cl_int kernel_error (0); + kernel = clCreateKernel (program, "raiblocks_work", &kernel_error); + error_a |= kernel_error != CL_SUCCESS; if (!error_a) { - cl_int arg2_error (clSetKernelArg (kernel, 2, sizeof (item_buffer), &item_buffer)); - error_a |= arg2_error != CL_SUCCESS; + cl_int arg0_error (clSetKernelArg (kernel, 0, sizeof (attempt_buffer), &attempt_buffer)); + error_a |= arg0_error != CL_SUCCESS; + if (!error_a) + { + cl_int arg1_error (clSetKernelArg (kernel, 1, sizeof (result_buffer), &result_buffer)); + error_a |= arg1_error != CL_SUCCESS; + if (!error_a) + { + cl_int arg2_error (clSetKernelArg (kernel, 2, sizeof (item_buffer), &item_buffer)); + error_a |= arg2_error != CL_SUCCESS; + } + } } } + else + { + /* + for (auto i (selected_devices.begin ()), n (selected_devices.end ()); i != n; ++i) + { + size_t log_size (0); + clGetProgramBuildInfo (program, *i, CL_PROGRAM_BUILD_LOG, 0, nullptr, &log_size); + std::vector log (log_size); + clGetProgramBuildInfo (program, *i, CL_PROGRAM_BUILD_LOG, log.size (), log.data (), nullptr); + std::cout << log.data () << std::endl; + }*/ + } } } - else - { - /* - for (auto i (selected_devices.begin ()), n (selected_devices.end ()); i != n; ++i) - { - size_t log_size (0); - clGetProgramBuildInfo (program, *i, CL_PROGRAM_BUILD_LOG, 0, nullptr, &log_size); - std::vector log (log_size); - clGetProgramBuildInfo (program, *i, CL_PROGRAM_BUILD_LOG, log.size (), log.data (), nullptr); - std::cout << log.data () << std::endl; - }*/ - } } } } @@ -587,13 +594,13 @@ rai::opencl_work::~opencl_work () clReleaseContext (context); } -uint64_t rai::opencl_work::generate_work (rai::uint256_union const & root_a) +uint64_t rai::opencl_work::generate_work (rai::work_pool & pool_a, rai::uint256_union const & root_a) { std::lock_guard lock (mutex); uint64_t result (0); unsigned thread_count (rai::rai_network == rai::rai_networks::rai_test_network ? 128 : 1024 * 1024); size_t work_size [] = { thread_count, 0, 0 }; - while (pool.work_validate (root_a, result)) + while (pool_a.work_validate (root_a, result)) { result = rand.next (); cl_int write_error1 = clEnqueueWriteBuffer (queue, attempt_buffer, false, 0, sizeof (uint64_t), &result, 0, nullptr, nullptr); @@ -604,3 +611,22 @@ uint64_t rai::opencl_work::generate_work (rai::uint256_union const & root_a) } return result; } + +std::unique_ptr rai::opencl_work::create (bool create_a, unsigned platform_a, unsigned device_a) +{ + std::unique_ptr result; + if (create_a) + { + auto error (false); + rai::opencl_environment environment (error); + if (!error) + { + result.reset (new rai::opencl_work (error, platform_a, device_a, environment)); + if (error) + { + result.reset (); + } + } + } + return result; +} diff --git a/rai/node/openclwork.hpp b/rai/node/openclwork.hpp index ba3c7cc0..9e51f3de 100644 --- a/rai/node/openclwork.hpp +++ b/rai/node/openclwork.hpp @@ -14,21 +14,28 @@ namespace rai { +class opencl_platform +{ +public: + cl_platform_id platform; + std::vector devices; +}; class opencl_environment { public: opencl_environment (bool &); void dump (); - std::map > devices; + std::vector platforms; }; union uint256_union; class work_pool; class opencl_work { public: - opencl_work (bool &, rai::opencl_environment &, rai::work_pool &); + opencl_work (bool &, unsigned, unsigned, rai::opencl_environment &); ~opencl_work (); - uint64_t generate_work (rai::uint256_union const &); + uint64_t generate_work (rai::work_pool &, rai::uint256_union const &); + static std::unique_ptr create (bool, unsigned, unsigned); std::mutex mutex; cl_context context; cl_mem attempt_buffer; @@ -38,6 +45,5 @@ public: cl_kernel kernel; cl_command_queue queue; rai::xorshift1024star rand; - rai::work_pool & pool; }; } \ No newline at end of file diff --git a/rai/node/testing.cpp b/rai/node/testing.cpp index 9824de33..c504a9b8 100644 --- a/rai/node/testing.cpp +++ b/rai/node/testing.cpp @@ -6,7 +6,7 @@ rai::system::system (uint16_t port_a, size_t count_a) : service (new boost::asio::io_service), alarm (*service), -work (false) +work (nullptr) { nodes.reserve (count_a); for (size_t i (0); i < count_a; ++i) diff --git a/rai/node/wallet.cpp b/rai/node/wallet.cpp index 29ad6c47..84a6489f 100644 --- a/rai/node/wallet.cpp +++ b/rai/node/wallet.cpp @@ -12,10 +12,11 @@ #include -rai::work_pool::work_pool (bool opencl_work_a) : +rai::work_pool::work_pool (std::unique_ptr opencl_a) : current (0), ticket (0), -done (false) +done (false), +opencl (std::move (opencl_a)) { static_assert (ATOMIC_INT_LOCK_FREE == 2, "Atomic int needed"); auto count (std::max (1u, std::thread::hardware_concurrency ())); @@ -28,16 +29,6 @@ done (false) })); threads.push_back (std::move (thread)); } - if (opencl_work_a) - { - auto error (false); - rai::opencl_environment environment (error); - opencl.reset (new rai::opencl_work (error, environment, *this)); - if (error) - { - opencl.reset(); - } - } } rai::work_pool::~work_pool () @@ -170,7 +161,7 @@ boost::optional rai::work_pool::generate_maybe (rai::uint256_union co boost::optional result; if (opencl != nullptr) { - result = opencl->generate_work (root_a); + result = opencl->generate_work (*this, root_a); } else { diff --git a/rai/node/wallet.hpp b/rai/node/wallet.hpp index bae874a9..265bc6e3 100644 --- a/rai/node/wallet.hpp +++ b/rai/node/wallet.hpp @@ -16,7 +16,7 @@ namespace rai class work_pool { public: - work_pool (bool); + work_pool (std::unique_ptr ); ~work_pool (); void loop (uint64_t); void stop (); diff --git a/rai/rai_landing/entry.cpp b/rai/rai_landing/entry.cpp index 9cfbed00..c8ffd26c 100644 --- a/rai/rai_landing/entry.cpp +++ b/rai/rai_landing/entry.cpp @@ -101,7 +101,7 @@ int main (int argc, char * const * argv) { rai::node_init init; auto service (boost::make_shared ()); - rai::work_pool work (config.node.opencl_work); + rai::work_pool work (rai::opencl_work::create (config.node.opencl_work, 0, 1)); rai::alarm alarm (*service); auto node (std::make_shared (init, *service, working, alarm, config.node, work)); if (!init.error ()) diff --git a/rai/rai_node/daemon.cpp b/rai/rai_node/daemon.cpp index 15c60ce0..9f30f255 100644 --- a/rai/rai_node/daemon.cpp +++ b/rai/rai_node/daemon.cpp @@ -62,7 +62,7 @@ void rai_daemon::daemon::run () if (!error) { auto service (boost::make_shared ()); - rai::work_pool work (config.node.opencl_work); + rai::work_pool work (std::move (rai::opencl_work::create (config.node.opencl_work, 0, 1))); rai::alarm alarm (*service); rai::node_init init; auto node (std::make_shared (init, *service, working, alarm, config.node, work)); diff --git a/rai/rai_node/entry.cpp b/rai/rai_node/entry.cpp index d517c67f..96124a3e 100644 --- a/rai/rai_node/entry.cpp +++ b/rai/rai_node/entry.cpp @@ -148,7 +148,7 @@ int main (int argc, char * const * argv) if (!key.decode_hex (vm ["key"].as ())) { rai::keypair genesis (key.to_string ()); - rai::work_pool work (false); + rai::work_pool work (nullptr); std::cout << "Genesis: " << genesis.prv.data.to_string () << std::endl << "Public: " << genesis.pub.to_string () << std::endl << "Account: " << genesis.pub.to_account () << std::endl; rai::keypair landing; std::cout << "Landing: " << landing.prv.data.to_string () << std::endl << "Public: " << landing.pub.to_string () << std::endl << "Account: " << landing.pub.to_account () << std::endl; @@ -215,7 +215,7 @@ int main (int argc, char * const * argv) } else if (vm.count ("debug_profile_generate")) { - rai::work_pool work (false); + rai::work_pool work (nullptr); rai::change_block block (0, 0, rai::keypair ().prv, 0, 0); std::cerr << "Starting generation profiling\n"; for (uint64_t i (0); true; ++i) @@ -229,7 +229,7 @@ int main (int argc, char * const * argv) } else if (vm.count ("debug_profile_verify")) { - rai::work_pool work (false); + rai::work_pool work (nullptr); rai::change_block block (0, 0, rai::keypair ().prv, 0, 0); std::cerr << "Starting verification profiling\n"; for (uint64_t i (0); true; ++i) diff --git a/rai/rai_wallet/entry.cpp b/rai/rai_wallet/entry.cpp index 821162c1..811ee354 100644 --- a/rai/rai_wallet/entry.cpp +++ b/rai/rai_wallet/entry.cpp @@ -149,7 +149,7 @@ int run_wallet (int argc, char * const * argv) QApplication application (argc, const_cast (argv)); rai::set_application_icon (application); auto service (boost::make_shared ()); - rai::work_pool work (config.node.opencl_work); + rai::work_pool work (rai::opencl_work::create (config.node.opencl_work, 0, 1)); rai::alarm alarm (*service); rai::node_init init; auto node (std::make_shared (init, *service, working, alarm, config.node, work));