//+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| ComputeDll.mqh | //| AnimateDread | //| https://www.mql5.com | //| CComputeDll + the WarriorCPU.dll #import block it wraps - the | //| multithreaded-CPU compute tier used when OpenCL is unavailable. | //| Self-contained - nothing outside this class touches CPU_* import | //| functions directly. | //| Formerly NeuronDirectML.mqh / CDirectMLMy: the D3D12/DirectML GPU | //| tier (WarriorDML.dll) it also used to front was removed entirely | //| (operator directive 2026-08-23) - three backends left: OpenCL, | //| this CPU DLL, pure MQL5. See project_solid_campaign_plan S1.5. | //+------------------------------------------------------------------+ //| CPU thread-pool fallback tier - used when OpenCL is unavailable | //| (e.g. a VM with no GPU passthrough). Full double precision, work | //| spread across a configurable pool of worker threads instead of a | //| device. Backed by DirectML\WarriorCPU.dll (build it with | //| DirectML\build_cpu.bat). | //+------------------------------------------------------------------+ // Every function below (besides CPU_Init/CPU_GetHardwareConcurrency) takes `ctx`, the opaque // per-instance handle CPU_Init() returns - see DirectML\WarriorCPU.h's comment for why: the DLL // keeps no global state of its own, so each CComputeDll instance owns an independent thread pool // and the DLL can be loaded/used by any number of instances or threads in parallel with zero // cross-talk between them. #import "WarriorCPU.dll" long CPU_Init(int threads); int CPU_GetLastError(long ctx); int CPU_GetThreadCount(long ctx); int CPU_GetHardwareConcurrency(); void CPU_Shutdown(long ctx); int CPU_BufferCreate(long ctx, int elementCount); int CPU_BufferWrite(long ctx, int handle, const double &data[], int count); int CPU_BufferRead(long ctx, int handle, double &data[], int count); void CPU_BufferFree(long ctx, int handle); int CPU_FeedForward(long ctx, int wHandle, int iHandle, int oHandle, int inputs, int activation); int CPU_CalcOutputGradient(long ctx, int tHandle, int oHandle, int igHandle, int activation, int count); int CPU_CalcHiddenGradient(long ctx, int wHandle, int gHandle, int oHandle, int igHandle, int outputs, int activation, int count); int CPU_UpdateWeightsMomentum(long ctx, int wHandle, int gHandle, int iHandle, int dwHandle, int inputs, double learningRate, double momentumRate, int neurons, int optimizer); int CPU_UpdateWeightsAdam(long ctx, int wHandle, int gHandle, int iHandle, int mHandle, int vHandle, int inputs, double lt, double b1v, double b2v, int neurons); int CPU_FeedForwardConv(long ctx, int wHandle, int iHandle, int oHandle, int inputs, int step, int windowIn, int windowOut, int activation, int positions); int CPU_CalcHiddenGradientConv(long ctx, int wHandle, int gHandle, int oHandle, int igHandle, int outputs, int step, int windowIn, int windowOut, int activation, int inputCount); int CPU_UpdateWeightsConvMomentum(long ctx, int wHandle, int gHandle, int iHandle, int dwHandle, int inputs, double learningRate, double momentumRate, int windowIn, int windowOut, int step, int optimizer); int CPU_UpdateWeightsConvAdam(long ctx, int wHandle, int gHandle, int iHandle, int mHandle, int vHandle, int inputs, double lt, double b1v, double b2v, int windowIn, int windowOut, int step); int CPU_LSTMGates(long ctx, int wHandle, int hiddenPrevHandle, int inputsHandle, int concatenatedHandle, int hiddenSize, int inputSize); int CPU_LSTMState(long ctx, int concatenatedHandle, int memoryHandle, int hiddenPrevHandle, int hiddenCacheHandle, int outputHandle, int hiddenSize); int CPU_LSTMGateGradient(long ctx, int gradientHandle, int memoryHandle, int concatenatedHandle, int concatenatedGradientHandle, int hiddenSize); int CPU_LSTMWeightsGradient(long ctx, int concatenatedGradientHandle, int hiddenCacheHandle, int inputsHandle, int weightsGradientHandle, int hiddenSize, int inputSize); int CPU_LSTMInputsGradient(long ctx, int concatenatedGradientHandle, int wHandle, int inputsGradientHandle, int hiddenSize, int inputSize); int CPU_LSTMSeqForward(long ctx, int wHandle, int inputsHandle, int cacheGatesHandle, int cacheCellHandle, int cacheHiddenHandle, int outputHandle, int hiddenSize, int stepInputs, int steps); int CPU_LSTMSeqBackward(long ctx, int wHandle, int inputsHandle, int cacheGatesHandle, int cacheCellHandle, int cacheHiddenHandle, int outGradientHandle, int weightsGradientHandle, int inputsGradientHandle, int hiddenSize, int stepInputs, int steps); int CPU_LSTMUpdateWeightsAdam(long ctx, int wHandle, int weightsGradientHandle, int mHandle, int vHandle, double l, double b1v, double b2v, int total); int CPU_LSTMUpdateWeightsMomentum(long ctx, int wHandle, int weightsGradientHandle, int dwHandle, double learningRate, double momentumRate, int total, int optimizer); int CPU_FeedForwardProof(long ctx, int iHandle, int oHandle, int inputs, int window, int step, int outputs); int CPU_CalcInputGradientProof(long ctx, int iHandle, int gHandle, int oHandle, int igHandle, int outputs, int window, int step, int inputs); int CPU_AccumulateWeightGrad(long ctx, int accHandle, int gHandle, int iHandle, int inputs, int neurons); int CPU_AccumulateWeightGradConv(long ctx, int accHandle, int gHandle, int iHandle, int inputs, int windowIn, int windowOut, int step); int CPU_AccumulateBufferInto(long ctx, int dstHandle, int srcHandle, int count); int CPU_ApplyAccumAdam(long ctx, int wHandle, int accHandle, int mHandle, int vHandle, int total, double scale, double lt, double b1v, double b2v); int CPU_ApplyAccumMomentum(long ctx, int wHandle, int accHandle, int dwHandle, int total, double scale, double learningRate, double momentumRate); int CPU_BatchNormForward(long ctx, int iHandle, int oHandle, int optHandle, double w, int frozen, int count); int CPU_BatchNormHiddenGrad(long ctx, int gHandle, int prevOHandle, int prevGHandle, int optHandle, int activation, int count); int CPU_BatchNormAccumGammaBeta(long ctx, int gHandle, int optHandle, int accHandle, int count); int CPU_BatchNormApplyGammaBeta(long ctx, int optHandle, int accHandle, double scale, double lt, double b1v, double b2v, double lr, double momentumRate, int optimizer, int count); #import //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ enum ENUM_COMPUTE_TIER { COMPUTE_TIER_NONE = 0, COMPUTE_TIER_CPU = 2 // multithreaded fallback - WarriorCPU.dll }; //+------------------------------------------------------------------+ //| CPU DLL fallback wrapper. Used when OpenCL is unavailable (no HW | //| accel, e.g. a VM), so callers just get "multithreaded acceleration,| //| or NULL" without caring about the backend's internals. | //+------------------------------------------------------------------+ class CComputeDll { private: ENUM_COMPUTE_TIER m_tier; int m_cpuLoadPercent; // 100 = auto/all cores; 10-90 scales down from the detected count //--- opaque per-instance context handle for the CPU DLL tier (0 when m_tier==NONE). WarriorCPU.dll //--- keeps no global state of its own - each CPU_Init() call heap-allocates an independent context //--- (own thread pool, own buffer table) and this handle is the caller's only reference to it, //--- threaded through every single call below. This is what makes the DLL safe to load/reload and //--- use from any number of CNet instances at once: a fault or a watchdog-killed call against one //--- instance's context can never poison another chart's or another CNet's calls the way a //--- shared/global singleton could. long m_ctx; //--- CPU_Init()'s failure reason, captured immediately since a failed Init() hands back no context //--- to read it from afterward - LastError() falls back to this when m_tier is NONE. int m_initError; public: CComputeDll(void) : m_tier(COMPUTE_TIER_NONE), m_cpuLoadPercent(100), m_ctx(0), m_initError(0) {}; ~CComputeDll(void) { if(m_tier == COMPUTE_TIER_CPU) CPU_Shutdown(m_ctx); } //--- pct <= 0 or >= 100 means "let WarriorCPU.dll pick hardware_concurrency() (all cores)"; //--- 10-90 targets that percentage of the auto-detected core count instead. void SetCpuLoadPercent(int pct) { m_cpuLoadPercent = pct; } ENUM_COMPUTE_TIER Tier(void) { return m_tier; } //--- Which DLL is actually behind this object, for diagnostics. string BackendName(void) { switch(m_tier) { case COMPUTE_TIER_CPU: return "CPU-DLL"; default: return "no-backend"; } } int CpuThreadsUsed(void) { return (m_tier == COMPUTE_TIER_CPU) ? CPU_GetThreadCount(m_ctx) : 0; } bool Initialize(void) { int threads = 0; // 0 = auto (hardware_concurrency, i.e. all cores) if(m_cpuLoadPercent > 0 && m_cpuLoadPercent < 100) { // CPU_GetHardwareConcurrency() is a stateless OS query, independent of any other // instance's pool size - each CNet gets its own CPU_Init() context now, so there is no // shared pool for this to be scaled down by the way there used to be. int detected = CPU_GetHardwareConcurrency(); threads = (int)MathMax(1, MathRound(detected * m_cpuLoadPercent / 100.0)); } long cpuCtx = CPU_Init(threads); if(cpuCtx != 0) { m_ctx = cpuCtx; m_tier = COMPUTE_TIER_CPU; return true; } // CPU-DLL init failed - every layer now falls through to the slow plain-MQL5 CPU path with no // diagnostic trail explaining the resulting behavior/performance change unless this is logged here. m_initError = -1; Print(__FUNCTION__ + ": CPU-DLL init failed (CPU_Init returned no context) - falling back to the plain-MQL5 CPU tier."); m_tier = COMPUTE_TIER_NONE; return false; } int LastError(void) { return (m_tier == COMPUTE_TIER_NONE) ? m_initError : CPU_GetLastError(m_ctx); } int BufferCreate(int count) { return CPU_BufferCreate(m_ctx, count); } bool BufferWrite(int handle, double &data[], int count) { return CPU_BufferWrite(m_ctx, handle, data, count) != 0; } bool BufferRead(int handle, double &data[], int count) { return CPU_BufferRead(m_ctx, handle, data, count) != 0; } void BufferFree(int handle) { CPU_BufferFree(m_ctx, handle); } bool FeedForward(int wHandle, int iHandle, int oHandle, int inputs, int activation) { return CPU_FeedForward(m_ctx, wHandle, iHandle, oHandle, inputs, activation) != 0; } bool CalcOutputGradient(int tHandle, int oHandle, int igHandle, int activation, int count) { return CPU_CalcOutputGradient(m_ctx, tHandle, oHandle, igHandle, activation, count) != 0; } bool CalcHiddenGradient(int wHandle, int gHandle, int oHandle, int igHandle, int outputs, int activation, int count) { return CPU_CalcHiddenGradient(m_ctx, wHandle, gHandle, oHandle, igHandle, outputs, activation, count) != 0; } bool UpdateWeightsMomentum(int wHandle, int gHandle, int iHandle, int dwHandle, int inputs, double learningRate, double momentumRate, int neurons, int optimizer) { return CPU_UpdateWeightsMomentum(m_ctx, wHandle, gHandle, iHandle, dwHandle, inputs, learningRate, momentumRate, neurons, optimizer) != 0; } bool UpdateWeightsAdam(int wHandle, int gHandle, int iHandle, int mHandle, int vHandle, int inputs, double lt, double b1v, double b2v, int neurons) { return CPU_UpdateWeightsAdam(m_ctx, wHandle, gHandle, iHandle, mHandle, vHandle, inputs, lt, b1v, b2v, neurons) != 0; } bool FeedForwardConv(int wHandle, int iHandle, int oHandle, int inputs, int step, int windowIn, int windowOut, int activation, int positions) { return CPU_FeedForwardConv(m_ctx, wHandle, iHandle, oHandle, inputs, step, windowIn, windowOut, activation, positions) != 0; } bool CalcHiddenGradientConv(int wHandle, int gHandle, int oHandle, int igHandle, int outputs, int step, int windowIn, int windowOut, int activation, int inputCount) { return CPU_CalcHiddenGradientConv(m_ctx, wHandle, gHandle, oHandle, igHandle, outputs, step, windowIn, windowOut, activation, inputCount) != 0; } bool UpdateWeightsConvMomentum(int wHandle, int gHandle, int iHandle, int dwHandle, int inputs, double learningRate, double momentumRate, int windowIn, int windowOut, int step, int optimizer) { return CPU_UpdateWeightsConvMomentum(m_ctx, wHandle, gHandle, iHandle, dwHandle, inputs, learningRate, momentumRate, windowIn, windowOut, step, optimizer) != 0; } bool UpdateWeightsConvAdam(int wHandle, int gHandle, int iHandle, int mHandle, int vHandle, int inputs, double lt, double b1v, double b2v, int windowIn, int windowOut, int step) { return CPU_UpdateWeightsConvAdam(m_ctx, wHandle, gHandle, iHandle, mHandle, vHandle, inputs, lt, b1v, b2v, windowIn, windowOut, step) != 0; } //--- Mini-batch gradient accumulation (2026-08-09 audit, F4). Accumulation only - the optimizer step //--- is host-side MQL5, so there is no matching Apply* here; see CNeuronBaseOCL::ApplyAccumulatedGradients. bool AccumulateWeightGrad(int accHandle, int gHandle, int iHandle, int inputs, int neurons) { return CPU_AccumulateWeightGrad(m_ctx, accHandle, gHandle, iHandle, inputs, neurons) != 0; } bool AccumulateWeightGradConv(int accHandle, int gHandle, int iHandle, int inputs, int windowIn, int windowOut, int step) { return CPU_AccumulateWeightGradConv(m_ctx, accHandle, gHandle, iHandle, inputs, windowIn, windowOut, step) != 0; } bool AccumulateBufferInto(int dstHandle, int srcHandle, int count) { return CPU_AccumulateBufferInto(m_ctx, dstHandle, srcHandle, count) != 0; } //--- Mini-batch apply (2026-08-25): the optimizer step on the batch mean, device-side. See //--- CPU_ApplyAccumAdam in WarriorCPU.h - without these the step ran as a per-weight MQL5 loop. bool ApplyAccumAdam(int wHandle, int accHandle, int mHandle, int vHandle, int total, double scale, double lt, double b1v, double b2v) { return CPU_ApplyAccumAdam(m_ctx, wHandle, accHandle, mHandle, vHandle, total, scale, lt, b1v, b2v) != 0; } bool ApplyAccumMomentum(int wHandle, int accHandle, int dwHandle, int total, double scale, double learningRate, double momentumRate) { return CPU_ApplyAccumMomentum(m_ctx, wHandle, accHandle, dwHandle, total, scale, learningRate, momentumRate) != 0; } //--- Batch norm (2026-08-25) - see CPU_BatchNormForward in WarriorCPU.h. These are what let a BN //--- layer run device-side on the DLL tier; the OpenCL kernels remain the device path there. bool BatchNormForward(int iHandle, int oHandle, int optHandle, double w, int frozen, int count) { return CPU_BatchNormForward(m_ctx, iHandle, oHandle, optHandle, w, frozen, count) != 0; } bool BatchNormHiddenGrad(int gHandle, int prevOHandle, int prevGHandle, int optHandle, int activation, int count) { return CPU_BatchNormHiddenGrad(m_ctx, gHandle, prevOHandle, prevGHandle, optHandle, activation, count) != 0; } bool BatchNormAccumGammaBeta(int gHandle, int optHandle, int accHandle, int count) { return CPU_BatchNormAccumGammaBeta(m_ctx, gHandle, optHandle, accHandle, count) != 0; } bool BatchNormApplyGammaBeta(int optHandle, int accHandle, double scale, double lt, double b1v, double b2v, double lr, double momentumRate, int optimizer, int count) { return CPU_BatchNormApplyGammaBeta(m_ctx, optHandle, accHandle, scale, lt, b1v, b2v, lr, momentumRate, optimizer, count) != 0; } //--- Fused unrolled sequence LSTM. These are what a sequence model uses; the per-step LSTMGates/ //--- LSTMState/LSTM*Gradient below remain only for the legacy single-timestep layer. bool LSTMSeqForward(int wHandle, int inputsHandle, int cacheGatesHandle, int cacheCellHandle, int cacheHiddenHandle, int outputHandle, int hiddenSize, int stepInputs, int steps) { return CPU_LSTMSeqForward(m_ctx, wHandle, inputsHandle, cacheGatesHandle, cacheCellHandle, cacheHiddenHandle, outputHandle, hiddenSize, stepInputs, steps) != 0; } bool LSTMSeqBackward(int wHandle, int inputsHandle, int cacheGatesHandle, int cacheCellHandle, int cacheHiddenHandle, int outGradientHandle, int weightsGradientHandle, int inputsGradientHandle, int hiddenSize, int stepInputs, int steps) { return CPU_LSTMSeqBackward(m_ctx, wHandle, inputsHandle, cacheGatesHandle, cacheCellHandle, cacheHiddenHandle, outGradientHandle, weightsGradientHandle, inputsGradientHandle, hiddenSize, stepInputs, steps) != 0; } bool LSTMGates(int wHandle, int hiddenPrevHandle, int inputsHandle, int concatenatedHandle, int hiddenSize, int inputSize) { return CPU_LSTMGates(m_ctx, wHandle, hiddenPrevHandle, inputsHandle, concatenatedHandle, hiddenSize, inputSize) != 0; } bool LSTMState(int concatenatedHandle, int memoryHandle, int hiddenPrevHandle, int hiddenCacheHandle, int outputHandle, int hiddenSize) { return CPU_LSTMState(m_ctx, concatenatedHandle, memoryHandle, hiddenPrevHandle, hiddenCacheHandle, outputHandle, hiddenSize) != 0; } bool LSTMGateGradient(int gradientHandle, int memoryHandle, int concatenatedHandle, int concatenatedGradientHandle, int hiddenSize) { return CPU_LSTMGateGradient(m_ctx, gradientHandle, memoryHandle, concatenatedHandle, concatenatedGradientHandle, hiddenSize) != 0; } bool LSTMWeightsGradient(int concatenatedGradientHandle, int hiddenCacheHandle, int inputsHandle, int weightsGradientHandle, int hiddenSize, int inputSize) { return CPU_LSTMWeightsGradient(m_ctx, concatenatedGradientHandle, hiddenCacheHandle, inputsHandle, weightsGradientHandle, hiddenSize, inputSize) != 0; } bool LSTMInputsGradient(int concatenatedGradientHandle, int wHandle, int inputsGradientHandle, int hiddenSize, int inputSize) { return CPU_LSTMInputsGradient(m_ctx, concatenatedGradientHandle, wHandle, inputsGradientHandle, hiddenSize, inputSize) != 0; } bool LSTMUpdateWeightsAdam(int wHandle, int weightsGradientHandle, int mHandle, int vHandle, double l, double b1v, double b2v, int total) { return CPU_LSTMUpdateWeightsAdam(m_ctx, wHandle, weightsGradientHandle, mHandle, vHandle, l, b1v, b2v, total) != 0; } bool LSTMUpdateWeightsMomentum(int wHandle, int weightsGradientHandle, int dwHandle, double learningRate, double momentumRate, int total, int optimizer) { return CPU_LSTMUpdateWeightsMomentum(m_ctx, wHandle, weightsGradientHandle, dwHandle, learningRate, momentumRate, total, optimizer) != 0; } bool FeedForwardProof(int iHandle, int oHandle, int inputs, int window, int step, int outputs) { return CPU_FeedForwardProof(m_ctx, iHandle, oHandle, inputs, window, step, outputs) != 0; } bool CalcInputGradientProof(int iHandle, int gHandle, int oHandle, int igHandle, int outputs, int window, int step, int inputs) { return CPU_CalcInputGradientProof(m_ctx, iHandle, gHandle, oHandle, igHandle, outputs, window, step, inputs) != 0; } }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+