Strange gpu arrayfun behavior

I have existing code that works but I'd like to accelerate using the GPU version of arrayfun. However the behavior of GPU arrayfun is difficult to understand. According to the documentation the code within the helper function performs scalar operations on the input gpuArray values. However if I try to write my own scalar values the result is unpredictable. To demonstrate, if I have a helper function that look like:
function outArray = simpleTest(inArray)
outArray = inArray * 3.14159;
end
x = gpuArray(1:4);
y = arrayfun(@simpleTest, x);
y = gather(y)
y =
Columns 1 through 2
0.0000 + 0.0000i 0.0000 + 0.0000i
Columns 3 through 4
0.0000 + 0.0000i 0.0000 + 0.0000i
If I pass the scalar value to the helper function, as shown in the second helper function, it does seem to work:
function outArray = simpleTest2(inArray, scalarValue)
outArray = inArray * scalarValue;
end
y = arrayfun(@simpleTest2, x, 3.14159);
y = gather(y)
y =
3.1416 6.2832 9.4248 12.5664
Reading the documentation, I know that the scalar values in the calling function are expanded (similar to bsxfun) however I have been unable to get that function, or any other function, to work within the helper function. I know I'm missing something here, I would appreciate the help.
I have Matlab R2018a with Parallel Computing Toolbox and Cuda version 9.0 installed.

5 Comments

Well, that behaviour you appear to be getting is just incredibly weird and it doesn't reproduce for me. I can't think of any good reason why it would happen. It would be best to start by eliminating coding issues. To start, copy the code above into a new script, but move the function to the end, then run the script. This will ensure that you are running exactly what you wrote:
x = gpuArray(1:4);
y = arrayfun(@simpleTest, x);
y = gather(y)
function outArray = simpleTest(inArray)
outArray = inArray * 3.14159;
end
nealm
nealm on 24 Jul 2018
Edited: nealm on 24 Jul 2018
I tried your script with the function at the end and got the same result. I was able to check on another computer running R2015a and it worked fine. After a lot of effort what I thought was a coding problem appears to be something else. I put in a service request with mathworks; perhaps there's a bug or configuration problem.
Just curious, what does the following return?
which simpleTest
which simpleTest2
nealm
nealm on 24 Jul 2018
Edited: nealm on 24 Jul 2018
>> which simpleTest
'simpleTest' not found.
>> which simpleTest2
'simpleTest2' not found.
>>
I placed the simpleTest functions in a script. I also tried calling them from their own files, no difference.
Okay, so the next thing to do is to check and upgrade your driver. What is your device? What is your driver version?
gpuDevice
parallel.internal.gpu.CUDADriverVersion

Sign in to comment.

 Accepted Answer

nealm
nealm on 25 Jul 2018
Joss/OCDER,
I found the source of the problem. I use my own "startup.m" file (which only has "addpath" commands) that is executed at the beginning of a Matlab start. The directories that have been added during the startup process appear to interfere with the way gpu arrayfun executes.
If I don't use the startup.m file gpu arrayfun works fine. Curiously, if I manually run the contents of startup.m AFTER starting Matlab - gpu arrayfun also works fine.

6 Comments

Interesting fix. Does one of the directory that is added include an arrayfun function?
which arrayfun
which gpuArray/arrayfun
See #10. Maybe addpath is changing the appearance order of a matlab path, and thus the function isn't correct. There's an arrayfun for non-gpu calculation, and arrayfun for gpu calculations. BUT, then you already tried running startup.m AFTER matlab, and this doesn't break the code. Very odd. What's in startup.m?
Yes thanks OCDER. I'd like to get to the bottom of it in case there's a real bug in here. A simple path issue doesn't seem to explain why it works with simpleTest2, unless perhaps the call to which wasn't working for some other reason.
First try changing the name of the function (to something random). and make sure the issue reproduces.
Next, set a breakpoint on the line with the call to arrayfun, run the script, then hit F11 to step into the call. If GPU arrayfun is behaving correctly, this should just step over that line because you cannot debug your simpleTest function on the GPU. If not, perhaps you will find the debugger does step into some function.
If this doesn't reveal anything, try stepping into arrayfun with a CPU array (set x to 1:4 rather than gpuArray(1:4)). It should step into your simpleTest code, but if simpleTest is elsewhere on the path it may take you to the true location.
Class gpuArray isn't loaded until it's used, and that includes its methods like arrayfun. It's not impossible that modifying the toolbox path before the first call to gpuArray could irrevocably change the resolution of arrayfun in a way that doesn't happen if the path is modified after the first call to gpuArray.
Thanks for your help isolating this (potential) issue.
Joss and OCDER, First thank you for helping me debug this problem. I've seen some great speed up in my code with the GPU fft and GPU xcorr functions and look forward to implementing GPU arrayfun.
I've rewritten the test function as follows:
x = gpuArray(1:4);
yTest1 = arrayfun(@axax123, x);
yTest1 = gather(yTest1)
yTest2 = arrayfun(@szsz789, x, 3.14159);
yTest2 = gather(yTest2)
function outArray = axax123(inArray)
outArray = inArray * 3.14159;
end
function outArray = szsz789(inArray, scalarValue)
outArray = inArray * scalarValue;
end
I've simplified my startup.m file (still causes the weird behavior) to:
startup()
addpath('D:\nealMatlab'); % Path to lots of other Matlab code
end
The first test case I start Matlab with startup.m present and run the test code
>> test
yTest1 =
Columns 1 through 2
0.0000 + 0.0000i 0.0000 + 0.0000i
Columns 3 through 4
0.0000 + 0.0000i 0.0000 + 0.0000i
yTest2 =
3.1416 6.2832 9.4248 12.5664
Checking the paths:
>> which arrayfun
built-in (C:\Program Files\MATLAB\R2018a\toolbox\matlab\datatypes\arrayfun)
>> which gpuArray/arrayfun
C:\Program Files\MATLAB\R2018a\toolbox\distcomp\gpu\@gpuArray\arrayfun.m % gpuArray method
>> which azaz123
'azaz123' not found.
>> which szsz789
'szsz789' not found.
nealm
nealm on 26 Jul 2018
Edited: nealm on 26 Jul 2018
Next if I put a breakpoint at the first GPU arrayfun and step into it with F11
yTest1 = arrayfun(@axax123, x);
The editor takes me to a matlab classdef called "mtree". Below is a copy and paste of the first 32 lines of mtree
classdef mtree
%MTREE Create and manipulate M parse trees
% This is an experimental program whose behavior and interface is likely
% to change in the future.
properties (SetAccess='protected', GetAccess='protected', Hidden)
T % parse tree array
% column 1: kind of node
% column 2: index of left child
% column 3: index of right child
% column 4: index of next node
% column 5: position of node
% column 6: size of node
% column 7: symbol table index (V)R/
% column 8: string table index
% column 9: index of parent node
% column 10: setting node
% column 11: lefttreepos
% column 12: righttreepos
% column 13: true parent
% column 14: righttreeindex
% column 15: rightfullindex
S % symbol table
C % character strings
IX % index set (default is true for everything)
n % number of nodes
m % sum(IX)
lnos % line number translation
str % input string that created the tree
end
If I don't use startup.m this doesn't happen and GPU arrayfun functions normally. Also if I run my addpath function by itself AFTER starting Matlab this doesn't happen and GPU arrayfun functions normally.
addpath('D:\nealMatlab');
Copyright 2006-2016 The MathWorks, Inc.
nealm
nealm on 26 Jul 2018
Edited: nealm on 26 Jul 2018
Assuming the call to mtree wasn't normal, I checked the files in my path and didn't find any file that uses classdef mtree directly. Then after some work I think I found the culprit; In my path I have a class folder "@char" where I've redefined the method str2double to that from a mex file from the file exchange:
I had relabeled the function from str2doubleq to str2double for convenience and have used it for several years without issue. After removing this user version of "str2double" from the @char folder, GPU arrayfun behaves normally in all test cases.
Not sure if this is a bug in Matlab or just poor coding form by me, but I'll stop relabeling matlab functions to my own user functions.
Thanks for the investigation! I'll have a look at why str2double is involved and whether I can reproduce your issue. MTree is used to do static analysis of your arrayfun function for the GPU, and presumably str2double is being used to convert the text of your literal value. It may well be a bug that it's possible to break arrayfun by shadowing this function.

Sign in to comment.

More Answers (0)

Categories

Products

Release

R2018a

Asked:

on 20 Jul 2018

Commented:

on 26 Jul 2018

Community Treasure Hunt

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

Start Hunting!