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(); }
override unsafe protected void MinerThread() { Random r = new Random(); MarkAsAlive(); MainForm.Logger("Miner thread for Device #" + DeviceIndex + " started."); BuildPascalProgram(); fixed(long *pascalGlobalWorkOffsetArrayPtr = mPascalGlobalWorkOffsetArray) fixed(long *pascalGlobalWorkSizeArrayPtr = mPascalGlobalWorkSizeArray) fixed(long *pascalLocalWorkSizeArrayPtr = mPascalLocalWorkSizeArray) fixed(byte *pascalMidstatePtr = mPascalMidstate) fixed(byte *pascalInputPtr = mPascalInput) fixed(UInt32 * pascalOutputPtr = mPascalOutput) while (!Stopped) { MarkAsAlive(); try { mPascalSearchKernel.SetMemoryArgument(0, mPascalInputBuffer); mPascalSearchKernel.SetMemoryArgument(1, mPascalOutputBuffer); mPascalSearchKernel.SetMemoryArgument(4, mPascalMidstateBuffer); // Wait for the first PascalJob to arrive. int elapsedTime = 0; while ((mPascalStratum == null || mPascalStratum.GetJob() == null) && elapsedTime < 60000) { Thread.Sleep(100); elapsedTime += 100; } if (mPascalStratum == null || mPascalStratum.GetJob() == null) { throw new TimeoutException("Stratum server failed to send a new PascalJob."); } System.Diagnostics.Stopwatch consoleUpdateStopwatch = new System.Diagnostics.Stopwatch(); PascalStratum.Work pascalWork; while (!Stopped && (pascalWork = mPascalStratum.GetWork()) != null) { MarkAsAlive(); 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); mPascalSearchKernel.SetValueArgument <UInt64>(3, PascalTarget); Queue.Write <byte>(mPascalInputBuffer, true, 0, sPascalInputSize, (IntPtr)pascalInputPtr, null); consoleUpdateStopwatch.Start(); while (!Stopped && mPascalStratum.GetJob().Equals(pascalJob)) { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); MarkAsAlive(); mPascalSearchKernel.SetValueArgument <UInt32>(2, pascalStartNonce); // Get a new local extranonce if necessary. if (0xffffffffu - pascalStartNonce < (UInt32)mPascalGlobalWorkSizeArray[0]) { break; } mPascalOutput[255] = 0; // mPascalOutput[255] is used as an atomic counter. Queue.Write <UInt32>(mPascalOutputBuffer, true, 0, sPascalOutputSize, (IntPtr)pascalOutputPtr, null); Queue.Execute(mPascalSearchKernel, mPascalGlobalWorkOffsetArray, mPascalGlobalWorkSizeArray, mPascalLocalWorkSizeArray, null); 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)mPascalGlobalWorkSizeArray[0]; sw.Stop(); Speed = ((double)mPascalGlobalWorkSizeArray[0]) / sw.Elapsed.TotalSeconds; if (consoleUpdateStopwatch.ElapsedMilliseconds >= 10 * 1000) { MainForm.Logger("Device #" + DeviceIndex + ": " + String.Format("{0:N2} Mh/s (Pascal)", Speed / 1000000)); consoleUpdateStopwatch.Restart(); } } } } catch (Exception ex) { MainForm.Logger("Exception in miner thread: " + ex.Message + ex.StackTrace); if (UnrecoverableException.IsUnrecoverableException(ex)) { this.UnrecoverableException = new UnrecoverableException(ex, GatelessGateDevice); Stop(); } } Speed = 0; if (!Stopped) { MainForm.Logger("Restarting miner thread..."); System.Threading.Thread.Sleep(5000); } } MarkAsDone(); }