2

I'm attempting to create a python script that modifies C source to time and collect other metrics about the execution of selected functions.

The goal is to start with a config file then run the script which modifies source to accomplish the following:

Idea A:

foo_profile()
    {
    start_profile();
    foo();
    end_profile();
    }

Idea B:

foo()
    {
    start_profile();
    //dostuff
    end_profile();
    }

A's considerations:

  • Strategy: Seems easiest to do this by inserting the intercepting prototypes/definitions into the same header/src files. Leaving everything else the same (in case some callers aren't changed). And of course adding the includes for the start/end_profile().

    • Need to identify the correct callers of foo()
      • There are some functions with identical names that are protected by higher level build system that splits things into projects/partitions (difficult to determine automatically, but a specific config could fix the problem)
    • Need to identify the correct header that has foo()
    • Parameters need passed through and would be duplicated on the stack, not a huge deal but might throw things off a bit

B's considerations:

  • Strategy: This one's straight forward, just add the profile calls. It would have quite a few annoying problems to deal with (following).
    • start_profile() needs to be called after variable declarations (arm)
      • not sure if this error can be ignored with a compiler flag, or is there an reason for this? (compiler specific I know, but generally)
      • simple locals can be found pretty easy (ctags), but there are some macros that are called for param validation that end up declaring variables that would be difficult to automatically find. Would likely end up with a macro black list to check for to add the profile call after.
    • end_profile() of course needs to be called right before all the returns
      • an expensive function call in a return would end up not profiled if the call was setup like: end_profile();return expensive_call();
        • of course the expensive_call() could be given a return variable (declared initially), type automatically found from an included header. Adding some complexity and potential for problems (more stack, could be some weird macro stuff to break things)
      • any way to tell compiler to add code to prolog/epilogue? (I know this is compiler specific, but just if you have a general idea if it's possible)

Overview/question:

Implementation wise A is most attractive, but for the information collected and configuration ease B would better. B seems more difficult/less reliable to implement. Of course there are other ways, like modifying the linking but the previous strategies seem best to me.

So my question boils down to is there a strategy here that I missing? Given the problem how would you go about it? Anything I haven't mention here I should consider? Any help with the scattered questions or general guidance would be appreciated.

If anything is unclear I'll be quick to edit and clarify. First question so if I've botched something let me know.

EDIT:----------------------------------------------------

My ARM compiler has a flag that lets you provide your own entry/exit definitions to do this (--gnu_instrument). If for some reason the compiler does not let you do this I think it would be easiest to actually change the name of the real definition and use a script to add back the 'real' function names in the same file with the same signature (not sure why I didn't think of this). That why all calls are instrumented and you don't have to worry about 'intercepting'. Like so:

Initial:

foo()
    {
    //do stuff
    }

Instrumented:

foo()
    {
    start_profile();
    foo_unique_id();
    end_profile();
    }

foo_unique_id()
    {
    //do stuff
    }
Idan Reed
  • 53
  • 4
  • Are you working on a new generic tool, or are you trying to solve a specific problem? In the latter case there might be a [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). If you're using GCC then look at `gcov` and `gprof`. – the busybee Jun 13 '19 at 06:41

1 Answers1

-1

It looks like what you're trying to do is called code instrumentation and is somewhat similar to this post. GCC has -finstrument-functions (if you're using GCC) which you can read about here and the official docs here. -finstrument-functions appears to take your second approach by adding the tracing calls into the existing function rather than wrapping it.

Zach Woods
  • 516
  • 2
  • 11
  • Turns out ARMCC has a --gnu_instrument flag which lets you define entry and exit functions. Which was pretty much exactly what I wanted to do – Idan Reed Jun 15 '19 at 02:39