matlab coder:Generating C code for general functions is a big performance problem

8 views (last 30 days)
To my incomplete knowledge, for matlab built-in function imwarp generated C code/mex file performance is much inferior to the open source library OpenCV, I originally wanted to use matlab coder/embeded coder to deploy the algorithm to generate C code, but found that performance is a big problem. Below I have written a simple function to test this, "myEntry" is the function to generate the C code. Again I wrote the same function with very little C++ code. The performance was then compared as follows:
function outImg = myEntry(inImg)%#codegen
% or use "tform = rigidtform2d(30,[100,200]);" The following matrix is
% obtained directly from tform.A
% note: here should "single" type input,while very sensitive to "double"
% type and highly susceptible to invalid matrix inputs!
tform = rigidtform2d(single([0.8660 -0.5000 100.0000
0.5000 0.8660 200.0000
0 0 1.0000]));
% get output view full range
[h,w,~] =size(inImg);
xLimitsIn = [0.5,w+0.5];
yLimitsIn = [0.5,h+0.5];
[xLimitsOut,yLimitsOut] = outputLimits(tform,xLimitsIn,yLimitsIn);
% global full view range
xWorldLimits = [min(xLimitsIn(1),xLimitsOut(1)),max(xLimitsIn(2),xLimitsOut(2))];
yWorldLimits = [min(yLimitsIn(1),yLimitsOut(1)),max(yLimitsIn(2),yLimitsOut(2))];
W = round(xWorldLimits(2)-xWorldLimits(1));
H = round(yWorldLimits(2)-yWorldLimits(1));
outputView = imref2d([H,W],xWorldLimits,yWorldLimits);
% warp image
outImg = imwarp(inImg,tform,'OutputView',outputView);
The following script was then used to generate the mex/C code executable library file:
%% opencv VS matlab origin code VS generate mex/C performance
%% generate mex file
inImg = im2single(imread("peppers.png"));
codegen -config:mex myEntry -args {inImg}
%% test speed
num = 1000;
t1 = tic;
for i = 1:num
outImg1 = myEntry(inImg);
t = toc(t1);
t2 = tic;
for i = 1:num
outImg2 = myEntry_mex(inImg);
tt = toc(t2);
fprintf("origin matlab code take time:%.5f seconds,generate C/mex code take time:%.5f seconds\n",t,tt);
Code generation successful.
origin matlab code take time:5.53857 seconds,generate C/mex code take time:5.46453 seconds
These two take about the same amount of time and it looks like imwarp uses a pre-compiled library, even though it generates C code, there is no significant speed advantage!
For the same functionality, I implemented it again using OpenCV C++ as follows:
cv::Mat img = cv::imread("peppers.png");
cv::Mat dst;
size_t nums = 1000;
double t1 = cv::getTickCount();
for (size_t i = 0; i < nums; i++) {
cv::Mat transMat = (cv::Mat_<float>(2, 3) << 0.8660, -0.5000, 100.0000,
0.5000, 0.8660, 200.0000);
// 计算包含目标图像的最大范围
std::vector<cv::Point2f> srcCorners = {cv::Point2f(0, 0), cv::Point2f(img.cols, 0), cv::Point2f(img.cols, img.rows), cv::Point2f(0, img.rows)};
std::vector<cv::Point2f> dstCorners;
cv::transform(srcCorners, dstCorners, transMat); // 对应matlabtranspointsforward
dstCorners.insert(dstCorners.end(), srcCorners.begin(), srcCorners.end());
cv::Rect outputView = cv::boundingRect(dstCorners);
// 平移到可视化区域
transMat.colRange(2, 3) = transMat.colRange(2, 3) - (cv::Mat_<float>(2, 1) << outputView.x, outputView.y);
cv::warpAffine(img, dst, transMat, cv::Size(outputView.width, outputView.height));
double t2 = cv::getTickCount();
std::printf("it take time:%.5f seconds. dst image size:(%d*%d)\n", (t2 - t1) * 1.0 / cv::getTickFrequency(), dst.rows, dst.cols);
it take time:0.79880 seconds. dst image size:(789*636)
As you can see above, the performance difference between imwarp's built-in functions is about 6.89 times, so it seems that performance is indeed an issue.
RUN in R2022b, windows 10

Accepted Answer

Matan Silver
Matan Silver on 7 Nov 2022
I took a look at the generated code for these reproduction steps, and found that a large performance penalty is paid in runtime integrity checks. These integrity checks are generated by default for MEX and check things like index bounds, integer overflows, divide by zero, and more. I don't know how openCV works under the hood but it's likely it's not doing as many runtime checks. You can turn off these checks by changing the codegen script to run:
cfg = coder.config('mex');
cfg.IntegrityChecks = false;
codegen -config cfg myEntry -args {inImg}
This could give a closer comparison between generated code and openCV. Running your repro after making those changes, I see the following significant improvement:
>> doit
Code generation successful.
origin matlab code take time:4.58261 seconds,generate C/mex code take time:1.37438 seconds
Hopefully that helps. Note that turning off IntegrityChecks has the downside that invalid input to the MEX can potentially cause the MEX to crash.

Sign in to comment.

More Answers (0)


Find more on Get Started with MATLAB Coder in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!