- BufferDouble: replace hardcoded "DirectML/CPU-DLL" with dynamic backend name and add buffer index/element count to all error prints for easier debugging. - NetPersistence: distinguish missing file from transient lock by probing FileIsExist before logging, eliminating false "sharing violation" warnings when no saved model exists on first run.
218 lines
9.2 KiB
MQL5
218 lines
9.2 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| BufferDouble.mqh |
|
|
//| AnimateDread |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
//| CBufferDouble - the OpenCL/DirectML-backed buffer wrapper every |
|
|
//| *OCL neuron class (AI\Network.mqh) uses for its weights/output/ |
|
|
//| gradient storage. Needs COpenCLMy (AI\Network.mqh) and |
|
|
//| CDirectMLMy (AI\NeuronDirectML.mqh) already declared. Extracted |
|
|
//| verbatim out of AI\Network.mqh (SOLID cleanup) - no logic changes.|
|
|
//+------------------------------------------------------------------+
|
|
#include "NeuronDirectML.mqh"
|
|
class CBufferDouble : public CArrayDouble
|
|
{
|
|
protected:
|
|
COpenCLMy *OpenCL;
|
|
CDirectMLMy *DirectML;
|
|
int m_myIndex;
|
|
//--- OpenCL device buffers are float32 (see AI\Network.cl's fp32 conversion) while this class's
|
|
//--- public CArrayDouble interface - and the DirectML backend's DLL boundary (DML_BufferRead/
|
|
//--- DML_BufferWrite, hardcoded to double[]) - stay double. This scratch array is the narrow/widen
|
|
//--- point: populated from m_data before an OpenCL write, copied back into m_data after an OpenCL
|
|
//--- read. Never touched on the DirectML or CPU-fallback paths.
|
|
float m_data_f[];
|
|
public:
|
|
CBufferDouble(void);
|
|
~CBufferDouble(void);
|
|
//---
|
|
virtual bool BufferInit(uint count, double value);
|
|
virtual bool BufferCreate(COpenCLMy *opencl);
|
|
virtual bool BufferCreate(CDirectMLMy *directml);
|
|
virtual bool BufferFree(void);
|
|
virtual bool BufferRead(void);
|
|
virtual bool BufferWrite(void);
|
|
virtual int GetData(double &values[]);
|
|
virtual int GetData(CArrayDouble *values);
|
|
virtual int GetIndex(void) { return m_myIndex; }
|
|
//---
|
|
virtual int Type(void) const { return defBufferDouble; }
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CBufferDouble::CBufferDouble(void) : m_myIndex(-1)
|
|
{
|
|
OpenCL = NULL;
|
|
DirectML = NULL;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CBufferDouble::~CBufferDouble(void)
|
|
{
|
|
BufferFree();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferDouble::BufferCreate(COpenCLMy *opencl)
|
|
{
|
|
BufferFree();
|
|
//---
|
|
if(CheckPointer(opencl) == POINTER_INVALID)
|
|
return false;
|
|
if(ArrayResize(m_data_f, m_data_total) < 0)
|
|
{
|
|
Print(__FUNCTION__ + ": ArrayResize(m_data_f, " + IntegerToString(m_data_total) + ") failed - allocation failure?");
|
|
return false;
|
|
}
|
|
for(int i = 0; i < m_data_total; i++)
|
|
m_data_f[i] = (float)m_data[i];
|
|
if((m_myIndex = opencl.AddBufferFromArray(m_data_f, 0, m_data_total, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR)) < 0)
|
|
{
|
|
Print(__FUNCTION__ + ": OpenCL AddBufferFromArray failed for " + IntegerToString(m_data_total) + " elements, error " + IntegerToString(GetLastError()) + " (VRAM exhaustion / device lost?)");
|
|
return false;
|
|
}
|
|
OpenCL = opencl;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferDouble::BufferCreate(CDirectMLMy *directml)
|
|
{
|
|
BufferFree();
|
|
//---
|
|
if(CheckPointer(directml) == POINTER_INVALID)
|
|
return false;
|
|
if((m_myIndex = directml.BufferCreate(m_data_total)) < 0)
|
|
{
|
|
Print(__FUNCTION__ + ": " + directml.BackendName() + " BufferCreate failed for " + IntegerToString(m_data_total) + " elements (error " + IntegerToString(directml.LastError()) + ")");
|
|
return false;
|
|
}
|
|
DirectML = directml;
|
|
bool ok = DirectML.BufferWrite(m_myIndex, m_data, m_data_total);
|
|
if(!ok)
|
|
Print(__FUNCTION__ + ": " + directml.BackendName() + " BufferWrite failed for buffer " + IntegerToString(m_myIndex) +
|
|
" on create (" + IntegerToString(m_data_total) + " elements, error " + IntegerToString(directml.LastError()) + ")");
|
|
return ok;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferDouble::BufferFree(void)
|
|
{
|
|
if(CheckPointer(OpenCL) != POINTER_INVALID && m_myIndex >= 0)
|
|
{
|
|
if(!OpenCL.BufferFree(m_myIndex))
|
|
return false;
|
|
m_myIndex = -1;
|
|
OpenCL = NULL;
|
|
return true;
|
|
}
|
|
if(CheckPointer(DirectML) != POINTER_INVALID && m_myIndex >= 0)
|
|
{
|
|
DirectML.BufferFree(m_myIndex);
|
|
m_myIndex = -1;
|
|
DirectML = NULL;
|
|
return true;
|
|
}
|
|
//---
|
|
return false;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferDouble::BufferRead(void)
|
|
{
|
|
if(CheckPointer(OpenCL) != POINTER_INVALID && m_myIndex >= 0)
|
|
{
|
|
if(ArrayResize(m_data_f, m_data_total) < 0)
|
|
{
|
|
Print(__FUNCTION__ + ": ArrayResize(m_data_f, " + IntegerToString(m_data_total) + ") failed - allocation failure?");
|
|
return false;
|
|
}
|
|
if(!OpenCL.BufferRead(m_myIndex, m_data_f, 0, 0, m_data_total))
|
|
{
|
|
Print(__FUNCTION__ + ": OpenCL BufferRead failed for buffer " + IntegerToString(m_myIndex) + ", error " + IntegerToString(GetLastError()));
|
|
return false;
|
|
}
|
|
for(int i = 0; i < m_data_total; i++)
|
|
m_data[i] = (double)m_data_f[i];
|
|
return true;
|
|
}
|
|
if(CheckPointer(DirectML) != POINTER_INVALID && m_myIndex >= 0)
|
|
{
|
|
bool ok = DirectML.BufferRead(m_myIndex, m_data, m_data_total);
|
|
if(!ok)
|
|
Print(__FUNCTION__ + ": " + DirectML.BackendName() + " BufferRead failed for buffer " + IntegerToString(m_myIndex) +
|
|
" (" + IntegerToString(m_data_total) + " elements, error " + IntegerToString(DirectML.LastError()) + ")");
|
|
return ok;
|
|
}
|
|
//---
|
|
return false;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferDouble::BufferWrite(void)
|
|
{
|
|
if(CheckPointer(OpenCL) != POINTER_INVALID && m_myIndex >= 0)
|
|
{
|
|
if(ArrayResize(m_data_f, m_data_total) < 0)
|
|
{
|
|
Print(__FUNCTION__ + ": ArrayResize(m_data_f, " + IntegerToString(m_data_total) + ") failed - allocation failure?");
|
|
return false;
|
|
}
|
|
for(int i = 0; i < m_data_total; i++)
|
|
m_data_f[i] = (float)m_data[i];
|
|
bool ok = OpenCL.BufferWrite(m_myIndex, m_data_f, 0, 0, m_data_total);
|
|
if(!ok)
|
|
Print(__FUNCTION__ + ": OpenCL BufferWrite failed for buffer " + IntegerToString(m_myIndex) + ", error " + IntegerToString(GetLastError()));
|
|
return ok;
|
|
}
|
|
if(CheckPointer(DirectML) != POINTER_INVALID && m_myIndex >= 0)
|
|
{
|
|
bool ok = DirectML.BufferWrite(m_myIndex, m_data, m_data_total);
|
|
if(!ok)
|
|
Print(__FUNCTION__ + ": " + DirectML.BackendName() + " BufferWrite failed for buffer " + IntegerToString(m_myIndex) +
|
|
" (" + IntegerToString(m_data_total) + " elements, error " + IntegerToString(DirectML.LastError()) + ")");
|
|
return ok;
|
|
}
|
|
//---
|
|
return false;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferDouble::BufferInit(uint count, double value)
|
|
{
|
|
if(!Reserve(count))
|
|
return false;
|
|
m_data_total = (int)fmin(ArrayInitialize(m_data, value), count);
|
|
//---
|
|
return m_data_total == count;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int CBufferDouble::GetData(double &values[])
|
|
{
|
|
if(!BufferRead())
|
|
return false;
|
|
return ArrayCopy(values, m_data, 0, 0, m_data_total);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int CBufferDouble::GetData(CArrayDouble *values)
|
|
{
|
|
if(!BufferRead())
|
|
return -1;
|
|
values.Clear();
|
|
if(!values.AddArray(GetPointer(this)))
|
|
return -1;
|
|
return m_data_total;
|
|
}
|