Skip to content

Commit ceeb86b

Browse files
committed
Matlab integration
1 parent 5cf687e commit ceeb86b

14 files changed

+467
-10
lines changed

atgpu/AbstractInterface.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ void AbstractInterface::setHandler(AbstractInterface *obj) {
1010
handler = obj;
1111
}
1212

13+
bool AbstractInterface::isValidHandler() {
14+
return handler != nullptr;
15+
}
16+
1317
AbstractInterface *AbstractInterface::getInstance() {
1418
if( handler== nullptr )
1519
throw string("AbstractInterface: handler not set");

atgpu/AbstractInterface.h

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class AbstractInterface {
2828
// Return handle to singleton class
2929
static AbstractInterface *getInstance();
3030
static void setHandler(AbstractInterface *obj);
31+
static bool isValidHandler();
3132

3233
// Get shape as string
3334
static std::string getShapeStr(std::vector<int64_t>& shape);

atgpu/Lattice.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,8 @@ void Lattice::fillGPUMemory() {
296296

297297
void Lattice::run(uint64_t nbTurn,uint32_t nbParticles,AT_FLOAT *rin,AT_FLOAT *rout,uint32_t nbRef,
298298
uint32_t *refPts,uint32_t nbElemOffset,uint32_t *elemOffsets,
299-
uint32_t *lostAtTurn,uint32_t *lostAtElem,AT_FLOAT *lostAtCoord) {
299+
uint32_t *lostAtTurn,uint32_t *lostAtElem,AT_FLOAT *lostAtCoord,
300+
bool updateRin) {
300301

301302
#ifdef _PROFILE
302303
double t0 = AbstractGPU::get_ticks();
@@ -382,7 +383,7 @@ void Lattice::run(uint64_t nbTurn,uint32_t nbParticles,AT_FLOAT *rin,AT_FLOAT *r
382383

383384
// Get back data
384385
gpu->deviceToHost(lost,gpuLost,lostSize);
385-
gpu->deviceToHost(rin, gpuRin, nbParticles * 6 * sizeof(AT_FLOAT));
386+
if(updateRin) gpu->deviceToHost(rin, gpuRin, nbParticles * 6 * sizeof(AT_FLOAT));
386387
if( routSize ) gpu->deviceToHost(rout,gpuRout,routSize);
387388
if( lostAtElem ) gpu->deviceToHost(lostAtElem,gpuLostAtElem, nbParticles * sizeof(uint32_t));
388389
if( lostAtCoord ) gpu->deviceToHost(lostAtCoord,gpuLostAtCoord, nbParticles * 6 * sizeof(AT_FLOAT));

atgpu/Lattice.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ class Lattice {
2727
void generateGPUKernel();
2828
// Run the simulation
2929
void run(uint64_t nbTurn,uint32_t nbParticles,AT_FLOAT *rin,AT_FLOAT *rout,uint32_t nbRef,uint32_t *refPts,
30-
uint32_t nbElemOffset,uint32_t *elemOffsets,uint32_t *lostAtTurn,uint32_t *lostAtElem,AT_FLOAT *lostAtCoord);
30+
uint32_t nbElemOffset,uint32_t *elemOffsets,uint32_t *lostAtTurn,uint32_t *lostAtElem,AT_FLOAT *lostAtCoord,
31+
bool updateRin);
3132
// Return handle to the GPU context
3233
GPUContext *getGPUContext();
3334
// Get ring length

atgpu/MatlabInterface.cpp

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#include "MatlabInterface.h"
2+
#include "AbstractGPU.h"
3+
4+
using namespace std;
5+
6+
void MatlabInterface::setObject(mxArray *obj) {
7+
elem = obj;
8+
}
9+
10+
mxArray *MatlabInterface::getField(const mxArray *pm, const std::string& name) {
11+
12+
mxArray *field;
13+
if (name[0] == '_') {
14+
// replace leading '_' by trailing '_'
15+
string newName = name.substr(1) + '_';
16+
field = mxGetField(pm,0,newName.c_str());
17+
} else {
18+
field = mxGetField(pm,0,name.c_str());
19+
}
20+
return field;
21+
22+
}
23+
24+
int MatlabInterface::getInt(const std::string& name) {
25+
26+
mxArray *field=getField(elem,name);
27+
if (!field)
28+
throw string("The required attribute " + name + " is missing.");
29+
return (int)mxGetScalar(field);
30+
31+
}
32+
33+
std::string MatlabInterface::getString(const std::string& name) {
34+
35+
mxArray *field=getField(elem,name);
36+
if (!field)
37+
throw string("The required attribute " + name + " is missing.");
38+
39+
const char *valueStr = mxArrayToString(field);
40+
string ret = string(valueStr);
41+
mxFree((void *)valueStr);
42+
return ret;
43+
44+
}
45+
46+
double MatlabInterface::getDouble(const std::string& name) {
47+
48+
mxArray *field=getField(elem,name);
49+
if (!field)
50+
throw string("The required attribute " + name + " is missing.");
51+
return mxGetScalar(field);
52+
53+
}
54+
55+
double *MatlabInterface::getNativeDoubleArray(const std::string& name,std::vector<int64_t>& shape) {
56+
57+
mxArray *field=getField(elem,name);
58+
if (!field)
59+
throw string("The required attribute " + name + " is missing.");
60+
61+
size_t nDim = mxGetNumberOfDimensions(field);
62+
shape.resize(nDim);
63+
for(int i=0;i<nDim;i++)
64+
shape[i] = mxGetDimensions(field)[i];
65+
66+
// Convert 1,x array to single dimension array
67+
if( shape[0]==1 )
68+
shape.erase(shape.begin());
69+
70+
double *ptr = mxGetDoubles(field);
71+
return ptr;
72+
73+
}
74+
75+
float *MatlabInterface::getNativeFloatArray(const std::string& name,std::vector<int64_t>& shape) {
76+
77+
throw string(name + ": float32 array not supported in MATLAB");
78+
79+
}
80+
81+
// --------------------------------------------------------------------------------------------------------------------
82+

atgpu/MatlabInterface.h

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#ifndef AT_GPU_MATLABINTERFACE_H
2+
#define AT_GPU_MATLABINTERFACE_H
3+
#include "AbstractInterface.h"
4+
#include <mex.h>
5+
6+
class MatlabInterface: public AbstractInterface {
7+
8+
public:
9+
10+
std::string getString(const std::string& name) override;
11+
int getInt(const std::string& name) override;
12+
double getDouble(const std::string& name) override;
13+
double *getNativeDoubleArray(const std::string& name,std::vector<int64_t>& shape) override;
14+
float *getNativeFloatArray(const std::string& name,std::vector<int64_t>& shape) override;
15+
16+
void setObject(mxArray *obj);
17+
18+
private:
19+
20+
mxArray *getField(const mxArray *pm, const std::string& name);
21+
mxArray *elem = nullptr;
22+
23+
};
24+
25+
#endif //AT_GPU_MATLABINTERFACE_H

atgpu/PyInterface.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ static PyObject *at_gpupass(PyObject *self, PyObject *args, PyObject *kwargs) {
304304

305305
try {
306306

307-
cout << "Tracking " << num_particles << " particles on " << gpuLattice->getGPUContext()->name() << " #" << gpuId << endl;
307+
//cout << "Tracking " << num_particles << " particles on " << gpuLattice->getGPUContext()->name() << " #" << gpuId << endl;
308308

309309
npy_intp outdims[4] = {6,(npy_intp)(num_particles),num_refs,num_turns};
310310
PyObject *rout = PyArray_EMPTY(4, outdims, floatType, 1);
@@ -325,7 +325,8 @@ static PyObject *at_gpupass(PyObject *self, PyObject *args, PyObject *kwargs) {
325325
bool *xlostPtr = (bool *)PyArray_DATA((PyArrayObject *)xlost);
326326
AT_FLOAT *xlostcoordPtr = (AT_FLOAT *)PyArray_DATA((PyArrayObject *)xlostcoord);
327327

328-
gpuLattice->run(num_turns,num_particles,drin,drout,num_refs,ref_pts,num_starts,track_starts,xnturnPtr,xnelemPtr,xlostcoordPtr);
328+
gpuLattice->run(num_turns,num_particles,drin,drout,num_refs,ref_pts,num_starts,track_starts,
329+
xnturnPtr,xnelemPtr,xlostcoordPtr,true);
329330

330331
// Format result for AT
331332
for(uint32_t i=0;i<num_particles;i++) {
@@ -349,7 +350,8 @@ static PyObject *at_gpupass(PyObject *self, PyObject *args, PyObject *kwargs) {
349350

350351
} else {
351352

352-
gpuLattice->run(num_turns,num_particles,drin,drout,num_refs,ref_pts,num_starts,track_starts,nullptr,nullptr,nullptr);
353+
gpuLattice->run(num_turns,num_particles,drin,drout,num_refs,ref_pts,num_starts,track_starts,
354+
nullptr,nullptr,nullptr,true);
353355
return rout;
354356

355357
}

atgpu/main.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ void integratorTest(int gpu,string latticeName) {
134134
// Choose an arc close to 1mm where unexpected tune drift is observed when step size in too small (EBS lattice)
135135
AT_FLOAT *rin = createArc(0.001,M_PI/2.0,-M_PI/2.0,nbPart);
136136

137-
l->run(nbTurn, nbPart, rin, rout, nbRef, refs, 0, nullptr, nullptr, nullptr, nullptr);
137+
l->run(nbTurn, nbPart, rin, rout, nbRef, refs, 0, nullptr, nullptr, nullptr, nullptr, false);
138138

139139
double err = 0;
140140
double max = 0;
@@ -222,7 +222,7 @@ void performanceTest(int gpu,string latticeName) {
222222
AT_FLOAT *lostAtCoord = new AT_FLOAT[nbPart * 6];
223223

224224
t0 = AbstractGPU::get_ticks();
225-
l->run(nbTurn, nbPart, rin, rout, nbRef, refs, nbStride, starts, lostAtTurn, lostAtElem, lostAtCoord);
225+
l->run(nbTurn, nbPart, rin, rout, nbRef, refs, nbStride, starts, lostAtTurn, lostAtElem, lostAtCoord,false);
226226
t1 = AbstractGPU::get_ticks();
227227

228228
//int pIdx = 0;

atmat/atmexall.m

+45
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ function atmexall(varargin)
99
% -fail Throw an exception if compiling any passmethod fails
1010
% (By defaults compilation goes on)
1111
% -openmp Build the integrators for OpenMP parallelisation
12+
% -cuda CUDA_PATH Build the GPU tracking support using Cuda
1213
% -c_only Do no compile C++ passmethods
1314
% -DOMP_PARTICLE_THRESHOLD=n
1415
% Set the parallelisation threshold to n particles
@@ -25,6 +26,7 @@ function atmexall(varargin)
2526

2627
pdir=fullfile(fileparts(atroot),'atintegrators');
2728
[openmp,varargs]=getflag(varargin,'-openmp');
29+
[cuda,varargs]=getoption(varargs,'-cuda','None');
2830
[miss_only,varargs]=getflag(varargs,'-missing');
2931
[c_only,varargs]=getflag(varargs,'-c_only');
3032
[fail,varargs]=getflag(varargs,'-fail');
@@ -92,6 +94,49 @@ function atmexall(varargin)
9294
compile([alloptions, {passinclude}, LIBDL, ompoptions], fullfile(cdir,'atpass.c'));
9395
compile([atoptions, ompoptions],fullfile(cdir,'coptions.c'))
9496

97+
% gpuextensions
98+
if ~strcmp(cuda,'None')
99+
gpudir=fullfile(fileparts(atroot),'atgpu','');
100+
if ispc()
101+
% TODO
102+
error('AT:atmexall', 'GPU windows not supported');
103+
elseif ismac()
104+
% TODO
105+
error('AT:atmexall', 'GPU ismac not supported');
106+
else
107+
gpuflags = {sprintf('-I"%s"',gpudir),...
108+
sprintf('-I"%s/include"',cuda),...
109+
sprintf('-L"%s/lib64"',cuda),...
110+
sprintf('LDFLAGS=$LDFLAGS -Wl,-rpath,"%s/lib64"',cuda),...
111+
'-DCUDA'};
112+
end
113+
compile([alloptions, {passinclude}, gpuflags], ...
114+
fullfile(cdir,'gpuinfo.cpp'),...
115+
fullfile(gpudir,'MatlabInterface.cpp'), ...
116+
fullfile(gpudir,'AbstractInterface.cpp'), ...
117+
fullfile(gpudir,'CudaGPU.cpp'), ...
118+
fullfile(gpudir,'AbstractGPU.cpp'), ...
119+
'-lcuda','-lnvrtc');
120+
compile([alloptions, {passinclude}, gpuflags], ...
121+
fullfile(cdir,'gpupass.cpp'),...
122+
fullfile(gpudir,'AbstractGPU.cpp'), ...
123+
fullfile(gpudir,'CudaGPU.cpp'), ...
124+
fullfile(gpudir,'AbstractInterface.cpp'), ...
125+
fullfile(gpudir,'MatlabInterface.cpp'), ...
126+
fullfile(gpudir,'Lattice.cpp'), ...
127+
fullfile(gpudir,'PassMethodFactory.cpp'), ...
128+
fullfile(gpudir,'SymplecticIntegrator.cpp'), ...
129+
fullfile(gpudir,'IdentityPass.cpp'), ...
130+
fullfile(gpudir,'DriftPass.cpp'), ...
131+
fullfile(gpudir,'StrMPoleSymplectic4Pass.cpp'), ...
132+
fullfile(gpudir,'BndMPoleSymplectic4Pass.cpp'), ...
133+
fullfile(gpudir,'StrMPoleSymplectic4RadPass.cpp'), ...
134+
fullfile(gpudir,'BndMPoleSymplectic4RadPass.cpp'), ...
135+
fullfile(gpudir,'CavityPass.cpp'), ...
136+
fullfile(gpudir,'RFCavityPass.cpp'), ...
137+
'-lcuda','-lnvrtc');
138+
end
139+
95140
[warnmess,warnid]=lastwarn; %#ok<ASGLU>
96141
if strcmp(warnid,'MATLAB:mex:GccVersion_link')
97142
warning('Disabling the compiler warning');

atmat/attrack/gpuinfo.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include <mex.h>
2+
#include <MatlabInterface.h>
3+
#include <AbstractGPU.h>
4+
5+
using namespace std;
6+
7+
// Return GPU Info
8+
const char * gpuInfoNames[] = {"Name","Version","CoreNumber","Platform"};
9+
10+
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
11+
12+
if(nlhs != 1 || nrhs !=0)
13+
mexErrMsgIdAndTxt("AT:WrongParameter","gpuinfo() must have only one output argument");
14+
15+
try {
16+
vector<GPU_INFO> gpuInfos;
17+
gpuInfos = AbstractGPU::getInstance()->getDeviceList();
18+
const mwSize dims[] = {(mwSize)gpuInfos.size()};
19+
plhs[0] = mxCreateCellArray(1,dims);
20+
for(int i=0;i<gpuInfos.size();i++) {
21+
mxArray *s = mxCreateStructMatrix(1, 1, 4, gpuInfoNames);
22+
mxArray *gpuName = mxCreateString(gpuInfos[i].name.c_str());
23+
mxArray *gpuVersion = mxCreateString(gpuInfos[i].version.c_str());
24+
mxArray *gpuCore = mxCreateDoubleScalar(gpuInfos[i].mpNumber);
25+
mxArray *gpuPlatform = mxCreateString(gpuInfos[i].platform.c_str());
26+
mxSetField(s, 0, gpuInfoNames[0], gpuName);
27+
mxSetField(s, 0, gpuInfoNames[1], gpuVersion);
28+
mxSetField(s, 0, gpuInfoNames[2], gpuCore);
29+
mxSetField(s, 0, gpuInfoNames[3], gpuPlatform);
30+
mxSetCell(plhs[0],i,s);
31+
}
32+
} catch (string& errorStr) {
33+
mexErrMsgIdAndTxt("AT:Error",errorStr.c_str());
34+
}
35+
36+
}

atmat/attrack/gpuinfo.m

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function varargout=at_gpuinfo() %#ok<STOUT>
2+
% INFO = at_gpuinfo()
3+
% INFO 1xn structure with the following fields:
4+
% Name: GPU name
5+
% Version: CUDA compute capability (? for OpenCL)
6+
% CoreNumber: Multi processor number
7+
% Platform: Platform name
8+
error('at:missingMex','missing MEX file.');
9+
end

0 commit comments

Comments
 (0)