Fabcoin Core  0.16.2
P2P Digital Currency
libgpusolver.cpp
Go to the documentation of this file.
1 /* MIT License
2  *
3  * Copyright (c) 2016 Omar Alvarez <omar.alvarez@udc.es>
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #include <chrono>
25 
26 #include "libgpusolver.h"
27 #include "util.h"
28 #include "primitives/block.h"
29 #include "arith_uint256.h"
30 
31 //#define DEBUG
32 
33 char *s_hexdump(const void *_a, uint32_t a_len)
34 {
35  const uint8_t *a = (const uint8_t *) _a;
36  static char buf[1024];
37  uint32_t i;
38  for (i = 0; i < a_len && i + 2 < sizeof (buf); i++)
39  sprintf(buf + i * 2, "%02x", a[i]);
40  buf[i * 2] = 0;
41  return buf;
42 }
43 
44 GPUSolver::GPUSolver(unsigned int n, unsigned k)
45 {
46  size_t global_work_size = 1 << 20;
47  size_t local_work_size = 32;
48 
49  miner = new cl_gpuminer(n,k);
50 
51  indices = (sols_t *) malloc(sizeof(sols_t));
52  if(indices == NULL)
53  std::cout << "Error allocating indices array!" << std::endl;
54 
55  GPU = miner->configureGPU(0, local_work_size, global_work_size);
56  if(!GPU)
57  std::cout << "ERROR: No suitable GPU found! No work will be performed!" << std::endl;
58 
59  /*Initialize the kernel, compile it and create buffers
60  Currently runs for the gpu-list-gen.c kernel DATA_SIZE=100 times
61  */
62 
63  if( n == 200 && k == 9 )
64  {
65  std::vector<std::string> kernels {"kernel_init_ht", "kernel_round0", "kernel_round1", "kernel_round2","kernel_round3", "kernel_round4", "kernel_round5", "kernel_round6", "kernel_round7", "kernel_round8", "kernel_sols"};
66  if(GPU)
67  initOK = miner->init(0, 0, kernels);
68  }
69  else if( n == 184 && k == 7 )
70  {
71  std::vector<std::string> kernels {"kernel_init_ht", "kernel_round0", "kernel_round1", "kernel_round2","kernel_round3", "kernel_round4", "kernel_round5", "kernel_round6", "kernel_sols"};
72  if(GPU)
73  initOK = miner->init(0, 0, kernels);
74  }
75 
76 }
77 
78 GPUSolver::GPUSolver(unsigned platform, unsigned device, unsigned int n, unsigned int k) {
79 
80  /* Notes
81  I've added some extra parameters in this interface to assist with dev, such as
82  a kernel string to specify which kernel to run and local/global work sizes.
83  */
84  //TODO This looks like IND_PER_BUCKET, enough for GPU?
85  size_t global_work_size = 1 << 20;
86  size_t local_work_size = 32;
87 
88  miner = new cl_gpuminer(n,k);
89 
90  indices = (sols_t *) malloc(sizeof(sols_t));
91  if(indices == NULL)
92  std::cout << "Error allocating indices array!" << std::endl;
93 
94  /* Checks each device for memory requirements and sets local/global sizes
95  TODO: Implement device logic for equihash kernel
96  @params: unsigned platformId
97  @params: unsigned localWorkSizes
98  @params: unsigned globalWorkSizes
99  */
100  GPU = miner->configureGPU(platform, local_work_size, global_work_size);
101  if(!GPU)
102  std::cout << "ERROR: No suitable GPU found! No work will be performed!" << std::endl;
103 
104  /*Initialize the kernel, compile it and create buffers
105  Currently runs for the gpu-list-gen.c kernel DATA_SIZE=100 times
106  TODO: pass base state and nonce's to kernel.
107  @params: unsigned _platformId
108  @params: unsigned _deviceId
109  @params: string& _kernel - The name of the kernel for dev purposes
110  */
111  if( n == 200 && k == 9 )
112  {
113  std::vector<std::string> kernels {"kernel_init_ht", "kernel_round0", "kernel_round1", "kernel_round2","kernel_round3", "kernel_round4", "kernel_round5", "kernel_round6", "kernel_round7", "kernel_round8", "kernel_sols"};
114  if(GPU)
115  initOK = miner->init(platform, device, kernels);
116  }
117  else if( n == 184 && k == 7 )
118  {
119  std::vector<std::string> kernels {"kernel_init_ht", "kernel_round0", "kernel_round1", "kernel_round2","kernel_round3", "kernel_round4", "kernel_round5", "kernel_round6", "kernel_sols"};
120  if(GPU)
121  initOK = miner->init(platform, device, kernels);
122  }
123 
124 }
125 
127 
128  if(GPU)
129  miner->finish();
130 
131  delete miner;
132 
133  if(indices != NULL)
134  free(indices);
135 
136 }
137 
138 bool GPUSolver::run(unsigned int n, unsigned int k, uint8_t *header, size_t header_len, uint256 nonce,
139  const std::function<bool(std::vector<unsigned char>)> validBlock,
140  const std::function<bool(GPUSolverCancelCheck)> cancelled,
141  crypto_generichash_blake2b_state base_state)
142 {
143  return GPUSolve(n, k, header, header_len, nonce, validBlock, cancelled, base_state);
144 }
145 
146 bool GPUSolver::GPUSolve(unsigned int n, unsigned int k, uint8_t *header, size_t header_len, uint256 &nonce,
147  const std::function<bool(std::vector<unsigned char>)> validBlock,
148  const std::function<bool(GPUSolverCancelCheck)> cancelled,
149  crypto_generichash_blake2b_state base_state)
150 {
151  /* Run the kernel
152  TODO: Optimise and figure out how we want this to go
153  @params eh_HashState& base_state - Sends to kernel in a buffer. Will update for specific kernels
154  */
155 
156  if(GPU && initOK)
157  {
158  // auto t = std::chrono::high_resolution_clock::now();
159  uint256 nNonce;
160  miner->run(header, header_len, nonce, indices, &n_sol, &nNonce);
161 
162 // uint256 nNonce = ArithToUint256(ptr);
163  //crypto_generichash_blake2b_update(&base_state, nNonce.begin(), nNonce.size());
164 /*
165  auto d = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - t);
166  auto milis = std::chrono::duration_cast<std::chrono::milliseconds>(d).count();
167 
168  if(!counter) {
169  sum = 1000.f*n_sol/milis;
170  } else {
171  sum += 1000.f*n_sol/milis;
172  }
173 
174  avg = sum/++counter;
175 
176  if(!(counter % 10))
177  std::cout << "Kernel run took " << milis << " ms. (" << avg << " H/s)" << std::endl;
178 */
179 
180  size_t checkedSols = n_sol;
181  size_t s = 0;
182  while (checkedSols)
183  {
184  ++s;
185  if(indices->valid[s-1])
186  --checkedSols;
187  else
188  continue;
189 
190  std::vector<eh_index> index_vector(512);
191 
192  index_vector.resize(1<<k);
193  for (size_t i = 0; i < (unsigned int)1 << k; i++)
194  {
195  index_vector[i] = indices->values[s-1][i];
196  }
197 
198  std::vector<unsigned char> sol_char = GetMinimalFromIndices(index_vector, miner->PREFIX());
199  //LogPrint(BCLog::POW, "Checking with = %s, %d sols\n",nNonce.ToString(), n_sol);
200 #ifdef DEBUG
201  bool isValid;
202  EhIsValidSolution(n, k, base_state, sol_char, isValid);
203  LogPrint(BCLog::POW,"is valid: \n");
204  if (!isValid)
205  {
206  //If we find invalid solution bail, it cannot be a valid POW
207  LogPrint(BCLog::POW,"Invalid solution found!\n");
208  return false;
209  }
210  else
211  {
212  LogPrint(BCLog::POW,"Valid solution found!\n");
213  }
214 #endif
215  if (validBlock(sol_char))
216  {
217  // If we find a POW solution, do not try other solutions
218  // because they become invalid as we created a new block in blockchain.
219  LogPrint(BCLog::POW,"Valid block found!\n");
220  return true;
221  }
222  }
223  //free(indices);
224  }
225 
226  return false;
227 
228 }
#define function(a, b, c, d, k, s)
std::vector< unsigned char > GetMinimalFromIndices(std::vector< eh_index > indices, size_t cBitLen)
Definition: equihash.cpp:195
void run(uint8_t *header, size_t header_len, uint256 nonce, sols_t *indices, uint32_t *n_sol, uint256 *ptr)
bool run(unsigned int n, unsigned int k, uint8_t *header, size_t header_len, uint256 nonce, const std::function< bool(std::vector< unsigned char >)> validBlock, const std::function< bool(GPUSolverCancelCheck)> cancelled, crypto_generichash_blake2b_state base_state)
sols_t * indices
Definition: libgpusolver.h:80
bool GPUSolve(unsigned int n, unsigned int k, uint8_t *header, size_t header_len, uint256 &nonce, const std::function< bool(std::vector< unsigned char >)> validBlock, const std::function< bool(GPUSolverCancelCheck)> cancelled, crypto_generichash_blake2b_state base_state)
uint32_t n_sol
Definition: libgpusolver.h:81
uint8_t valid[MAX_SOLS]
Definition: libclwrapper.h:17
#define a(i)
bool init(unsigned _platformId, unsigned _deviceId, std::vector< std::string > _kernels)
GPUSolverCancelCheck
Definition: libgpusolver.h:57
#define EhIsValidSolution(n, k, base_state, soln, ret)
Definition: equihash.h:271
#define LogPrint(category,...)
Definition: util.h:164
cl_gpuminer * miner
Definition: libgpusolver.h:75
256-bit opaque blob.
Definition: uint256.h:132
uint values[MAX_SOLS][512]
Definition: libclwrapper.h:18
char * s_hexdump(const void *_a, uint32_t a_len)
unsigned int PREFIX()
Definition: libclwrapper.h:253
bool initOK
Definition: libgpusolver.h:77
static bool configureGPU(unsigned _platformId, unsigned _localWorkSize, unsigned _globalWorkSize)