5

What do I want?

I am looking for a way to detect all points in my code where a specific function is called.

Why do I want it?

Some examples:

  • Some output comes out sorted or randomized, and I want to know where this happens
  • I am considering to change/overload a function and want to know in which part of my code this could have impact

What have I tried?

  • I tried placing a breakpoint in the file that was called. This only works for non builtin functions which are called from short running code that always executes everything.
  • I tried 'find files', this way I can easily find direct calls to sort but it is not so easy to find a call to sort invoked by unique for example.
  • I have tried depfun, it tells me:
    • whether something will be called
    • from where non-builtin functions will be called
  • I thought of overloading the builtin function, but feels like a last resort for me as I am afraid to make a mess. | Edit: Also it probably won't help due to function precedence.

The question

What is the best way to track all potential (in)direct function calls from a specific function to a specific (built-in)function.

Dennis Jaheruddin
  • 21,208
  • 8
  • 66
  • 122
  • Listing _all_ potential calls is likely impossible without running the code and encountering all edge cases. This is because the built-in function of interest (hereinafter: _foi_) may be called from other built-in functions that might be compiled/closed source, so the only way to know who called the _foi_ is via `dbstack` (and this is assuming it's open-source). You mentioned that the runtime of the code was very long and so this process was impractical. However, may be possible to replace the calls to the most time-consuming functions with randomized/predefined outputs and save much time. – Dev-iL Oct 23 '17 at 11:13

3 Answers3

3

I don't exactly understand your use case, but I guess most of the information you want can be obtained using dbstack, which gives you the call-stack of all the parent functions calling a certain function. I think the easiest way is to overload built-in functions something like this (I tried to overload min):

function varargout = min(varargin)

% print info before function call
disp('Wrapped function called with inputs:')
disp(varargin)
[stack,I] = dbstack();
disp('Call stack:')
for i=1:length(stack)
    fprintf('level %i: called from line %i in file %s\n', ...
        i, stack(i).line, stack(i).file);
end

% call original function
[varargout{1:nargout}] = builtin('min', varargin{:});

% print info after function call
disp('Result of wrapped function:')
disp(varargout)

I tried to test this, but I could not make it work unfortunately, matlab keeps on using the original function, even after playing a lot with addpath. Not sure what I did wrong there, but I hope this gets you started ...

Bas Swinckels
  • 18,095
  • 3
  • 45
  • 62
  • I believe this is somewhat similar to trying to place a breakpoint in a file. The problem is that I also want to list function calls that could happen in corner cases or after a very long time. Running the code untill I have covered all the corner cases is not really an option for me. – Dennis Jaheruddin Jan 07 '14 at 09:59
  • Why is this not an option, because of speed? You could modify the wrapper function in any way you want, for example only displaying something when the parent function is not in a list of known callers. – Bas Swinckels Jan 07 '14 at 10:08
  • The runtime of my code is 'only' a few hours, but during a single run only a fraction of the lines will be touched. Hence a 'list-if-touched' approach is a bit problematic. – Dennis Jaheruddin Jan 07 '14 at 11:18
3

Built-in functions take precedence over functions in local folder or in path. There are two ways you can overload a built-in for direct calls from your own code. By putting your function in a private folder under the same directory where your other MATLAB functions are. This is easier if you are not already using private folder. You can rename your private folder once you are done investigating.

Another way is to use packages and importing them. You put all your override functions in a folder (e.g. +do_not_use). Then in the function where you suspect built-in calls are made add the line "import do_not_use.*;". This will make calls go to the functions in +do_not_use directory first. Once you are done checking you can use "clear import" to clear all imports. This is not easy to use if you have too many functions and do not know in which function you need to add import.

In addition to this, for each of the function you need to follow Bas Swinckels answer for the function body.

Function precedence order.

Those two methods does not work for indirect calls which are not from your own code. For indirect calls I can only think of one way where you create your own class based on built-in type. For example, if you work only on double precision types, you need to create your own class which inherits from double and override the methods you want to detect. Then pass this class as input to your code. Your code should work fine (assuming you are not using class(x) to decide code paths) since the new class should behave like a double data type. This option will not work if your output data is not created from your input data. See subclassing built-in types.

Navan
  • 4,407
  • 1
  • 24
  • 26
  • The first part definitely explains why a simple overload won't help. I am not yet sure about how to try the latter part of this answer and can definitely not guess whether it will work, but so far I am optimistic and I will definitely try. – Dennis Jaheruddin Jan 07 '14 at 15:15
0

Did you try depfun?

The doc shows results similar to the ones you request.

doc depfun:

...

[list, builtins, classes, prob_files, prob_sym, eval_strings, called_from, java_classes] = depfun('fun') creates additional cell arrays or structure arrays containing information about any problems with the depfun search and about where the functions in list are invoked. The additional outputs are ...

Looks to me you could just filter the results for your function.

Though need to warn you - usually it takes forever to analyze code.

bdecaf
  • 4,652
  • 23
  • 44
  • That was actually point 3 under what I tried. This is indeed the closest I have come, but for it to work I would probably need to overload the built in function I am looking for each time I am doing this. (It is not clear from the doc, but depfun only appears to show where the call to regular functions is made, and not to builtin functions. For builtin functions it only gives a list which are called). – Dennis Jaheruddin Jan 07 '14 at 11:19
  • oh. I wasn't aware built-in functions are not reported as other functions. I just did an `edit depfun` - there is a function `fix_output_data` that will call the unique on builtins. Maybe if you try to comment that out? – bdecaf Jan 07 '14 at 12:14
  • Commenting out that line won't help me find out where the function is called, but editing `depfun` may be the way to go. I was thinking of either creating a 'called from' list for the builtin functions, or by putting the builtin functions together with the regular functions (may have some nasty sideffects, but I guess I could try). Unfortunately I have not managed to do either as I don't comprehend the basics of `depfun`, like where the builtin functions are split off from the others. – Dennis Jaheruddin Jan 07 '14 at 15:07