private void BuildEthashProgram()
        {
            ComputeDevice computeDevice = OpenCLDevice.GetComputeDevice();

            try { mProgramArrayMutex.WaitOne(5000); } catch (Exception) { }

            if (mEthashProgramArray.ContainsKey(new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }))
            {
                mEthashProgram      = mEthashProgramArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }];
                mEthashDAGKernel    = mEthashDAGKernelArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }];
                mEthashSearchKernel = mEthashSearchKernelArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }];
            }
            else
            {
                try
                {
                    if (mEthashLocalWorkSizeArray[0] != 192)
                    {
                        throw new Exception("No suitable binary file was found.");
                    }
                    string fileName = @"BinaryKernels\" + computeDevice.Name + "_ethash.bin";
                    byte[] binary   = System.IO.File.ReadAllBytes(fileName);
                    mEthashProgram = new ComputeProgram(Context, new List <byte[]>()
                    {
                        binary
                    }, new List <ComputeDevice>()
                    {
                        computeDevice
                    });
                    MainForm.Logger("Loaded " + fileName + " for Device #" + DeviceIndex + ".");
                }
                catch (Exception)
                {
                    //MainForm.Logger("ex.message: " + ex.Message);
                    String source = System.IO.File.ReadAllText(@"Kernels\ethash.cl");
                    mEthashProgram = new ComputeProgram(Context, source);
                    MainForm.Logger(@"Loaded Kernels\ethash.cl for Device #" + DeviceIndex + ".");
                }
                String buildOptions = (OpenCLDevice.GetVendor() == "AMD"    ? "-O1 " :
                                       OpenCLDevice.GetVendor() == "NVIDIA" ? "" : // "-cl-nv-opt-level=1 -cl-nv-maxrregcount=256 " :
                                       "")
                                      + " -IKernels -DWORKSIZE=" + mEthashLocalWorkSizeArray[0];
                try
                {
                    mEthashProgram.Build(OpenCLDevice.DeviceList, buildOptions, null, IntPtr.Zero);
                }
                catch (Exception)
                {
                    MainForm.Logger(mEthashProgram.GetBuildLog(computeDevice));
                    throw;
                }
                MainForm.Logger("Built Ethash program for Device #" + DeviceIndex + ".");
                MainForm.Logger("Build options: " + buildOptions);
                mEthashProgramArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }]      = mEthashProgram;
                mEthashDAGKernelArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }]    = mEthashDAGKernel = mEthashProgram.CreateKernel("GenerateDAG");
                mEthashSearchKernelArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }] = mEthashSearchKernel = mEthashProgram.CreateKernel("search");
            }

            try { mProgramArrayMutex.ReleaseMutex(); } catch (Exception) { }
        }
        public void BuildNeoScryptProgram()
        {
            ComputeDevice computeDevice = OpenCLDevice.GetComputeDevice();

            try { mProgramArrayMutex.WaitOne(5000); } catch (Exception) { }

            if (mNeoScryptProgramArray.ContainsKey(new ProgramArrayIndex(DeviceIndex, mNeoScryptLocalWorkSizeArray[0])))
            {
                mNeoScryptProgram      = mNeoScryptProgramArray[new ProgramArrayIndex(DeviceIndex, mNeoScryptLocalWorkSizeArray[0])];
                mNeoScryptSearchKernel = mNeoScryptSearchKernelArray[new ProgramArrayIndex(DeviceIndex, mNeoScryptLocalWorkSizeArray[0])];
            }
            else
            {
                String source = System.IO.File.ReadAllText(@"Kernels\neoscrypt.cl");
                mNeoScryptProgram = new ComputeProgram(Context, source);
                MainForm.Logger(@"Loaded Kernels\neoscrypt.cl for Device #" + DeviceIndex + ".");
                String buildOptions = (OpenCLDevice.GetVendor() == "AMD" ? "-O5 -legacy" : // "-legacy" :
                                       OpenCLDevice.GetVendor() == "NVIDIA" ? "" :         //"-cl-nv-opt-level=1 -cl-nv-maxrregcount=256 " :
                                       "")
                                      + " -IKernels -DWORKSIZE=" + mNeoScryptLocalWorkSizeArray[0];
                try {
                    mNeoScryptProgram.Build(OpenCLDevice.DeviceList, buildOptions, null, IntPtr.Zero);
                } catch (Exception) {
                    MainForm.Logger(mNeoScryptProgram.GetBuildLog(computeDevice));
                    throw;
                }
                MainForm.Logger("Built NeoScrypt program for Device #" + DeviceIndex + ".");
                MainForm.Logger("Build options: " + buildOptions);
                mNeoScryptProgramArray[new ProgramArrayIndex(DeviceIndex, mNeoScryptLocalWorkSizeArray[0])]      = mNeoScryptProgram;
                mNeoScryptSearchKernelArray[new ProgramArrayIndex(DeviceIndex, mNeoScryptLocalWorkSizeArray[0])] = mNeoScryptSearchKernel = mNeoScryptProgram.CreateKernel("search");
            }

            try { mProgramArrayMutex.ReleaseMutex(); } catch (Exception) { }
        }
Beispiel #3
0
        public void BuildLbryProgram()
        {
            ComputeDevice computeDevice = OpenCLDevice.GetComputeDevice();

            try { mProgramArrayMutex.WaitOne(5000); } catch (Exception) { }

            if (mLbryProgramArray.ContainsKey(new ProgramArrayIndex(DeviceIndex, mLbryLocalWorkSizeArray[0])))
            {
                mLbryProgram      = mLbryProgramArray[new ProgramArrayIndex(DeviceIndex, mLbryLocalWorkSizeArray[0])];
                mLbrySearchKernel = mLbrySearchKernelArray[new ProgramArrayIndex(DeviceIndex, mLbryLocalWorkSizeArray[0])];
            }
            else
            {
                try
                {
                    if (mLbryLocalWorkSizeArray[0] != 256)
                    {
                        throw new Exception("No suitable binary file was found.");
                    }
                    string fileName = @"BinaryKernels\" + computeDevice.Name + "_lbry.bin";
                    byte[] binary   = System.IO.File.ReadAllBytes(fileName);
                    mLbryProgram = new ComputeProgram(Context, new List <byte[]>()
                    {
                        binary
                    }, new List <ComputeDevice>()
                    {
                        computeDevice
                    });
                    //MainForm.Logger("Loaded " + fileName + " for Device #" + DeviceIndex + ".");
                }
                catch (Exception)
                {
                    String source = System.IO.File.ReadAllText(@"Kernels\lbry.cl");
                    mLbryProgram = new ComputeProgram(Context, source);
                    //MainForm.Logger(@"Loaded Kernels\lbry.cl for Device #" + DeviceIndex + ".");
                }
                String buildOptions = (OpenCLDevice.GetVendor() == "AMD" ? "-O1 " : //"-O1 " :
                                       OpenCLDevice.GetVendor() == "NVIDIA" ? "" :  //"-cl-nv-opt-level=1 -cl-nv-maxrregcount=256 " :
                                       "")
                                      + " -IKernels -DWORKSIZE=" + mLbryLocalWorkSizeArray[0] + " -DITERATIONS=" + mIterations;
                try
                {
                    mLbryProgram.Build(OpenCLDevice.DeviceList, buildOptions, null, IntPtr.Zero);
                }
                catch (Exception)
                {
                    MainForm.Logger(mLbryProgram.GetBuildLog(computeDevice));
                    throw;
                }
                //MainForm.Logger("Built Lbry program for Device #" + DeviceIndex + ".");
                //MainForm.Logger("Build options: " + buildOptions);
                mLbryProgramArray[new ProgramArrayIndex(DeviceIndex, mLbryLocalWorkSizeArray[0])]      = mLbryProgram;
                mLbrySearchKernelArray[new ProgramArrayIndex(DeviceIndex, mLbryLocalWorkSizeArray[0])] = mLbrySearchKernel = mLbryProgram.CreateKernel("search_combined");
            }

            try { mProgramArrayMutex.ReleaseMutex(); } catch (Exception) { }
        }
Beispiel #4
0
        private void BuildEthashProgram()
        {
            ComputeDevice computeDevice = OpenCLDevice.GetComputeDevice();

            try { mProgramArrayMutex.WaitOne(5000); } catch (Exception) { }

            if (mEthashProgramArray.ContainsKey(new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }))
            {
                mEthashProgram      = mEthashProgramArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }];
                mEthashDAGKernel    = mEthashDAGKernelArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }];
                mEthashSearchKernel = mEthashSearchKernelArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }];
            }
            else
            {
                String source = System.IO.File.ReadAllText(@"Kernels\ethash_lbry.cl");
                mEthashProgram = new ComputeProgram(Context, source);
                MainForm.Logger(@"Loaded Kernels\ethash_lbry.cl for Device #" + DeviceIndex + ".");
                String buildOptions = (OpenCLDevice.GetVendor() == "AMD"    ? "-O1 " :
                                       OpenCLDevice.GetVendor() == "NVIDIA" ? "" : // "-cl-nv-opt-level=1 -cl-nv-maxrregcount=256 " :
                                       "")
                                      + " -IKernels -DWORKSIZE=" + mEthashLocalWorkSizeArray[0];
                try
                {
                    mEthashProgram.Build(OpenCLDevice.DeviceList, buildOptions, null, IntPtr.Zero);
                }
                catch (Exception)
                {
                    MainForm.Logger(mEthashProgram.GetBuildLog(computeDevice));
                    throw;
                }
                MainForm.Logger("Built Ethash program for Device #" + DeviceIndex + ".");
                MainForm.Logger("Build options: " + buildOptions);
                mEthashProgramArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }]      = mEthashProgram;
                mEthashDAGKernelArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }]    = mEthashDAGKernel = mEthashProgram.CreateKernel("GenerateDAG");
                mEthashSearchKernelArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }] = mEthashSearchKernel = mEthashProgram.CreateKernel("search");
            }

            try { mProgramArrayMutex.ReleaseMutex(); } catch (Exception) { }
        }
        private void BuildEthashProgram()
        {
            ComputeDevice computeDevice = OpenCLDevice.GetComputeDevice();

            try { mProgramArrayMutex.WaitOne(5000); } catch (Exception) { }

            if (mEthashProgramArray.ContainsKey(new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }))
            {
                mEthashProgram      = mEthashProgramArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }];
                mEthashDAGKernel    = mEthashDAGKernelArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }];
                mEthashSearchKernel = mEthashSearchKernelArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }];
            }
            else
            {
                mEthashProgram = BuildProgram("ethash_lbry", mEthashLocalWorkSizeArray[0], "-O1", "", "");
                mEthashProgramArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }]      = mEthashProgram;
                mEthashDAGKernelArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }]    = mEthashDAGKernel = mEthashProgram.CreateKernel("GenerateDAG");
                mEthashSearchKernelArray[new long[] { DeviceIndex, mEthashLocalWorkSizeArray[0] }] = mEthashSearchKernel = mEthashProgram.CreateKernel("search");
            }

            try { mProgramArrayMutex.ReleaseMutex(); } catch (Exception) { }
        }
        override unsafe protected void MinerThread()
        {
            ComputeProgram       program           = null;
            ComputeBuffer <byte> statesBuffer      = null;
            ComputeBuffer <byte> scratchpadsBuffer = null;

            try {
                Random r          = new Random();
                var    openCLName = OpenCLDevice.GetComputeDevice().Name;
                var    GCN1       = openCLName == "Capeverde" || openCLName == "Hainan" || openCLName == "Oland" || openCLName == "Pitcairn" || openCLName == "Tahiti";

                MarkAsAlive();

                MainForm.Logger("Miner thread for Device #" + DeviceIndex + " started.");
                MainForm.Logger("NiceHash mode is " + (NiceHashMode ? "on" : "off") + ".");

                program = BuildProgram("cryptonight", localWorkSizeA[0], "-O5" + (GCN1 ? " -legacy" : ""), "", "");

                statesBuffer      = OpenCLDevice.RequestComputeByteBuffer(ComputeMemoryFlags.ReadWrite, 200 * globalWorkSizeA[0]);
                scratchpadsBuffer = OpenCLDevice.RequestComputeByteBuffer(ComputeMemoryFlags.ReadWrite, ((long)1 << 21) * globalWorkSizeA[0]);

                using (var searchKernel0 = program.CreateKernel("search"))
                    using (var searchKernel1 = program.CreateKernel("search1"))
                        using (var searchKernel2 = program.CreateKernel("search2"))
                            using (var searchKernel3 = program.CreateKernel("search3"))
                                using (var inputBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadOnly, 76))
                                    using (var outputBuffer = new ComputeBuffer <UInt32>(Context, ComputeMemoryFlags.ReadWrite, outputSize))
                                        using (var terminateBuffer = new ComputeBuffer <Int32>(Context, ComputeMemoryFlags.ReadWrite, 1))
                                            fixed(Int32 *terminatePtr = terminate)
                                            fixed(byte *inputPtr     = input)
                                            fixed(UInt32 * outputPtr = output)
                                            while (!Stopped)
                                            {
                                                MarkAsAlive();
                                                MemoryUsage =
                                                    200 * globalWorkSizeA[0]
                                                    + ((long)1 << 21) * globalWorkSizeA[0]
                                                    + 76 + outputSize + 1;

                                                try {
                                                    searchKernel0.SetMemoryArgument(0, inputBuffer);
                                                    searchKernel0.SetMemoryArgument(1, scratchpadsBuffer);
                                                    searchKernel0.SetMemoryArgument(2, statesBuffer);

                                                    searchKernel1.SetMemoryArgument(0, scratchpadsBuffer);
                                                    searchKernel1.SetMemoryArgument(1, statesBuffer);
                                                    searchKernel1.SetMemoryArgument(2, terminateBuffer);

                                                    searchKernel2.SetMemoryArgument(0, scratchpadsBuffer);
                                                    searchKernel2.SetMemoryArgument(1, statesBuffer);

                                                    searchKernel3.SetMemoryArgument(0, statesBuffer);
                                                    searchKernel3.SetMemoryArgument(1, outputBuffer);

                                                    // 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)
                                                    {
                                                        throw new TimeoutException("Stratum server failed to send a new job.");
                                                    }

                                                    System.Diagnostics.Stopwatch consoleUpdateStopwatch = new System.Diagnostics.Stopwatch();
                                                    CryptoNightStratum.Work      work;
                                                    CryptoNightStratum.Job       job;

                                                    while (!Stopped && (work = Stratum.GetWork()) != null && (job = work.GetJob()) != null)
                                                    {
                                                        MarkAsAlive();

                                                        Array.Copy(Utilities.StringToByteArray(job.Blob), input, 76);
                                                        byte   localExtranonce = (byte)work.LocalExtranonce;
                                                        byte[] targetByteArray = Utilities.StringToByteArray(job.Target);
                                                        UInt32 startNonce;
                                                        if (NiceHashMode)
                                                        {
                                                            startNonce = ((UInt32)input[42] << (8 * 3)) | ((UInt32)localExtranonce << (8 * 2)) | (UInt32)(r.Next(0, int.MaxValue) & (0x0000ffffu));
                                                        }
                                                        else
                                                        {
                                                            startNonce = ((UInt32)localExtranonce << (8 * 3)) | (UInt32)(r.Next(0, int.MaxValue) & (0x00ffffffu));
                                                        }
                                                        UInt32 target = ((UInt32)targetByteArray[0] << 0)
                                                                        | ((UInt32)targetByteArray[1] << 8)
                                                                        | ((UInt32)targetByteArray[2] << 16)
                                                                        | ((UInt32)targetByteArray[3] << 24);
                                                        searchKernel3.SetValueArgument <UInt32>(2, target);

                                                        Queue.Write <byte>(inputBuffer, true, 0, 76, (IntPtr)inputPtr, null);

                                                        consoleUpdateStopwatch.Start();

                                                        while (!Stopped && Stratum.GetJob() != null && Stratum.GetJob().Equals(job))
                                                        {
                                                            MarkAsAlive();

                                                            globalWorkOffsetA[0] = globalWorkOffsetB[0] = startNonce;

                                                            // Get a new local extranonce if necessary.
                                                            if (NiceHashMode)
                                                            {
                                                                if ((startNonce & 0xffff) + (UInt32)globalWorkSizeA[0] >= 0x10000)
                                                                {
                                                                    break;
                                                                }
                                                            }
                                                            else
                                                            {
                                                                if ((startNonce & 0xffffff) + (UInt32)globalWorkSizeA[0] >= 0x1000000)
                                                                {
                                                                    break;
                                                                }
                                                            }

                                                            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
                                                            sw.Start();
                                                            output[255] = 0; // output[255] is used as an atomic counter.
                                                            Queue.Write <UInt32>(outputBuffer, true, 0, outputSize, (IntPtr)outputPtr, null);
                                                            terminate[0] = 0;
                                                            Queue.Write <Int32>(terminateBuffer, true, 0, 1, (IntPtr)terminatePtr, null);
                                                            Queue.Execute(searchKernel0, globalWorkOffsetA, globalWorkSizeA, localWorkSizeA, null);
                                                            Queue.Finish();
                                                            if (Stopped)
                                                            {
                                                                break;
                                                            }
                                                            Queue.Execute(searchKernel1, globalWorkOffsetB, globalWorkSizeB, localWorkSizeB, null);
                                                            Queue.Finish();
                                                            if (Stopped)
                                                            {
                                                                break;
                                                            }
                                                            Queue.Execute(searchKernel2, globalWorkOffsetA, globalWorkSizeA, localWorkSizeA, null);
                                                            Queue.Finish();
                                                            if (Stopped)
                                                            {
                                                                break;
                                                            }
                                                            Queue.Execute(searchKernel3, globalWorkOffsetB, globalWorkSizeB, localWorkSizeB, null);
                                                            Queue.Finish(); // Run the above statement before leaving the current local scope.
                                                            if (Stopped)
                                                            {
                                                                break;
                                                            }

                                                            Queue.Read <UInt32>(outputBuffer, true, 0, outputSize, (IntPtr)outputPtr, null);
                                                            if (Stratum.GetJob() != null && Stratum.GetJob().Equals(job))
                                                            {
                                                                for (int i = 0; i < output[255]; ++i)
                                                                {
                                                                    String result = "";
                                                                    for (int j = 0; j < 8; ++j)
                                                                    {
                                                                        UInt32 word = output[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));
                                                                    }
                                                                    Stratum.Submit(Device, job, output[i], result);
                                                                }
                                                            }
                                                            startNonce += (UInt32)globalWorkSizeA[0];

                                                            sw.Stop();
                                                            Speed = ((double)globalWorkSizeA[0]) / sw.Elapsed.TotalSeconds;
                                                            Device.TotalHashesPrimaryAlgorithm += (double)globalWorkSizeA[0];
                                                            if (consoleUpdateStopwatch.ElapsedMilliseconds >= 10 * 1000)
                                                            {
                                                                MainForm.Logger("Device #" + DeviceIndex + " (CryptoNight): " + String.Format("{0:N2} h/s", Speed));
                                                                consoleUpdateStopwatch.Restart();
                                                            }
                                                        }
                                                    }
                                                } catch (Exception ex) {
                                                    if (statesBuffer != null)
                                                    {
                                                        OpenCLDevice.ReleaseComputeByteBuffer(statesBuffer); statesBuffer = null;
                                                    }
                                                    if (scratchpadsBuffer != null)
                                                    {
                                                        OpenCLDevice.ReleaseComputeByteBuffer(scratchpadsBuffer); scratchpadsBuffer = null;
                                                    }
                                                    MainForm.Logger("Exception in miner thread: " + ex.Message + ex.StackTrace);
                                                    if (UnrecoverableException.IsUnrecoverableException(ex))
                                                    {
                                                        this.UnrecoverableException = new UnrecoverableException(ex, Device);
                                                        Stop();
                                                    }
                                                }

                                                Speed = 0;

                                                if (!Stopped)
                                                {
                                                    MainForm.Logger("Restarting miner thread...");
                                                    System.Threading.Thread.Sleep(Parameters.WaitTimeForRestartingMinerThreadInMilliseconds);
                                                }
                                            }
            } 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;
                }
                if (statesBuffer != null)
                {
                    OpenCLDevice.ReleaseComputeByteBuffer(statesBuffer); statesBuffer = null;
                }
                if (scratchpadsBuffer != null)
                {
                    OpenCLDevice.ReleaseComputeByteBuffer(scratchpadsBuffer); scratchpadsBuffer = null;
                }
            }
        }
Beispiel #7
0
        public void Start(EthashStratum aEthashStratum, PascalStratum aPascalStratum, int aEthashIntensity, int aPascalIterations)
        {
            mEthashStratum = aEthashStratum;
            mEthashLocalWorkSizeArray[0]  = 256;
            mEthashGlobalWorkSizeArray[0] = aEthashIntensity * mEthashLocalWorkSizeArray[0] * OpenCLDevice.GetComputeDevice().MaxComputeUnits;

            mPascalStratum = aPascalStratum;
            mPascalRatio   = (UInt32)aPascalIterations;

            base.Start();
        }
Beispiel #8
0
        override unsafe protected void MinerThread()
        {
            ComputeProgram program = null;

            try {
                ComputeDevice computeDevice = OpenCLDevice.GetComputeDevice();
                Random        r             = new Random();

                MarkAsAlive();

                //MainForm.Logger("Miner thread for Device #" + DeviceIndex + " started.");

                program = BuildProgram(
                    "lbry",
                    mLbryLocalWorkSizeArray[0],
                    "-O1 -DITERATIONS=" + mIterations,
                    "-DITERATIONS=" + mIterations,
                    "-DITERATIONS=" + mIterations);

                using (var mLbryInputBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadOnly, 112))
                    using (var mLbryOutputBuffer = new ComputeBuffer <UInt32>(Context, ComputeMemoryFlags.ReadWrite, lbryOutputSize))
                        using (var mLbrySearchKernel = program.CreateKernel("search_combined"))
                            fixed(long *lbryGlobalWorkOffsetArrayPtr = mLbryGlobalWorkOffsetArray)
                            fixed(long *lbryGlobalWorkSizeArrayPtr = mLbryGlobalWorkSizeArray)
                            fixed(long *lbryLocalWorkSizeArrayPtr  = mLbryLocalWorkSizeArray)
                            fixed(byte *lbryInputPtr     = mLbryInput)
                            fixed(UInt32 * lbryOutputPtr = mLbryOutput)
                            while (!Stopped)
                            {
                                MarkAsAlive();

                                try
                                {
                                    mLbrySearchKernel.SetMemoryArgument(0, mLbryInputBuffer);
                                    mLbrySearchKernel.SetMemoryArgument(1, mLbryOutputBuffer);

                                    while (!Stopped)
                                    {
                                        MarkAsAlive();

                                        mLbryInput = new byte[112];
                                        UInt32 lbryStartNonce = (UInt32)(r.Next(0, int.MaxValue));
                                        UInt64 lbryTarget     = (UInt64)((double)0xffff0000UL / (256 / 256));
                                        mLbrySearchKernel.SetValueArgument <UInt64>(3, lbryTarget);
                                        Queue.Write <byte>(mLbryInputBuffer, true, 0, 112, (IntPtr)lbryInputPtr, null);

                                        while (!Stopped)
                                        {
                                            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
                                            sw.Start();

                                            MarkAsAlive();

                                            mLbrySearchKernel.SetValueArgument <UInt32>(2, lbryStartNonce);

                                            // Get a new local extranonce if necessary.
                                            if (0xffffffffu - lbryStartNonce < (UInt32)mLbryGlobalWorkSizeArray[0] * mIterations)
                                            {
                                                break;
                                            }

                                            mLbryOutput[255] = 0; // mLbryOutput[255] is used as an atomic counter.
                                            Queue.Write <UInt32>(mLbryOutputBuffer, true, 0, lbryOutputSize, (IntPtr)lbryOutputPtr, null);
                                            Queue.Execute(mLbrySearchKernel, mLbryGlobalWorkOffsetArray, mLbryGlobalWorkSizeArray, mLbryLocalWorkSizeArray, null);
                                            Queue.Read <UInt32>(mLbryOutputBuffer, true, 0, lbryOutputSize, (IntPtr)lbryOutputPtr, null);
                                            lbryStartNonce += (UInt32)mLbryGlobalWorkSizeArray[0] * (uint)mIterations;
                                        }
                                    }
                                } catch (Exception ex) {
                                    MainForm.Logger("Exception in dummy miner thread: " + ex.Message + ex.StackTrace);
                                    MainForm.Logger("Restarting dummy miner thread...");
                                }
                            }
            } 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;
            }
        }
Beispiel #9
0
        public void Start(EthashStratum aEthashStratum, int aEthashIntensity, int aEthashLocalWorkSize, LbryStratum aLbryStratum, int aLbryIntensity, int aLbryLocalWorkSize)
        {
            mEthashStratum = aEthashStratum;
            mEthashLocalWorkSizeArray[0]  = aEthashLocalWorkSize;
            mEthashGlobalWorkSizeArray[0] = aEthashIntensity * mEthashLocalWorkSizeArray[0] * OpenCLDevice.GetComputeDevice().MaxComputeUnits;

            mLbryStratum = aLbryStratum;

            base.Start();
        }
Beispiel #10
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_pascal", mEthashLocalWorkSizeArray[0], "-O1", "", "");

                MemoryUsage  = 256;
                MemoryUsage += 32;
                MemoryUsage += sPascalInputSize;
                MemoryUsage += sPascalOutputSize;
                MemoryUsage += sPascalMidstateSize;

                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))
                                using (var pascalInputBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadOnly, sPascalInputSize))
                                    using (var pascalOutputBuffer = new ComputeBuffer <UInt32>(Context, ComputeMemoryFlags.ReadWrite, sPascalOutputSize))
                                        using (var pascalMidstateBuffer = new ComputeBuffer <byte>(Context, ComputeMemoryFlags.ReadOnly, sPascalMidstateSize))
                                            fixed(UInt32 *ethashOutputPtr = ethashOutput)
                                            fixed(byte *ethashHeaderhashPtr = ethashHeaderhash)
                                            fixed(byte *pascalMidstatePtr   = mPascalMidstate)
                                            fixed(byte *pascalInputPtr      = mPascalInput)
                                            fixed(UInt32 * pascalOutputPtr  = mPascalOutput)
                                            while (!Stopped)
                                            {
                                                ComputeBuffer <byte> ethashDAGBuffer = null;

                                                MarkAsAlive();

                                                try {
                                                    int  ethashEpoch   = -1;
                                                    long ethashDAGSize = 0;

                                                    searchKernel.SetMemoryArgument(7 + 0, pascalInputBuffer);
                                                    searchKernel.SetMemoryArgument(7 + 1, pascalOutputBuffer);
                                                    searchKernel.SetMemoryArgument(7 + 4, pascalMidstateBuffer);
                                                    searchKernel.SetValueArgument <UInt32>(7 + 5, mPascalRatio);

                                                    // Wait for the first job to arrive.
                                                    int elapsedTime = 0;
                                                    while ((PrimaryStratum == null || PrimaryStratum.GetJob() == null || SecondaryStratum == null || SecondaryStratum.GetJob() == null) && elapsedTime < Parameters.TimeoutForFirstJobInMilliseconds && !Stopped)
                                                    {
                                                        Thread.Sleep(100);
                                                        elapsedTime += 100;
                                                    }
                                                    if (PrimaryStratum == null || PrimaryStratum.GetJob() == null || SecondaryStratum == null || SecondaryStratum.GetJob() == null)
                                                    {
                                                        throw new TimeoutException("Stratum server failed to send a new job.");
                                                    }

                                                    System.Diagnostics.Stopwatch consoleUpdateStopwatch = new System.Diagnostics.Stopwatch();
                                                    EthashStratum.Work           ethashWork;
                                                    EthashStratum.Job            ethashJob;
                                                    PascalStratum.Work           pascalWork;
                                                    PascalStratum.Job            pascalJob;

                                                    while (!Stopped &&
                                                           (ethashWork = PrimaryStratum.GetWork()) != null && (ethashJob = ethashWork.GetJob()) != null &&
                                                           (pascalWork = SecondaryStratum.GetWork()) != null && (pascalJob = pascalWork.Job) != null)
                                                    {
                                                        MarkAsAlive();

                                                        String ethashPoolExtranonce      = PrimaryStratum.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 = PrimaryStratum.Difficulty;
                                                        Buffer.BlockCopy(Utilities.StringToByteArray(ethashWork.GetJob().Headerhash), 0, ethashHeaderhash, 0, 32);
                                                        Queue.Write <byte>(ethashHeaderBuffer, true, 0, 32, (IntPtr)ethashHeaderhashPtr, null);

                                                        Array.Copy(pascalWork.Blob, mPascalInput, sPascalInputSize);
                                                        CalculatePascalMidState();
                                                        Queue.Write <byte>(pascalMidstateBuffer, true, 0, sPascalMidstateSize, (IntPtr)pascalMidstatePtr, null);
                                                        UInt32 pascalStartNonce = (UInt32)(r.Next(0, int.MaxValue));
                                                        UInt64 PascalTarget     = (UInt64)((double)0xffff0000UL / SecondaryStratum.Difficulty);
                                                        searchKernel.SetValueArgument <UInt64>(7 + 3, PascalTarget);
                                                        Queue.Write <byte>(pascalInputBuffer, true, 0, sPascalInputSize, (IntPtr)pascalInputPtr, 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);
                                                            MemoryUsage += DAGCacheBuffer.Size;

                                                            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    += 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 || PrimaryStratum.GetJob() == null || !PrimaryStratum.GetJob().ID.Equals(ethashJobID))
                                                                {
                                                                    break;
                                                                }
                                                            }
                                                            DAGCacheBuffer.Dispose();
                                                            MemoryUsage -= DAGCacheBuffer.Size;
                                                            if (Stopped || PrimaryStratum.GetJob() == null || !PrimaryStratum.GetJob().ID.Equals(ethashJobID))
                                                            {
                                                                break;
                                                            }
                                                            sw.Stop();
                                                            MainForm.Logger("Generated DAG for Epoch #" + ethashEpoch + " (" + (long)sw.Elapsed.TotalMilliseconds + "ms).");
                                                        }

                                                        consoleUpdateStopwatch.Start();

                                                        while (!Stopped && PrimaryStratum.GetJob().ID.Equals(ethashJobID) && PrimaryStratum.PoolExtranonce.Equals(ethashPoolExtranonce) && SecondaryStratum.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);
                                                            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

                                                            searchKernel.SetValueArgument <UInt32>(7 + 2, pascalStartNonce);

                                                            ethashOutput[255] = 0; // ethashOutput[255] is used as an atomic counter.
                                                            Queue.Write <UInt32>(ethashOutputBuffer, true, 0, 256, (IntPtr)ethashOutputPtr, null);
                                                            mEthashGlobalWorkOffsetArray[0] = 0;
                                                            mPascalOutput[255] = 0; // mPascalOutput[255] is used as an atomic counter.
                                                            Queue.Write <UInt32>(pascalOutputBuffer, true, 0, sPascalOutputSize, (IntPtr)pascalOutputPtr, null);
                                                            Queue.Execute(searchKernel, mEthashGlobalWorkOffsetArray, mEthashGlobalWorkSizeArray, mEthashLocalWorkSizeArray, null);

                                                            Queue.Read <UInt32>(ethashOutputBuffer, true, 0, 256, (IntPtr)ethashOutputPtr, null);
                                                            if (PrimaryStratum.GetJob() != null && PrimaryStratum.GetJob().ID.Equals(ethashJobID))
                                                            {
                                                                for (int i = 0; i < ethashOutput[255]; ++i)
                                                                {
                                                                    PrimaryStratum.Submit(Device, ethashWork.GetJob(), ethashStartNonce + (UInt64)ethashOutput[i]);
                                                                }
                                                            }
                                                            ethashStartNonce += (UInt64)mEthashGlobalWorkSizeArray[0] * 3 / 4;

                                                            Queue.Read <UInt32>(pascalOutputBuffer, true, 0, sPascalOutputSize, (IntPtr)pascalOutputPtr, null);
                                                            if (SecondaryStratum.GetJob() != null && SecondaryStratum.GetJob().Equals(pascalJob))
                                                            {
                                                                for (int i = 0; i < mPascalOutput[255]; ++i)
                                                                {
                                                                    SecondaryStratum.Submit(Device, pascalWork, mPascalOutput[i]);
                                                                }
                                                            }
                                                            pascalStartNonce += (UInt32)mEthashGlobalWorkSizeArray[0] * mPascalRatio;

                                                            sw.Stop();
                                                            Speed = ((double)mEthashGlobalWorkSizeArray[0]) / sw.Elapsed.TotalSeconds * 0.75;
                                                            Device.TotalHashesPrimaryAlgorithm   += (double)mEthashGlobalWorkSizeArray[0] * 0.75;
                                                            SpeedSecondaryAlgorithm               = ((double)mEthashGlobalWorkSizeArray[0]) / sw.Elapsed.TotalSeconds * mPascalRatio;
                                                            Device.TotalHashesSecondaryAlgorithm += (double)mEthashGlobalWorkSizeArray[0] * 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)", SpeedSecondaryAlgorithm / (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;
            }
        }
Beispiel #11
0
        override unsafe protected void MinerThread()
        {
            Random        r             = new Random();
            ComputeDevice computeDevice = OpenCLDevice.GetComputeDevice();

            MarkAsAlive();

            MainForm.Logger("Miner thread for Device #" + DeviceIndex + " started.");
            MainForm.Logger("NiceHash mode is " + (NiceHashMode ? "on" : "off") + ".");

            ComputeProgram program;

            try { mProgramArrayMutex.WaitOne(5000); } catch (Exception) { }
            if (mProgramArray.ContainsKey(new ProgramArrayIndex(DeviceIndex, localWorkSizeA[0])))
            {
                program       = mProgramArray[new ProgramArrayIndex(DeviceIndex, localWorkSizeA[0])];
                searchKernel0 = mSearchKernel0Array[new ProgramArrayIndex(DeviceIndex, localWorkSizeA[0])];
                searchKernel1 = mSearchKernel1Array[new ProgramArrayIndex(DeviceIndex, localWorkSizeA[0])];
                searchKernel2 = mSearchKernel2Array[new ProgramArrayIndex(DeviceIndex, localWorkSizeA[0])];
                searchKernel3 = mSearchKernel3Array[new ProgramArrayIndex(DeviceIndex, localWorkSizeA[0])];
            }
            else
            {
                try
                {
                    if (localWorkSizeA[0] != 8)
                    {
                        throw new Exception("No suitable binary file was found.");
                    }
                    string fileName = @"BinaryKernels\" + computeDevice.Name + "_cryptonight.bin";
                    byte[] binary   = System.IO.File.ReadAllBytes(fileName);
                    program = new ComputeProgram(Context, new List <byte[]>()
                    {
                        binary
                    }, new List <ComputeDevice>()
                    {
                        computeDevice
                    });
                    MainForm.Logger("Loaded " + fileName + " for Device #" + DeviceIndex + ".");
                }
                catch (Exception)
                {
                    String source = System.IO.File.ReadAllText(@"Kernels\cryptonight.cl");
                    program = new ComputeProgram(Context, source);
                    MainForm.Logger(@"Loaded Kernels\cryptonight.cl for Device #" + DeviceIndex + ".");
                }
                String buildOptions = (OpenCLDevice.GetVendor() == "AMD"    ? "-O5" : //"-O1 " :
                                       OpenCLDevice.GetVendor() == "NVIDIA" ? "" :    //"-cl-nv-opt-level=1 -cl-nv-maxrregcount=256 " :
                                       "")
                                      + " -IKernels -DWORKSIZE=" + localWorkSizeA[0];
                try
                {
                    program.Build(OpenCLDevice.DeviceList, buildOptions, null, IntPtr.Zero);
                }
                catch (Exception)
                {
                    MainForm.Logger(program.GetBuildLog(computeDevice));
                    throw;
                }
                MainForm.Logger("Built CryptoNight program for Device #" + DeviceIndex + ".");
                MainForm.Logger("Build options: " + buildOptions);
                mProgramArray[new ProgramArrayIndex(DeviceIndex, localWorkSizeA[0])]       = program;
                mSearchKernel0Array[new ProgramArrayIndex(DeviceIndex, localWorkSizeA[0])] = searchKernel0 = program.CreateKernel("search");
                mSearchKernel1Array[new ProgramArrayIndex(DeviceIndex, localWorkSizeA[0])] = searchKernel1 = program.CreateKernel("search1");
                mSearchKernel2Array[new ProgramArrayIndex(DeviceIndex, localWorkSizeA[0])] = searchKernel2 = program.CreateKernel("search2");
                mSearchKernel3Array[new ProgramArrayIndex(DeviceIndex, localWorkSizeA[0])] = searchKernel3 = program.CreateKernel("search3");
            }
            try { mProgramArrayMutex.ReleaseMutex(); } catch (Exception) { }

            fixed(long *globalWorkOffsetAPtr = globalWorkOffsetA)
            fixed(long *globalWorkOffsetBPtr = globalWorkOffsetB)
            fixed(long *globalWorkSizeAPtr   = globalWorkSizeA)
            fixed(long *globalWorkSizeBPtr   = globalWorkSizeB)
            fixed(long *localWorkSizeAPtr    = localWorkSizeA)
            fixed(long *localWorkSizeBPtr    = localWorkSizeB)
            fixed(Int32 * terminatePtr       = terminate)
            fixed(byte *inputPtr             = input)
            fixed(UInt32 * outputPtr         = output)
            {
                while (!Stopped)
                {
                    MarkAsAlive();

                    try {
                        searchKernel0.SetMemoryArgument(0, inputBuffer);
                        searchKernel0.SetMemoryArgument(1, scratchpadsBuffer);
                        searchKernel0.SetMemoryArgument(2, statesBuffer);

                        searchKernel1.SetMemoryArgument(0, scratchpadsBuffer);
                        searchKernel1.SetMemoryArgument(1, statesBuffer);
                        searchKernel1.SetMemoryArgument(2, terminateBuffer);

                        searchKernel2.SetMemoryArgument(0, scratchpadsBuffer);
                        searchKernel2.SetMemoryArgument(1, statesBuffer);

                        searchKernel3.SetMemoryArgument(0, statesBuffer);
                        searchKernel3.SetMemoryArgument(1, outputBuffer);

                        // Wait for the first job to arrive.
                        int elapsedTime = 0;
                        while ((mStratum == null || mStratum.GetJob() == null) && elapsedTime < 60000)
                        {
                            Thread.Sleep(100);
                            elapsedTime += 100;
                        }
                        if (mStratum == null || mStratum.GetJob() == null)
                        {
                            throw new TimeoutException("Stratum server failed to send a new job.");
                        }

                        System.Diagnostics.Stopwatch consoleUpdateStopwatch = new System.Diagnostics.Stopwatch();
                        CryptoNightStratum.Work      work;

                        while (!Stopped && (work = mStratum.GetWork()) != null)
                        {
                            MarkAsAlive();

                            var job = work.GetJob();
                            Array.Copy(Utilities.StringToByteArray(job.Blob), input, 76);
                            byte   localExtranonce = (byte)work.LocalExtranonce;
                            byte[] targetByteArray = Utilities.StringToByteArray(job.Target);
                            UInt32 startNonce;
                            if (NiceHashMode)
                            {
                                startNonce = ((UInt32)input[42] << (8 * 3)) | ((UInt32)localExtranonce << (8 * 2)) | (UInt32)(r.Next(0, int.MaxValue) & (0x0000ffffu));
                            }
                            else
                            {
                                startNonce = ((UInt32)localExtranonce << (8 * 3)) | (UInt32)(r.Next(0, int.MaxValue) & (0x00ffffffu));
                            }
                            UInt32 target = ((UInt32)targetByteArray[0] << 0)
                                            | ((UInt32)targetByteArray[1] << 8)
                                            | ((UInt32)targetByteArray[2] << 16)
                                            | ((UInt32)targetByteArray[3] << 24);
                            searchKernel3.SetValueArgument <UInt32>(2, target);

                            Queue.Write <byte>(inputBuffer, true, 0, 76, (IntPtr)inputPtr, null);

                            consoleUpdateStopwatch.Start();

                            while (!Stopped && mStratum.GetJob().Equals(job))
                            {
                                MarkAsAlive();

                                globalWorkOffsetA[0] = globalWorkOffsetB[0] = startNonce;

                                // Get a new local extranonce if necessary.
                                if (NiceHashMode)
                                {
                                    if ((startNonce & 0xffff) + (UInt32)globalWorkSizeA[0] >= 0x10000)
                                    {
                                        break;
                                    }
                                }
                                else
                                {
                                    if ((startNonce & 0xffffff) + (UInt32)globalWorkSizeA[0] >= 0x1000000)
                                    {
                                        break;
                                    }
                                }

                                System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
                                sw.Start();
                                output[255] = 0; // output[255] is used as an atomic counter.
                                Queue.Write <UInt32>(outputBuffer, true, 0, outputSize, (IntPtr)outputPtr, null);
                                terminate[0] = 0;
                                Queue.Write <Int32>(terminateBuffer, true, 0, 1, (IntPtr)terminatePtr, null);
                                Queue.Execute(searchKernel0, globalWorkOffsetA, globalWorkSizeA, localWorkSizeA, null);
                                Queue.Finish();
                                if (Stopped)
                                {
                                    break;
                                }
                                Queue.Execute(searchKernel1, globalWorkOffsetB, globalWorkSizeB, localWorkSizeB, null);
                                Queue.Finish();
                                if (Stopped)
                                {
                                    break;
                                }
                                Queue.Execute(searchKernel2, globalWorkOffsetA, globalWorkSizeA, localWorkSizeA, null);
                                Queue.Finish();
                                if (Stopped)
                                {
                                    break;
                                }
                                Queue.Execute(searchKernel3, globalWorkOffsetB, globalWorkSizeB, localWorkSizeB, null);
                                Queue.Finish(); // Run the above statement before leaving the current local scope.
                                if (Stopped)
                                {
                                    break;
                                }

                                Queue.Read <UInt32>(outputBuffer, true, 0, outputSize, (IntPtr)outputPtr, null);
                                if (mStratum.GetJob().Equals(job))
                                {
                                    for (int i = 0; i < output[255]; ++i)
                                    {
                                        String result = "";
                                        for (int j = 0; j < 8; ++j)
                                        {
                                            UInt32 word = output[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));
                                        }
                                        mStratum.Submit(GatelessGateDevice, job, output[i], result);
                                    }
                                }
                                startNonce += (UInt32)globalWorkSizeA[0];

                                sw.Stop();
                                Speed = ((double)globalWorkSizeA[0]) / sw.Elapsed.TotalSeconds;
                                if (consoleUpdateStopwatch.ElapsedMilliseconds >= 10 * 1000)
                                {
                                    MainForm.Logger("Device #" + DeviceIndex + " (CryptoNight): " + String.Format("{0:N2} h/s", Speed));
                                    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();
        }