override unsafe protected void MinerThread() { Random r = new Random(); UInt32[] ethashOutput = new UInt32[256]; byte[] ethashHeaderhash = new byte[32]; MarkAsAlive(); MainForm.Logger("Miner thread for Device #" + DeviceIndex + " started."); BuildEthashProgram(); fixed(UInt32 *ethashOutputPtr = ethashOutput) fixed(byte *ethashHeaderhashPtr = ethashHeaderhash) fixed(byte *pascalMidstatePtr = mPascalMidstate) fixed(byte *pascalInputPtr = mPascalInput) fixed(UInt32 * pascalOutputPtr = mPascalOutput) while (!Stopped) { MarkAsAlive(); try { int ethashEpoch = -1; long ethashDAGSize = 0; ComputeBuffer <byte> ethashDAGBuffer = null; mEthashSearchKernel.SetMemoryArgument(7 + 0, mPascalInputBuffer); mEthashSearchKernel.SetMemoryArgument(7 + 1, mPascalOutputBuffer); mEthashSearchKernel.SetMemoryArgument(7 + 4, mPascalMidstateBuffer); mEthashSearchKernel.SetValueArgument <UInt32>(7 + 5, mPascalRatio); // Wait for the first job to arrive. int elapsedTime = 0; while ((mEthashStratum == null || mEthashStratum.GetJob() == null || mPascalStratum == null || mPascalStratum.GetJob() == null) && elapsedTime < 60000) { Thread.Sleep(100); elapsedTime += 100; } if (mEthashStratum == null || mEthashStratum.GetJob() == null || mPascalStratum == null || mPascalStratum.GetJob() == null) { MainForm.Logger("Ethash stratum server failed to send a new job."); //throw new TimeoutException("Stratum server failed to send a new job."); return; } System.Diagnostics.Stopwatch consoleUpdateStopwatch = new System.Diagnostics.Stopwatch(); EthashStratum.Work ethashWork; PascalStratum.Work pascalWork; while (!Stopped && (ethashWork = mEthashStratum.GetWork()) != null && (pascalWork = mPascalStratum.GetWork()) != null) { MarkAsAlive(); String ethashPoolExtranonce = mEthashStratum.PoolExtranonce; byte[] ethashExtranonceByteArray = Utilities.StringToByteArray(ethashPoolExtranonce); byte ethashLocalExtranonce = (byte)ethashWork.LocalExtranonce; UInt64 ethashStartNonce = (UInt64)ethashLocalExtranonce << (8 * (7 - ethashExtranonceByteArray.Length)); for (int i = 0; i < ethashExtranonceByteArray.Length; ++i) { ethashStartNonce |= (UInt64)ethashExtranonceByteArray[i] << (8 * (7 - i)); } ethashStartNonce += (ulong)r.Next(0, int.MaxValue) & (0xfffffffffffffffful >> (ethashExtranonceByteArray.Length * 8 + 8)); String ethashJobID = ethashWork.GetJob().ID; String ethashSeedhash = ethashWork.GetJob().Seedhash; double ethashDifficulty = mEthashStratum.Difficulty; Buffer.BlockCopy(Utilities.StringToByteArray(ethashWork.GetJob().Headerhash), 0, ethashHeaderhash, 0, 32); Queue.Write <byte>(mEthashHeaderBuffer, true, 0, 32, (IntPtr)ethashHeaderhashPtr, null); var pascalJob = pascalWork.Job; Array.Copy(pascalWork.Blob, mPascalInput, sPascalInputSize); CalculatePascalMidState(); Queue.Write <byte>(mPascalMidstateBuffer, true, 0, sPascalMidstateSize, (IntPtr)pascalMidstatePtr, null); UInt32 pascalStartNonce = (UInt32)(r.Next(0, int.MaxValue)); UInt64 PascalTarget = (UInt64)((double)0xffff0000UL / mPascalStratum.Difficulty); mEthashSearchKernel.SetValueArgument <UInt64>(7 + 3, PascalTarget); Queue.Write <byte>(mPascalInputBuffer, true, 0, sPascalInputSize, (IntPtr)pascalInputPtr, null); if (ethashEpoch != ethashWork.GetJob().Epoch) { if (ethashDAGBuffer != null) { ethashDAGBuffer.Dispose(); ethashDAGBuffer = null; } ethashEpoch = ethashWork.GetJob().Epoch; DAGCache cache = new DAGCache(ethashEpoch, ethashWork.GetJob().Seedhash); ethashDAGSize = Utilities.GetDAGSize(ethashEpoch); System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); mEthashGlobalWorkSizeArray[0] = ethashDAGSize / 64; mEthashGlobalWorkSizeArray[0] /= 8; if (mEthashGlobalWorkSizeArray[0] % mEthashLocalWorkSizeArray[0] > 0) { mEthashGlobalWorkSizeArray[0] += mEthashLocalWorkSizeArray[0] - mEthashGlobalWorkSizeArray[0] % mEthashLocalWorkSizeArray[0]; } ComputeBuffer <byte> DAGCacheBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadOnly, cache.GetData().Length); fixed(byte *p = cache.GetData()) Queue.Write <byte>(DAGCacheBuffer, true, 0, cache.GetData().Length, (IntPtr)p, null); ethashDAGBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadWrite, mEthashGlobalWorkSizeArray[0] * 8 * 64 /* ethashDAGSize */); // With this, we can remove a conditional statement in the DAG kernel. mEthashDAGKernel.SetValueArgument <UInt32>(0, 0); mEthashDAGKernel.SetMemoryArgument(1, DAGCacheBuffer); mEthashDAGKernel.SetMemoryArgument(2, ethashDAGBuffer); mEthashDAGKernel.SetValueArgument <UInt32>(3, (UInt32)cache.GetData().Length / 64); mEthashDAGKernel.SetValueArgument <UInt32>(4, 0xffffffffu); for (long start = 0; start < ethashDAGSize / 64; start += mEthashGlobalWorkSizeArray[0]) { mEthashGlobalWorkOffsetArray[0] = start; Queue.Execute(mEthashDAGKernel, mEthashGlobalWorkOffsetArray, mEthashGlobalWorkSizeArray, mEthashLocalWorkSizeArray, null); Queue.Finish(); if (Stopped || !mEthashStratum.GetJob().ID.Equals(ethashJobID)) { break; } } DAGCacheBuffer.Dispose(); if (Stopped || !mEthashStratum.GetJob().ID.Equals(ethashJobID)) { break; } sw.Stop(); MainForm.Logger("Generated DAG for Epoch #" + ethashEpoch + " (" + (long)sw.Elapsed.TotalMilliseconds + "ms)."); } consoleUpdateStopwatch.Start(); while (!Stopped && mEthashStratum.GetJob().ID.Equals(ethashJobID) && mEthashStratum.PoolExtranonce.Equals(ethashPoolExtranonce) && mPascalStratum.GetJob().Equals(pascalJob)) { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); MarkAsAlive(); // Get a new local extranonce if necessary. if ((ethashStartNonce & (0xfffffffffffffffful >> (ethashExtranonceByteArray.Length * 8 + 8)) + (ulong)mEthashGlobalWorkSizeArray[0] * 3 / 4) >= ((ulong)0x1 << (64 - (ethashExtranonceByteArray.Length * 8 + 8)))) { break; } if (0xffffffffu - pascalStartNonce < (UInt32)mEthashGlobalWorkSizeArray[0] * mPascalRatio) { break; } UInt64 target = (UInt64)((double)0xffff0000U / ethashDifficulty); mEthashSearchKernel.SetMemoryArgument(0, mEthashOutputBuffer); // g_output mEthashSearchKernel.SetMemoryArgument(1, mEthashHeaderBuffer); // g_header mEthashSearchKernel.SetMemoryArgument(2, ethashDAGBuffer); // _g_dag mEthashSearchKernel.SetValueArgument <UInt32>(3, (UInt32)(ethashDAGSize / 128)); // DAG_SIZE mEthashSearchKernel.SetValueArgument <UInt64>(4, ethashStartNonce); // start_nonce mEthashSearchKernel.SetValueArgument <UInt64>(5, target); // target mEthashSearchKernel.SetValueArgument <UInt32>(6, 0xffffffffu); // isolate mEthashSearchKernel.SetValueArgument <UInt32>(7 + 2, pascalStartNonce); ethashOutput[255] = 0; // ethashOutput[255] is used as an atomic counter. Queue.Write <UInt32>(mEthashOutputBuffer, true, 0, 256, (IntPtr)ethashOutputPtr, null); mEthashGlobalWorkOffsetArray[0] = 0; mPascalOutput[255] = 0; // mPascalOutput[255] is used as an atomic counter. Queue.Write <UInt32>(mPascalOutputBuffer, true, 0, sPascalOutputSize, (IntPtr)pascalOutputPtr, null); Queue.Execute(mEthashSearchKernel, mEthashGlobalWorkOffsetArray, mEthashGlobalWorkSizeArray, mEthashLocalWorkSizeArray, null); Queue.Read <UInt32>(mEthashOutputBuffer, true, 0, 256, (IntPtr)ethashOutputPtr, null); if (mEthashStratum.GetJob().ID.Equals(ethashJobID)) { for (int i = 0; i < ethashOutput[255]; ++i) { mEthashStratum.Submit(GatelessGateDevice, ethashWork.GetJob(), ethashStartNonce + (UInt64)ethashOutput[i]); } } ethashStartNonce += (UInt64)mEthashGlobalWorkSizeArray[0] * 3 / 4; Queue.Read <UInt32>(mPascalOutputBuffer, true, 0, sPascalOutputSize, (IntPtr)pascalOutputPtr, null); if (mPascalStratum.GetJob().Equals(pascalJob)) { for (int i = 0; i < mPascalOutput[255]; ++i) { mPascalStratum.Submit(GatelessGateDevice, pascalWork, mPascalOutput[i]); } } pascalStartNonce += (UInt32)mEthashGlobalWorkSizeArray[0] * mPascalRatio; sw.Stop(); Speed = ((double)mEthashGlobalWorkSizeArray[0]) / sw.Elapsed.TotalSeconds * 0.75; SecondSpeed = ((double)mEthashGlobalWorkSizeArray[0]) / sw.Elapsed.TotalSeconds * mPascalRatio; if (consoleUpdateStopwatch.ElapsedMilliseconds >= 10 * 1000) { MainForm.Logger("Device #" + DeviceIndex + ": " + String.Format("{0:N2} Mh/s (Ethash), ", Speed / (1000000)) + String.Format("{0:N2} Mh/s (Pascal)", SecondSpeed / (1000000))); consoleUpdateStopwatch.Restart(); } } } if (ethashDAGBuffer != null) { ethashDAGBuffer.Dispose(); ethashDAGBuffer = null; } } catch (Exception ex) { MainForm.Logger("Exception in miner thread: " + ex.Message + ex.StackTrace); Speed = 0; if (UnrecoverableException.IsUnrecoverableException(ex)) { this.UnrecoverableException = new UnrecoverableException(ex, GatelessGateDevice); Stop(); } else { MainForm.Logger("Restarting miner thread..."); System.Threading.Thread.Sleep(5000); } } } MarkAsDone(); }
public String GetMixHash(UInt64 nonce) { IHash hash = HashFactory.Crypto.SHA3.CreateKeccak512(); byte[] data; System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); // def hashimoto(header, nonce, full_size, dataset_lookup): int epoch = Epoch; byte[] seedhashArray = Utilities.StringToByteArray(Seedhash); byte[] headerhashArray = Utilities.StringToByteArray(Headerhash); DAGCache cache = new DAGCache(epoch, Seedhash); data = cache.GetData(); long fullSize = Utilities.GetDAGSize(epoch); // n = full_size / HASH_BYTES int n = (int)(fullSize / HASH_BYTES); // w = MIX_BYTES // WORD_BYTES int w = MIX_BYTES / WORD_BYTES; // mixhashes = MIX_BYTES / HASH_BYTES int mixhashes = MIX_BYTES / HASH_BYTES; // # combine header+nonce into a 64 byte seed // s = sha3_512(header + nonce[::-1]) byte[] combined = new byte[headerhashArray.Length + sizeof(UInt64)]; Buffer.BlockCopy(headerhashArray, 0, combined, 0, headerhashArray.Length); for (int i = 0; i < 8; ++i) { combined[headerhashArray.Length + i] = (byte)((nonce >> (i * 8)) & 0xff); } byte[] s = hash.ComputeBytes(combined).GetBytes(); // # start the mix with replicated s // mix = [] // for _ in range(MIX_BYTES / HASH_BYTES): // mix.extend(s) byte[] mix = new byte[s.Length * mixhashes]; for (int i = 0; i < mixhashes; ++i) { Buffer.BlockCopy(s, 0, mix, i * s.Length, s.Length); } // # mix in random dataset nodes // for i in range(ACCESSES): for (int i = 0; i < ACCESSES; ++i) { // p = fnv(i ^ s[0], mix[i % w]) % (n // mixhashes) * mixhashes UInt32 v1 = ((UInt32)s[0] ^ (UInt32)i) | ((UInt32)s[1] << 8) | ((UInt32)s[2] << 16) | ((UInt32)s[3] << 24); int mixIndex = (i % w) * 4; UInt32 v2 = ((UInt32)mix[mixIndex + 0] << 0) | ((UInt32)mix[mixIndex + 1] << 8) | ((UInt32)mix[mixIndex + 2] << 16) | ((UInt32)mix[mixIndex + 3] << 24); int p = (int)(FNV(v1, v2) % (n / mixhashes) * mixhashes); // newdata = [] // for j in range(MIX_BYTES / HASH_BYTES): // newdata.extend(dataset_lookup(p + j)) byte[] newData = new byte[s.Length * mixhashes]; for (int j = 0; j < mixhashes; ++j) { Buffer.BlockCopy(CalculateDatasetItem(data, p + j), 0, newData, j * (int)s.Length, (int)s.Length); } // mix = map(fnv, mix, newdata) for (int j = 0; j < s.Length * mixhashes; j += 4) { v1 = ((UInt32)mix[j + 0] << 0) | ((UInt32)mix[j + 1] << 8) | ((UInt32)mix[j + 2] << 16) | ((UInt32)mix[j + 3] << 24); v2 = ((UInt32)newData[j + 0] << 0) | ((UInt32)newData[j + 1] << 8) | ((UInt32)newData[j + 2] << 16) | ((UInt32)newData[j + 3] << 24); UInt32 result = FNV(v1, v2); for (int k = 0; k < 4; ++k) { mix[j + k] = (byte)((result >> (k * 8)) & 0xff); } } } // # compress mix // cmix = [] // for i in range(0, len(mix), 4): // cmix.append(fnv(fnv(fnv(mix[i], mix[i+1]), mix[i+2]), mix[i+3])) byte[] cmix = new byte[mix.Length / 4]; for (int i = 0; i < mix.Length / 4; i += 4) { UInt32 v1 = ((UInt32)mix[i * 4 + 0] << 0) | ((UInt32)mix[i * 4 + 1] << 8) | ((UInt32)mix[i * 4 + 2] << 16) | ((UInt32)mix[i * 4 + 3] << 24); for (int j = 1; j < 4; ++j) { UInt32 v2 = ((UInt32)mix[(i + j) * 4 + 0] << 0) | ((UInt32)mix[(i + j) * 4 + 1] << 8) | ((UInt32)mix[(i + j) * 4 + 2] << 16) | ((UInt32)mix[(i + j) * 4 + 3] << 24); v1 = FNV(v1, v2); } for (int j = 0; j < 4; ++j) { cmix[i + j] = (byte)((v1 >> (j * 8)) & 0xff); } } // return { // "mix digest": serialize_hash(cmix), // "result": serialize_hash(sha3_256(s+cmix)) // } sw.Stop(); MainForm.Logger("Generated mix hash (" + (long)sw.Elapsed.TotalMilliseconds + "ms)."); return(Utilities.ByteArrayToString(cmix)); }
override unsafe protected void MinerThread() { Random r = new Random(); MarkAsAlive(); MainForm.Logger("Dual Ethash/Lbry miner thread for Device #" + DeviceIndex + " started."); BuildEthashProgram(); fixed(UInt32 *ethashOutputPtr = mEthashOutput) fixed(byte *ethashHeaderhashPtr = mEthashHeaderhash) fixed(byte *lbryInputPtr = mLbryInput) fixed(UInt32 * lbryOutputPtr = mLbryOutput) while (!Stopped) { MarkAsAlive(); try { int ethashEpoch = -1; long ethashDAGSize = 0; ComputeBuffer <byte> ethashDAGBuffer = null; // Wait for the first job to arrive. int elapsedTime = 0; while ((mEthashStratum == null || mEthashStratum.GetJob() == null || mLbryStratum == null || mLbryStratum.GetJob() == null) && elapsedTime < Parameters.TimeoutForFirstJobInMilliseconds && !Stopped) { Thread.Sleep(100); elapsedTime += 100; } if (mEthashStratum == null || mEthashStratum.GetJob() == null || mLbryStratum == null || mLbryStratum.GetJob() == null) { MainForm.Logger("Stratum server failed to send a new job."); return; } System.Diagnostics.Stopwatch consoleUpdateStopwatch = new System.Diagnostics.Stopwatch(); EthashStratum.Work ethashWork; LbryStratum.Work lbryWork; mEthashSearchKernel.SetMemoryArgument(7, mLbryInputBuffer); mEthashSearchKernel.SetMemoryArgument(8, mLbryOutputBuffer); while (!Stopped && (ethashWork = mEthashStratum.GetWork()) != null && (lbryWork = mLbryStratum.GetWork()) != null) { MarkAsAlive(); String ethashPoolExtranonce = mEthashStratum.PoolExtranonce; byte[] ethashExtranonceByteArray = Utilities.StringToByteArray(ethashPoolExtranonce); byte ethashLocalExtranonce = (byte)ethashWork.LocalExtranonce; UInt64 ethashStartNonce = (UInt64)ethashLocalExtranonce << (8 * (7 - ethashExtranonceByteArray.Length)); for (int i = 0; i < ethashExtranonceByteArray.Length; ++i) { ethashStartNonce |= (UInt64)ethashExtranonceByteArray[i] << (8 * (7 - i)); } ethashStartNonce += (ulong)r.Next(0, int.MaxValue) & (0xfffffffffffffffful >> (ethashExtranonceByteArray.Length * 8 + 8)); String ethashJobID = ethashWork.GetJob().ID; String ethashSeedhash = ethashWork.GetJob().Seedhash; double ethashDifficulty = mEthashStratum.Difficulty; Buffer.BlockCopy(Utilities.StringToByteArray(ethashWork.GetJob().Headerhash), 0, mEthashHeaderhash, 0, 32); Queue.Write <byte>(mEthashHeaderBuffer, true, 0, 32, (IntPtr)ethashHeaderhashPtr, null); var lbryJob = lbryWork.Job; Array.Copy(lbryWork.Blob, mLbryInput, 112); UInt32 lbryStartNonce = (UInt32)(r.Next(0, int.MaxValue)); UInt64 lbryTarget = (UInt64)((double)0xffff0000UL / (mLbryStratum.Difficulty / 256)); mEthashSearchKernel.SetValueArgument <UInt64>(10, lbryTarget); Queue.Write <byte>(mLbryInputBuffer, true, 0, 112, (IntPtr)lbryInputPtr, null); if (ethashEpoch != ethashWork.GetJob().Epoch) { if (ethashDAGBuffer != null) { ethashDAGBuffer.Dispose(); ethashDAGBuffer = null; } ethashEpoch = ethashWork.GetJob().Epoch; DAGCache cache = new DAGCache(ethashEpoch, ethashWork.GetJob().Seedhash); ethashDAGSize = Utilities.GetDAGSize(ethashEpoch); System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); mEthashGlobalWorkSizeArray[0] = ethashDAGSize / 64; mEthashGlobalWorkSizeArray[0] /= 8; if (mEthashGlobalWorkSizeArray[0] % mEthashLocalWorkSizeArray[0] > 0) { mEthashGlobalWorkSizeArray[0] += mEthashLocalWorkSizeArray[0] - mEthashGlobalWorkSizeArray[0] % mEthashLocalWorkSizeArray[0]; } ComputeBuffer <byte> DAGCacheBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadOnly, cache.GetData().Length); fixed(byte *p = cache.GetData()) Queue.Write <byte>(DAGCacheBuffer, true, 0, cache.GetData().Length, (IntPtr)p, null); ethashDAGBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadWrite, mEthashGlobalWorkSizeArray[0] * 8 * 64 /* ethashDAGSize */); // With this, we can remove a conditional statement in the DAG kernel. mEthashDAGKernel.SetValueArgument <UInt32>(0, 0); mEthashDAGKernel.SetMemoryArgument(1, DAGCacheBuffer); mEthashDAGKernel.SetMemoryArgument(2, ethashDAGBuffer); mEthashDAGKernel.SetValueArgument <UInt32>(3, (UInt32)cache.GetData().Length / 64); mEthashDAGKernel.SetValueArgument <UInt32>(4, 0xffffffffu); for (long start = 0; start < ethashDAGSize / 64; start += mEthashGlobalWorkSizeArray[0]) { mEthashGlobalWorkOffsetArray[0] = start; Queue.Execute(mEthashDAGKernel, mEthashGlobalWorkOffsetArray, mEthashGlobalWorkSizeArray, mEthashLocalWorkSizeArray, null); Queue.Finish(); if (Stopped || !mEthashStratum.GetJob().ID.Equals(ethashJobID)) { break; } } DAGCacheBuffer.Dispose(); if (Stopped || !mEthashStratum.GetJob().ID.Equals(ethashJobID)) { break; } sw.Stop(); MainForm.Logger("Generated DAG for Epoch #" + ethashEpoch + " (" + (long)sw.Elapsed.TotalMilliseconds + "ms)."); } consoleUpdateStopwatch.Start(); while (!Stopped && mEthashStratum.GetJob().ID.Equals(ethashJobID) && mEthashStratum.PoolExtranonce.Equals(ethashPoolExtranonce) && mLbryStratum.GetJob().Equals(lbryJob)) { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); MarkAsAlive(); mEthashGlobalWorkOffsetArray[0] = 0; mEthashSearchKernel.SetValueArgument <UInt32>(9, lbryStartNonce);; // Get a new local extranonce if necessary. if ((ethashStartNonce & (0xfffffffffffffffful >> (ethashExtranonceByteArray.Length * 8 + 8)) + (ulong)mEthashGlobalWorkSizeArray[0] * 3 / 4) >= ((ulong)0x1 << (64 - (ethashExtranonceByteArray.Length * 8 + 8)))) { break; } if (0xffffffffu - lbryStartNonce < (UInt32)mEthashGlobalWorkSizeArray[0] / 4) { break; } UInt64 target = (UInt64)((double)0xffff0000U / ethashDifficulty); mEthashSearchKernel.SetMemoryArgument(0, mEthashOutputBuffer); // g_output mEthashSearchKernel.SetMemoryArgument(1, mEthashHeaderBuffer); // g_header mEthashSearchKernel.SetMemoryArgument(2, ethashDAGBuffer); // _g_dag mEthashSearchKernel.SetValueArgument <UInt32>(3, (UInt32)(ethashDAGSize / 128)); // DAG_SIZE mEthashSearchKernel.SetValueArgument <UInt64>(4, ethashStartNonce); // start_nonce mEthashSearchKernel.SetValueArgument <UInt64>(5, target); // target mEthashSearchKernel.SetValueArgument <UInt32>(6, 0xffffffffu); // isolate mEthashOutput[255] = 0; // mEthashOutput[255] is used as an atomic counter. Queue.Write <UInt32>(mEthashOutputBuffer, true, 0, 256, (IntPtr)ethashOutputPtr, null); mLbryOutput[255] = 0; // mLbryOutput[255] is used as an atomic counter. Queue.Write <UInt32>(mLbryOutputBuffer, true, 0, lbryOutputSize, (IntPtr)lbryOutputPtr, null); Queue.Execute(mEthashSearchKernel, mEthashGlobalWorkOffsetArray, mEthashGlobalWorkSizeArray, mEthashLocalWorkSizeArray, null); Queue.Read <UInt32>(mEthashOutputBuffer, true, 0, 256, (IntPtr)ethashOutputPtr, null); if (mEthashStratum.GetJob().ID.Equals(ethashJobID)) { for (int i = 0; i < mEthashOutput[255]; ++i) { mEthashStratum.Submit(Device, ethashWork.GetJob(), ethashStartNonce + (UInt64)mEthashOutput[i]); } } ethashStartNonce += (UInt64)mEthashGlobalWorkSizeArray[0] * 3 / 4; Queue.Read <UInt32>(mLbryOutputBuffer, true, 0, lbryOutputSize, (IntPtr)lbryOutputPtr, null); if (mLbryStratum.GetJob().Equals(lbryJob)) { for (int i = 0; i < mLbryOutput[255]; ++i) { String result = ""; for (int j = 0; j < 8; ++j) { UInt32 word = mLbryOutput[256 + i * 8 + j]; result += String.Format("{0:x2}{1:x2}{2:x2}{3:x2}", ((word >> 0) & 0xff), ((word >> 8) & 0xff), ((word >> 16) & 0xff), ((word >> 24) & 0xff)); } mLbryStratum.Submit(Device, lbryWork, mLbryOutput[i], result); } } lbryStartNonce += (UInt32)mEthashGlobalWorkSizeArray[0] / 4; sw.Stop(); Speed = ((double)mEthashGlobalWorkSizeArray[0] * 3 / 4) / sw.Elapsed.TotalSeconds; double speedSecondary = (((double)mEthashGlobalWorkSizeArray[0] / 4) / sw.Elapsed.TotalSeconds); if (consoleUpdateStopwatch.ElapsedMilliseconds >= 10 * 1000) { MainForm.Logger("Device #" + DeviceIndex + " (Ethash): " + String.Format("{0:N2} Mh/s (Ethash), {1:N2} Mh/s (Lbry)", Speed / (1000000), speedSecondary / (1000000))); consoleUpdateStopwatch.Restart(); } } } if (ethashDAGBuffer != null) { ethashDAGBuffer.Dispose(); ethashDAGBuffer = null; } } catch (Exception ex) { MainForm.Logger("Exception in miner thread: " + ex.Message + ex.StackTrace); Speed = 0; if (UnrecoverableException.IsUnrecoverableException(ex)) { this.UnrecoverableException = new UnrecoverableException(ex, Device); Stop(); } else { MainForm.Logger("Restarting miner thread..."); System.Threading.Thread.Sleep(5000); } } } MarkAsDone(); }
override unsafe protected void MinerThread() { Random r = new Random(); UInt32[] output = new UInt32[256]; ComputeDevice computeDevice = Device.GetComputeDevice(); MarkAsAlive(); MainForm.Logger("Miner thread for Device #" + DeviceIndex + " started."); ComputeProgram program; try { mProgramArrayMutex.WaitOne(); } catch (Exception) { } if (mProgramArray.ContainsKey(new long[] { DeviceIndex, mLocalWorkSize })) { program = mProgramArray[new long[] { DeviceIndex, mLocalWorkSize }]; } else { String source = System.IO.File.ReadAllText(@"Kernels\ethash.cl"); program = new ComputeProgram(Context, source); MainForm.Logger("Loaded ethash program for Device #" + DeviceIndex + "."); String buildOptions = (Device.Vendor == "AMD" ? "-O1 " : Device.Vendor == "NVIDIA" ? "" : // "-cl-nv-opt-level=1 -cl-nv-maxrregcount=256 " : "") + " -IKernels -DWORKSIZE=" + mLocalWorkSize; try { program.Build(Device.DeviceList, buildOptions, null, IntPtr.Zero); } catch (Exception) { MainForm.Logger(program.GetBuildLog(computeDevice)); throw; } MainForm.Logger("Built cryptonight program for Device #" + DeviceIndex + "."); MainForm.Logger("Built options: " + buildOptions); mProgramArray[new long[] { DeviceIndex, mLocalWorkSize }] = program; } try { mProgramArrayMutex.ReleaseMutex(); } catch (Exception) { } while (!Stopped) { MarkAsAlive(); try { // Wait for the first job to arrive. int elapsedTime = 0; while ((mStratum == null || mStratum.GetJob() == null) && elapsedTime < 5000) { Thread.Sleep(10); elapsedTime += 10; } if (mStratum == null || mStratum.GetJob() == null) { MainForm.Logger("Stratum server failed to send a new job."); //throw new TimeoutException("Stratum server failed to send a new job."); return; } int epoch = -1; long DAGSize = 0; ComputeBuffer <byte> DAGBuffer = null; using (ComputeKernel DAGKernel = program.CreateKernel("GenerateDAG")) using (ComputeKernel searchKernel = program.CreateKernel("search")) using (ComputeBuffer <UInt32> outputBuffer = new ComputeBuffer <UInt32>(Context, ComputeMemoryFlags.ReadWrite, 256)) using (ComputeBuffer <byte> headerBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadOnly, 32)) { MarkAsAlive(); System.Diagnostics.Stopwatch consoleUpdateStopwatch = new System.Diagnostics.Stopwatch(); EthashStratum.Work work; while (!Stopped && (work = mStratum.GetWork()) != null) { String poolExtranonce = mStratum.PoolExtranonce; byte[] extranonceByteArray = Utilities.StringToByteArray(poolExtranonce); byte localExtranonce = work.LocalExtranonce; UInt64 startNonce = (UInt64)localExtranonce << (8 * (7 - extranonceByteArray.Length)); for (int i = 0; i < extranonceByteArray.Length; ++i) { startNonce |= (UInt64)extranonceByteArray[i] << (8 * (7 - i)); } startNonce += (ulong)r.Next(0, int.MaxValue) & (0xfffffffffffffffful >> (extranonceByteArray.Length * 8 + 8)); String jobID = work.GetJob().ID; String headerhash = work.GetJob().Headerhash; String seedhash = work.GetJob().Seedhash; double difficulty = mStratum.Difficulty; fixed(byte *p = Utilities.StringToByteArray(headerhash)) Queue.Write <byte>(headerBuffer, true, 0, 32, (IntPtr)p, null); if (epoch != work.GetJob().Epoch) { if (DAGBuffer != null) { DAGBuffer.Dispose(); DAGBuffer = null; } epoch = work.GetJob().Epoch; DAGCache cache = new DAGCache(epoch, work.GetJob().Seedhash); DAGSize = Utilities.GetDAGSize(epoch); System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); fixed(byte *p = cache.GetData()) { long globalWorkSize = DAGSize / 64; globalWorkSize /= 8; if (globalWorkSize % mLocalWorkSize > 0) { globalWorkSize += mLocalWorkSize - globalWorkSize % mLocalWorkSize; } ComputeBuffer <byte> DAGCacheBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadOnly | ComputeMemoryFlags.CopyHostPointer, cache.GetData().Length, (IntPtr)p); DAGBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadWrite, globalWorkSize * 8 * 64 /* DAGSize */); // With this, we can remove a conditional statement in the DAG kernel. DAGKernel.SetValueArgument <UInt32>(0, 0); DAGKernel.SetMemoryArgument(1, DAGCacheBuffer); DAGKernel.SetMemoryArgument(2, DAGBuffer); DAGKernel.SetValueArgument <UInt32>(3, (UInt32)cache.GetData().Length / 64); DAGKernel.SetValueArgument <UInt32>(4, 0xffffffffu); for (long start = 0; start < DAGSize / 64; start += globalWorkSize) { Queue.Execute(DAGKernel, new long[] { start }, new long[] { globalWorkSize }, new long[] { mLocalWorkSize }, null); Queue.Finish(); if (Stopped || !mStratum.GetJob().ID.Equals(jobID)) { break; } } DAGCacheBuffer.Dispose(); if (Stopped || !mStratum.GetJob().ID.Equals(jobID)) { break; } } sw.Stop(); MainForm.Logger("Generated DAG for Epoch #" + epoch + " (" + (long)sw.Elapsed.TotalMilliseconds + "ms)."); } consoleUpdateStopwatch.Start(); while (!Stopped && mStratum.GetJob().ID.Equals(jobID) && mStratum.PoolExtranonce.Equals(poolExtranonce)) { MarkAsAlive(); // Get a new local extranonce if necessary. if ((startNonce & (0xfffffffffffffffful >> (extranonceByteArray.Length * 8 + 8)) + (ulong)mGlobalWorkSize) >= ((ulong)0x1 << (64 - (extranonceByteArray.Length * 8 + 8)))) { break; } UInt64 target = (UInt64)((double)0xffff0000U / difficulty); searchKernel.SetMemoryArgument(0, outputBuffer); // g_output searchKernel.SetMemoryArgument(1, headerBuffer); // g_header searchKernel.SetMemoryArgument(2, DAGBuffer); // _g_dag searchKernel.SetValueArgument <UInt32>(3, (UInt32)(DAGSize / 128)); // DAG_SIZE searchKernel.SetValueArgument <UInt64>(4, startNonce); // start_nonce searchKernel.SetValueArgument <UInt64>(5, target); // target searchKernel.SetValueArgument <UInt32>(6, 0xffffffffu); // isolate System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); fixed(UInt32 *p = output) { output[255] = 0; // output[255] is used as an atomic counter. Queue.Write <UInt32>(outputBuffer, true, 0, 256, (IntPtr)p, null); Queue.Execute(searchKernel, new long[] { 0 }, new long[] { mGlobalWorkSize }, new long[] { mLocalWorkSize }, null); Queue.Read <UInt32>(outputBuffer, true, 0, 256, (IntPtr)p, null); } sw.Stop(); mSpeed = ((double)mGlobalWorkSize) / sw.Elapsed.TotalSeconds; if (consoleUpdateStopwatch.ElapsedMilliseconds >= 10 * 1000) { MainForm.Logger("Device #" + DeviceIndex + ": " + String.Format("{0:N2} Mh/s", mSpeed / (1000000))); consoleUpdateStopwatch.Restart(); } if (mStratum.GetJob().ID.Equals(jobID)) { for (int i = 0; i < output[255]; ++i) { mStratum.Submit(GatelessGateDevice, work.GetJob(), startNonce + (UInt64)output[i]); } } startNonce += (UInt64)mGlobalWorkSize; } } } if (DAGBuffer != null) { DAGBuffer.Dispose(); DAGBuffer = null; } } catch (Exception ex) { MainForm.Logger("Exception in miner thread: " + ex.Message + ex.StackTrace); MainForm.Logger("Restarting miner thread..."); } } MarkAsDone(); }
unsafe public void MinerThread() { MainForm.Logger("Miner thread for Device #" + DeviceIndex + " started."); // Wait for the first job to arrive. int timePassed = 0; while ((mStratum == null || mStratum.CurrentJob == null) && timePassed < 5000) { Thread.Sleep(10); timePassed += 10; } if (mStratum == null || mStratum.CurrentJob == null) { MainForm.Logger("Stratum server failed to send a new job."); //throw new TimeoutException("Stratum server failed to send a new job."); return; } System.Diagnostics.Stopwatch consoleUpdateStopwatch = new System.Diagnostics.Stopwatch(); EthashStratum.Work work; int epoch = -1; long DAGSize = 0; ComputeBuffer <byte> DAGBuffer = null; ComputeBuffer <UInt32> outputBuffer = new ComputeBuffer <UInt32>(Context, ComputeMemoryFlags.ReadWrite, 256); ComputeBuffer <byte> headerBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadOnly, 32); UInt32[] output = new UInt32[256]; Random r = new Random(); while (!Stopped && (work = mStratum.GetWork()) != null) { String poolExtranonce = mStratum.PoolExtranonce; byte[] extranonceByteArray = Utilities.StringToByteArray(poolExtranonce); byte localExtranonce = work.LocalExtranonce; UInt64 startNonce = (UInt64)localExtranonce << (8 * (7 - extranonceByteArray.Length)); for (int i = 0; i < extranonceByteArray.Length; ++i) { startNonce |= (UInt64)extranonceByteArray[i] << (8 * (7 - i)); } startNonce += (ulong)r.Next(0, int.MaxValue) & (0xfffffffffffffffful >> (extranonceByteArray.Length * 8 + 16)); String jobID = work.GetJob().ID; String headerhash = work.GetJob().Headerhash; String seedhash = work.GetJob().Seedhash; double difficulty = mStratum.Difficulty; fixed(byte *p = Utilities.StringToByteArray(headerhash)) Queue.Write <byte>(headerBuffer, true, 0, 32, (IntPtr)p, null); if (epoch != work.GetJob().Epoch) { if (DAGBuffer != null) { DAGBuffer.Dispose(); DAGBuffer = null; } epoch = work.GetJob().Epoch; DAGCache cache = new DAGCache(epoch, work.GetJob().Seedhash); DAGSize = Utilities.GetDAGSize(epoch); System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); fixed(byte *p = cache.GetData()) { long globalWorkSize = DAGSize / 64; globalWorkSize /= 8; if (globalWorkSize % mLocalWorkSize > 0) { globalWorkSize += mLocalWorkSize - globalWorkSize % mLocalWorkSize; } ComputeBuffer <byte> DAGCacheBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadOnly | ComputeMemoryFlags.CopyHostPointer, cache.GetData().Length, (IntPtr)p); DAGBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadWrite, globalWorkSize * 8 * 64 /* DAGSize */); // With this, we can remove a conditional statement in the DAG kernel. mDAGKernel.SetValueArgument <UInt32>(0, 0); mDAGKernel.SetMemoryArgument(1, DAGCacheBuffer); mDAGKernel.SetMemoryArgument(2, DAGBuffer); mDAGKernel.SetValueArgument <UInt32>(3, (UInt32)cache.GetData().Length / 64); //mDAGKernel.SetValueArgument<UInt32>(4, (UInt32)(DAGSize / 64)); mDAGKernel.SetValueArgument <UInt32>(4, 0xffffffffu); for (long start = 0; start < DAGSize / 64; start += globalWorkSize) { Queue.Execute(mDAGKernel, new long[] { start }, new long[] { globalWorkSize }, new long[] { mLocalWorkSize }, null); Queue.Finish(); } DAGCacheBuffer.Dispose(); } sw.Stop(); MainForm.Logger("Generated DAG for Epoch #" + epoch + " (" + (long)sw.Elapsed.TotalMilliseconds + "ms)."); } consoleUpdateStopwatch.Start(); while (!Stopped && mStratum.CurrentJob.ID.Equals(jobID) && mStratum.PoolExtranonce.Equals(poolExtranonce)) { UInt64 target = (UInt64)((double)0xffff0000U / difficulty); mSearchKernel.SetMemoryArgument(0, outputBuffer); // g_output mSearchKernel.SetMemoryArgument(1, headerBuffer); // g_header mSearchKernel.SetMemoryArgument(2, DAGBuffer); // _g_dag mSearchKernel.SetValueArgument <UInt32>(3, (UInt32)(DAGSize / 128)); // DAG_SIZE mSearchKernel.SetValueArgument <UInt64>(4, startNonce); // start_nonce mSearchKernel.SetValueArgument <UInt64>(5, target); // target mSearchKernel.SetValueArgument <UInt32>(6, 0xffffffffu); // isolate System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); fixed(UInt32 *p = output) { output[255] = 0; // output[255] is used as an atomic counter. Queue.Write <UInt32>(outputBuffer, true, 0, 256, (IntPtr)p, null); Queue.Execute(mSearchKernel, new long[] { 0 }, new long[] { mGlobalWorkSize }, new long[] { mLocalWorkSize }, null); Queue.Read <UInt32>(outputBuffer, true, 0, 256, (IntPtr)p, null); } sw.Stop(); mSpeed = ((double)mGlobalWorkSize) / sw.Elapsed.TotalSeconds; if (consoleUpdateStopwatch.ElapsedMilliseconds >= 10 * 1000) { MainForm.Logger("Device #" + DeviceIndex + ": " + String.Format("{0:N2} Mh/s", mSpeed / (1000000))); consoleUpdateStopwatch.Restart(); } for (int i = 0; i < output[255]; ++i) { mStratum.Submit(work.GetJob(), startNonce + (UInt64)output[i]); } startNonce += (UInt64)mGlobalWorkSize; } } headerBuffer.Dispose(); outputBuffer.Dispose(); DAGBuffer.Dispose(); mSpeed = 0; }
override unsafe protected void MinerThread() { ComputeProgram program = null; try { Random r = new Random(); ComputeDevice computeDevice = OpenCLDevice.GetComputeDevice(); UInt32[] ethashOutput = new UInt32[256]; byte[] ethashHeaderhash = new byte[32]; MarkAsAlive(); MainForm.Logger("Miner thread for Device #" + DeviceIndex + " started."); program = BuildProgram("ethash", mEthashLocalWorkSizeArray[0], "-O1", "", ""); MemoryUsage = 256 + 32; using (var searchKernel = program.CreateKernel("search")) using (var DAGKernel = program.CreateKernel("GenerateDAG")) using (var ethashOutputBuffer = new ComputeBuffer <UInt32>(Context, ComputeMemoryFlags.ReadWrite, 256)) using (var ethashHeaderBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadOnly, 32)) fixed(UInt32 *ethashOutputPtr = ethashOutput) fixed(byte *ethashHeaderhashPtr = ethashHeaderhash) while (!Stopped) { ComputeBuffer <byte> ethashDAGBuffer = null; MarkAsAlive(); try { int ethashEpoch = -1; long ethashDAGSize = 0; // Wait for the first job to arrive. int elapsedTime = 0; while ((Stratum == null || Stratum.GetJob() == null) && elapsedTime < Parameters.TimeoutForFirstJobInMilliseconds && !Stopped) { Thread.Sleep(100); elapsedTime += 100; } if (Stratum == null || Stratum.GetJob() == null) { MainForm.Logger("Ethash stratum server failed to send a new job."); //throw new TimeoutException("Stratum server failed to send a new job."); return; } System.Diagnostics.Stopwatch consoleUpdateStopwatch = new System.Diagnostics.Stopwatch(); EthashStratum.Work ethashWork; EthashStratum.Job ethashJob; while (!Stopped && (ethashWork = Stratum.GetWork()) != null && (ethashJob = ethashWork.GetJob()) != null) { MarkAsAlive(); String ethashPoolExtranonce = Stratum.PoolExtranonce; byte[] ethashExtranonceByteArray = Utilities.StringToByteArray(ethashPoolExtranonce); byte ethashLocalExtranonce = (byte)ethashWork.LocalExtranonce; UInt64 ethashStartNonce = (UInt64)ethashLocalExtranonce << (8 * (7 - ethashExtranonceByteArray.Length)); for (int i = 0; i < ethashExtranonceByteArray.Length; ++i) { ethashStartNonce |= (UInt64)ethashExtranonceByteArray[i] << (8 * (7 - i)); } ethashStartNonce += (ulong)r.Next(0, int.MaxValue) & (0xfffffffffffffffful >> (ethashExtranonceByteArray.Length * 8 + 8)); String ethashJobID = ethashJob.ID; String ethashSeedhash = ethashJob.Seedhash; double ethashDifficulty = Stratum.Difficulty; Buffer.BlockCopy(Utilities.StringToByteArray(ethashWork.GetJob().Headerhash), 0, ethashHeaderhash, 0, 32); Queue.Write <byte>(ethashHeaderBuffer, true, 0, 32, (IntPtr)ethashHeaderhashPtr, null); if (ethashEpoch != ethashWork.GetJob().Epoch) { if (ethashDAGBuffer != null) { MemoryUsage -= ethashDAGBuffer.Size; ethashDAGBuffer.Dispose(); ethashDAGBuffer = null; } ethashEpoch = ethashWork.GetJob().Epoch; DAGCache cache = new DAGCache(ethashEpoch, ethashWork.GetJob().Seedhash); ethashDAGSize = Utilities.GetDAGSize(ethashEpoch); System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); mEthashGlobalWorkSizeArray[0] = ethashDAGSize / 64; mEthashGlobalWorkSizeArray[0] /= 8; if (mEthashGlobalWorkSizeArray[0] % mEthashLocalWorkSizeArray[0] > 0) { mEthashGlobalWorkSizeArray[0] += mEthashLocalWorkSizeArray[0] - mEthashGlobalWorkSizeArray[0] % mEthashLocalWorkSizeArray[0]; } ComputeBuffer <byte> DAGCacheBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadOnly, cache.GetData().Length); fixed(byte *p = cache.GetData()) Queue.Write <byte>(DAGCacheBuffer, true, 0, cache.GetData().Length, (IntPtr)p, null); ethashDAGBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadWrite, mEthashGlobalWorkSizeArray[0] * 8 * 64 /* ethashDAGSize */); // With this, we can remove a conditional statement in the DAG kernel. MemoryUsage += DAGCacheBuffer.Size + ethashDAGBuffer.Size; DAGKernel.SetValueArgument <UInt32>(0, 0); DAGKernel.SetMemoryArgument(1, DAGCacheBuffer); DAGKernel.SetMemoryArgument(2, ethashDAGBuffer); DAGKernel.SetValueArgument <UInt32>(3, (UInt32)cache.GetData().Length / 64); DAGKernel.SetValueArgument <UInt32>(4, 0xffffffffu); for (long start = 0; start < ethashDAGSize / 64; start += mEthashGlobalWorkSizeArray[0]) { mEthashGlobalWorkOffsetArray[0] = start; Queue.Execute(DAGKernel, mEthashGlobalWorkOffsetArray, mEthashGlobalWorkSizeArray, mEthashLocalWorkSizeArray, null); Queue.Finish(); if (Stopped || Stratum.GetJob() == null || !Stratum.GetJob().ID.Equals(ethashJobID)) { break; } } MemoryUsage -= DAGCacheBuffer.Size; DAGCacheBuffer.Dispose(); if (Stopped || Stratum.GetJob() == null || !Stratum.GetJob().ID.Equals(ethashJobID)) { break; } sw.Stop(); MainForm.Logger("Generated DAG for Epoch #" + ethashEpoch + " (" + (long)sw.Elapsed.TotalMilliseconds + "ms)."); } consoleUpdateStopwatch.Start(); while (!Stopped && Stratum.GetJob() != null && Stratum.GetJob().ID.Equals(ethashJobID) && Stratum.PoolExtranonce.Equals(ethashPoolExtranonce)) { MarkAsAlive(); // Get a new local extranonce if necessary. if ((ethashStartNonce & (0xfffffffffffffffful >> (ethashExtranonceByteArray.Length * 8 + 8)) + (ulong)mEthashGlobalWorkSizeArray[0]) >= ((ulong)0x1 << (64 - (ethashExtranonceByteArray.Length * 8 + 8)))) { break; } UInt64 target = (UInt64)((double)0xffff0000U / ethashDifficulty); searchKernel.SetMemoryArgument(0, ethashOutputBuffer); // g_output searchKernel.SetMemoryArgument(1, ethashHeaderBuffer); // g_header searchKernel.SetMemoryArgument(2, ethashDAGBuffer); // _g_dag searchKernel.SetValueArgument <UInt32>(3, (UInt32)(ethashDAGSize / 128)); // DAG_SIZE searchKernel.SetValueArgument <UInt64>(4, ethashStartNonce); // start_nonce searchKernel.SetValueArgument <UInt64>(5, target); // target searchKernel.SetValueArgument <UInt32>(6, 0xffffffffu); // isolate System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); ethashOutput[255] = 0; // ethashOutput[255] is used as an atomic counter. Queue.Write <UInt32>(ethashOutputBuffer, true, 0, 256, (IntPtr)ethashOutputPtr, null); mEthashGlobalWorkOffsetArray[0] = 0; Queue.Execute(searchKernel, mEthashGlobalWorkOffsetArray, mEthashGlobalWorkSizeArray, mEthashLocalWorkSizeArray, null); Queue.Read <UInt32>(ethashOutputBuffer, true, 0, 256, (IntPtr)ethashOutputPtr, null); if (Stratum.GetJob() != null && Stratum.GetJob().ID.Equals(ethashJobID)) { for (int i = 0; i < ethashOutput[255]; ++i) { Stratum.Submit(Device, ethashWork.GetJob(), ethashStartNonce + (UInt64)ethashOutput[i]); } } ethashStartNonce += (UInt64)mEthashGlobalWorkSizeArray[0]; sw.Stop(); Speed = ((double)mEthashGlobalWorkSizeArray[0]) / sw.Elapsed.TotalSeconds; Device.TotalHashesPrimaryAlgorithm += (double)mEthashGlobalWorkSizeArray[0]; if (consoleUpdateStopwatch.ElapsedMilliseconds >= 10 * 1000) { MainForm.Logger("Device #" + DeviceIndex + " (Ethash): " + String.Format("{0:N2} Mh/s", Speed / (1000000))); consoleUpdateStopwatch.Restart(); } } } } catch (Exception ex) { MainForm.Logger("Exception in miner thread: " + ex.Message + ex.StackTrace); Speed = 0; if (UnrecoverableException.IsUnrecoverableException(ex)) { this.UnrecoverableException = new UnrecoverableException(ex, Device); Stop(); } else { MainForm.Logger("Restarting miner thread..."); System.Threading.Thread.Sleep(Parameters.WaitTimeForRestartingMinerThreadInMilliseconds); } } finally { if (ethashDAGBuffer != null) { MemoryUsage -= ethashDAGBuffer.Size; ethashDAGBuffer.Dispose(); ethashDAGBuffer = null; } } } } catch (UnrecoverableException ex) { this.UnrecoverableException = ex; } catch (Exception ex) { this.UnrecoverableException = new UnrecoverableException(ex, Device); } finally { MarkAsDone(); MemoryUsage = 0; if (program != null) { program.Dispose(); } program = null; } }