main.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /*
  2. * This file is part of ygg-brute
  3. * Copyright (c) 2020 ygg-brute authors
  4. * See LICENSE for licensing information
  5. */
  6. #include <chrono>
  7. #include <ctime>
  8. #include <thread>
  9. #include <condition_variable>
  10. #include <memory>
  11. #include <iostream>
  12. #include <random>
  13. #include <string_view>
  14. #include <cstdio>
  15. #include "third_party/CLI11/CLI11.hpp"
  16. #include "io.hpp"
  17. #include "processor.hpp"
  18. #include "outputter.hpp"
  19. #ifdef CUDA_ENGINE
  20. # include "cuda/engine.hpp"
  21. #endif
  22. #ifdef OPENCL_ENGINE
  23. # include "opencl/engine.hpp"
  24. #endif
  25. struct Options {
  26. size_t generators{0};
  27. size_t workers{0};
  28. uint64_t time{0};
  29. AddressFilter filter;
  30. GeneratorParams generator_params;
  31. Engine* engine{nullptr};
  32. };
  33. class Manager {
  34. public:
  35. Manager(const Options& options)
  36. {
  37. for(auto i = 0; i < options.generators + options.workers; ++i)
  38. free_contexts_.emplace_back(options.engine->make_generator_context());
  39. for(auto i = 0; i < options.generators; ++i) {
  40. auto generator_params = options.generator_params;
  41. generator_params.seed = std::random_device()();
  42. generator_params.seq = std::random_device()();
  43. producers_.emplace_back(
  44. &Manager::produce,
  45. this,
  46. options.engine->make_generator(generator_params)
  47. );
  48. }
  49. for(auto i = 0; i < options.workers; ++i)
  50. processors_.emplace_back(&Manager::process, this, std::make_shared<Processor>(options.filter));
  51. }
  52. ~Manager() { stop(); }
  53. void stop() {
  54. if(stop_) return;
  55. {
  56. std::lock_guard<std::mutex> lock{ctx_mutex_};
  57. stop_ = true;
  58. }
  59. outputter_.stop();
  60. produce_cv_.notify_all();
  61. process_cv_.notify_all();
  62. for(auto& p : producers_)
  63. p.join();
  64. for(auto& c : processors_)
  65. c.join();
  66. producers_.clear();
  67. processors_.clear();
  68. }
  69. private:
  70. void produce(std::shared_ptr<Generator> gen)
  71. {
  72. auto is_ready = [this] { return stop_ || !free_contexts_.empty(); };
  73. std::unique_lock<std::mutex> lock{ctx_mutex_};
  74. for(;;) {
  75. if(!is_ready())
  76. produce_cv_.wait(lock, is_ready);
  77. if(stop_) return;
  78. auto ctx = std::move(free_contexts_.front());
  79. free_contexts_.pop_front();
  80. lock.unlock();
  81. gen->produce(*ctx);
  82. lock.lock();
  83. ready_contexts_.emplace_back(std::move(ctx));
  84. lock.unlock();
  85. process_cv_.notify_one();
  86. lock.lock();
  87. }
  88. }
  89. void process(std::shared_ptr<Processor> processor)
  90. {
  91. auto is_ready = [this] { return stop_ || !ready_contexts_.empty(); };
  92. std::unique_lock<std::mutex> lock{ctx_mutex_};
  93. for(;;) {
  94. if(!is_ready())
  95. process_cv_.wait(lock, is_ready);
  96. if(stop_) return;
  97. auto ctx = std::move(ready_contexts_.front());
  98. ready_contexts_.pop_front();
  99. lock.unlock();
  100. auto res = processor->process(*ctx);
  101. lock.lock();
  102. free_contexts_.emplace_back(std::move(ctx));
  103. lock.unlock();
  104. produce_cv_.notify_one();
  105. outputter_.output(std::move(res.results), res.stats);
  106. lock.lock();
  107. }
  108. }
  109. private:
  110. std::list<std::unique_ptr<GeneratorCtx>> free_contexts_;
  111. std::list<std::unique_ptr<GeneratorCtx>> ready_contexts_;
  112. std::mutex ctx_mutex_;
  113. std::condition_variable produce_cv_;
  114. std::condition_variable process_cv_;
  115. Outputter outputter_;
  116. std::list<std::thread> producers_;
  117. std::list<std::thread> processors_;
  118. bool stop_{false};
  119. };
  120. static void run(Options options)
  121. {
  122. using clock_t = std::chrono::steady_clock;
  123. if(!options.workers)
  124. options.workers = std::min(std::thread::hardware_concurrency(), 2u);
  125. if(!options.generators)
  126. options.generators = 2;
  127. options.engine->fill_params(options.generator_params);
  128. std::cerr << "=================================================================" << std::endl;
  129. std::cerr << "Starting with " << options.engine->name() << ", ";
  130. std::cerr << options.workers << " worker(s), " << options.generators << " generator(s)" << std::endl;
  131. auto& gparams = options.generator_params;
  132. std::cerr << "on device " << options.engine->device_name(gparams.device) << std::endl;
  133. std::cerr << "block size " << gparams.block_size << ", number of blocks " << gparams.n_blocks << " ";
  134. std::cerr << "(batch size " << (gparams.block_size * gparams.n_blocks) << ")" << std::endl;
  135. std::cerr << "invert batch size " << gparams.inv_batch_size << std::endl;
  136. std::cerr << "=================================================================" << std::endl;
  137. uint64_t sleep_seconds = 60;
  138. if(options.time) sleep_seconds = std::min(options.time, sleep_seconds);
  139. const auto start_ts = clock_t::now();
  140. Manager mgr(options);
  141. for(;;) {
  142. std::this_thread::sleep_for(std::chrono::seconds(sleep_seconds));
  143. if(options.time) {
  144. auto now = clock_t::now();
  145. auto elapsed_seconds = std::chrono::duration_cast<std::chrono::seconds>(now - start_ts).count();
  146. if(elapsed_seconds > options.time) return;
  147. sleep_seconds = std::min(sleep_seconds, options.time - elapsed_seconds);
  148. }
  149. }
  150. }
  151. int main(int argc, char **argv)
  152. {
  153. std::vector<Engine*> g_engines;
  154. # ifdef CUDA_ENGINE
  155. g_engines.push_back(&cuda::get_engine());
  156. # endif
  157. # ifdef OPENCL_ENGINE
  158. g_engines.push_back(&opencl::get_engine());
  159. # endif
  160. bool info{false};
  161. std::string engine;
  162. std::string engines;
  163. if(g_engines.empty()) {
  164. engines = "none";
  165. engine = "none";
  166. } else {
  167. engine = g_engines.front()->name();
  168. for(auto& e : g_engines) {
  169. if(!engines.empty()) engines += ", ";
  170. engines += e->name();
  171. }
  172. }
  173. CLI::App app{"Yggdrasil address bruteforcer"};
  174. Options options;
  175. app.add_option("--min-hi", options.filter.min_hi,
  176. "Required minimal address difficulty (2nd bit's value), "
  177. "lower addresses will be discarded")
  178. ->check(CLI::Range(1, 255));
  179. app.add_option("--hi", options.filter.hi,
  180. "Desired minimal address difficulty, match is greater or equal")
  181. ->check(CLI::Range(1, 255));
  182. app.add_option("--re", options.filter.re,
  183. "Regex to match address string (can be specified multiple times)");
  184. app.add_option("-t,--time", options.time, "Number of seconds to run");
  185. app.add_option("--workers", options.workers, "Number of threads matching addresses");
  186. app.add_option("--generators", options.generators, "Number of threads generating addresses");
  187. app.add_option("--engine", engine, "Heterogenous computation runtime (" + engines + ")");
  188. app.add_option("--device", options.generator_params.device,
  189. "Device index");
  190. app.add_option("--block-size", options.generator_params.block_size,
  191. "Bruteforcer block size");
  192. app.add_option("--blocks", options.generator_params.n_blocks,
  193. "Number of blocks in batch");
  194. app.add_option("--inv-batch-size", options.generator_params.inv_batch_size,
  195. "Inversion batch size (advanced)");
  196. app.add_flag("--info", info, "Display system information");
  197. CLI11_PARSE(app, argc, argv);
  198. try {
  199. if(info) {
  200. std::cout << "Supported engines: " << engines << std::endl;
  201. for(auto& e : g_engines) {
  202. e->print_info();
  203. }
  204. return 0;
  205. }
  206. for(auto& e : g_engines) {
  207. if(engine == e->name()) {
  208. options.engine = e;
  209. break;
  210. }
  211. }
  212. if(!options.engine)
  213. throw std::runtime_error{"Unsupported engine: '" + engine + "'"};
  214. run(std::move(options));
  215. } catch(const std::exception& ex) {
  216. std::cerr << "Error: " << ex.what() << std::endl;
  217. return 1;
  218. }
  219. return 0;
  220. }