Skip to content

Commit 2afdca7

Browse files
committed
feat: 📦️ MEX-accelerated upscale function
Introduce `CodeMexGen` class that can compile the `upscale` function into MEX-file to accelerate the toolkit. How to use: ```matlab % 1. compile MEX functions codegen_mex = CodeGenMex().config().build(); % 2. use strata_trapper normally ... % 3. recompile MEX functions when the source code changes codegen_mex.build(); % 4. delete MEX functions to use the original codegen_mex.clear(); ```
1 parent e115dff commit 2afdca7

File tree

7 files changed

+139
-6
lines changed

7 files changed

+139
-6
lines changed

.cspell.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"ignoreWords": [
2222
"buildfile",
2323
"buildplan",
24-
"localfunctions"
24+
"localfunctions",
25+
"codegen_mex"
2526
]
2627
}

.github/workflows/matlab.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@ jobs:
1818
Statistics_and_Machine_Learning_Toolbox
1919
Parallel_Computing_Toolbox
2020
- uses: matlab-actions/run-build@v2
21+
with:
22+
#NOTE: test_codegen requires batch licensing
23+
tasks: check test

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Repository: [github.com/ImperialCollegeLondon/StrataTrapper](https://github.com/
1111
* [The StrataTrapper codes](#the-stratatrapper-codes)
1212
* [Structure](#structure)
1313
* [Running](#running)
14+
* [MEX acceleration](#mex-acceleration)
1415
* [Versions](#versions)
1516
* [Contributing](#contributing)
1617
* [References](#references)
@@ -63,6 +64,27 @@ if they are in a startup folder.
6364
So, using several parallel workers usually results
6465
in a proportional performance boost.
6566

67+
## MEX acceleration
68+
69+
We provide the `CodeGenMex` class to automatically build
70+
a MEX-accelerated version of the `upscale` function.
71+
72+
```matlab
73+
% 1. compile MEX functions
74+
codegen_mex = CodeGenMex().config().build();
75+
76+
% 2. use strata_trapper normally
77+
...
78+
79+
% 3. recompile MEX functions when the source code changes
80+
codegen_mex.build();
81+
82+
% 4. delete MEX functions to use the original
83+
codegen_mex.clear();
84+
```
85+
86+
Requires [MATLAB Coder](https://uk.mathworks.com/products/matlab-coder.html).
87+
6688
## Versions
6789

6890
The original version of the toolkit is [v0.1.0](https://github.com/ImperialCollegeLondon/StrataTrapper/tree/v0.1.0).\

buildfile.m

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,30 @@
11
function plan = buildfile()
2-
2+
startup;
33
plan = buildplan(localfunctions);
4-
plan.DefaultTasks = ["check", "test"];
4+
plan.DefaultTasks = ["check", "test", "test_codegen"];
55

6-
test_options = {"IncludeSubfolders",true};
6+
test_options = {"IncludeSubfolders",false};
7+
test_codegen_options = {"test/CodeGenMexTest.m"};
78

89
if isMATLABReleaseOlderThan("R2023b")
910
plan("test") = matlab.buildtool.Task( ...
1011
Description="Run tests", ...
1112
Actions=@(~) assert(runtests(test_options{:}).Failed == 0));
1213

14+
plan("test_codegen") = matlab.buildtool.Task( ...
15+
Description="Run tests", ...
16+
Actions=@(~) assert(runtests(test_codegen_options{:}).Failed == 0));
17+
1318
plan("check") = matlab.buildtool.Task(...
1419
Description="Identify code issues", ...
1520
Actions=@(~) assert(code_issues()) );
16-
21+
1722
return;
1823
end
1924

2025
plan("check") = matlab.buildtool.tasks.CodeIssuesTask(WarningThreshold=0);
2126
plan("test") = matlab.buildtool.tasks.TestTask(test_options{:});
22-
27+
plan("test_codegen") = matlab.buildtool.tasks.TestTask(test_codegen_options{:});
2328
end
2429

2530
function issue_free = code_issues()

src/CodeGenMex.m

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
classdef CodeGenMex < handle
2+
properties
3+
cfg
4+
built_func
5+
end
6+
7+
methods
8+
function self = CodeGenMex()
9+
mex -setup C++
10+
end
11+
12+
function self = config(self)
13+
self.cfg = coder.config("mex");
14+
15+
self.cfg.Name = "strata_trapper-mex";
16+
self.cfg.Description = "MEX-compiled StrataTrapper functions";
17+
18+
self.cfg.TargetLang = "C++";
19+
self.cfg.CppNamespace = "strata_trapper";
20+
21+
self.cfg.InlineBetweenUserFunctions = "Speed";
22+
self.cfg.InlineBetweenUserAndMathWorksFunctions = "Speed";
23+
self.cfg.InlineBetweenMathWorksFunctions = "Speed";
24+
25+
self.cfg.NumberOfCpuThreads = 32;
26+
self.cfg.SIMDAcceleration = "Full";
27+
self.cfg.OptimizeReductions = true;
28+
self.cfg.EnableAutoParallelization = false;
29+
self.cfg.EnableOpenMP = false;
30+
end
31+
32+
33+
function self = build_with(self,options,func)
34+
codegen("-config",self.cfg,options{:},func);
35+
self.built_func = func;
36+
end
37+
38+
function self = build(self)
39+
self = self.build_with({"-o","upscale"},'upscale');
40+
end
41+
42+
function self = clear(self)
43+
clear mex; %#ok<CLMEX>
44+
delete([self.built_func,'.mex*']);
45+
self.built_func = [];
46+
end
47+
end
48+
end

test/CodeGenMexTest.m

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
% This test file was generated by Copilot. Validate the generated output before use.
2+
classdef CodeGenMexTest < matlab.unittest.TestCase
3+
properties
4+
codeGen
5+
end
6+
7+
methods(TestMethodSetup)
8+
function createCodeGen(testCase)
9+
testCase.codeGen = CodeGenMex();
10+
end
11+
end
12+
13+
methods(Test)
14+
function testConfig(testCase)
15+
testCase.codeGen.config();
16+
testCase.verifyEqual(testCase.codeGen.cfg.Name, 'strata_trapper-mex');
17+
testCase.verifyEqual(testCase.codeGen.cfg.Description, ...
18+
'MEX-compiled StrataTrapper functions');
19+
testCase.verifyEqual(testCase.codeGen.cfg.TargetLang, 'C++');
20+
testCase.verifyEqual(testCase.codeGen.cfg.NumberOfCpuThreads, int32(32));
21+
end
22+
23+
function testBuild(testCase)
24+
testCase.codeGen.config();
25+
a = int32(2);
26+
b = int32(2);
27+
sum = add_mex_test(a,b);
28+
testCase.codeGen.build_with({"-o","add_mex_test","-v"},'add_mex_test');
29+
% Check if the MEX file was created
30+
testCase.verifyTrue(exist('add_mex_test', 'file') == 3);
31+
sum_mex = add_mex_test(a,b);
32+
testCase.verifyTrue(sum_mex == sum); % test compiled MEX function
33+
end
34+
35+
function testClear(testCase)
36+
testCase.codeGen.config();
37+
testCase.codeGen.build_with({"-o","add_mex_test"},'add_mex_test');
38+
testCase.codeGen.clear();
39+
% Check if the MEX file was deleted
40+
testCase.verifyTrue(exist('add_mex_test', 'file') == 2);
41+
end
42+
end
43+
end

test/add_mex_test.m

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
function sum= add_mex_test(a,b)
2+
arguments (Input)
3+
a (1,1) int32
4+
b (1,1) int32
5+
end
6+
7+
arguments (Output)
8+
sum (1,1) int32
9+
end
10+
sum = a+b;
11+
end

0 commit comments

Comments
 (0)