How Chen
How Chen

Reputation: 1370

generate function call for c

I use -finstrument-functions to generated enter and exit information of my each function call and use dot to draw it just like above. However, I found one problem, in my main function, I create two threads, one called driver_TASL, another is keyBoard_TASK. but in my generated picture, It seems like my keyBoard_TASK was called by driver_TASK. It should be like these two TASK called by main

Remark: I can NOT upload picture, so I describe it below:

after I generate function call, it should be like:

however, it becomes

Why the keyBoard_TASK was called by driver_TASK? It should be called by main I think

In my source code, I wrote them like (I deleted some print functions in code):

int main(/*@ unused @*/int argc, /*@ unused @*/char *argv[]) //comment for lint
{
    int         res;
    pthread_t   driver_thread, keyBoard_thread;
    void        *thread_result;

    res = pthread_create(&driver_thread, NULL, driver_TASK, (void *)&_gDriverStatus);
    if(res != 0)
    {
        perror("Thread Creation Failed");
        exit(EXIT_FAILURE);
    }

    sleep(1);

    res = pthread_create(&keyBoard_thread, NULL, keyBoard_TASK, (void *)&_gKeyStatus);
    if(res != 0)
    {
        perror("Thread Creation Failed");
        exit(EXIT_FAILURE);
    }

    res = pthread_join(driver_thread, &thread_result);
    if(res != 0)
    {
        perror("Thread Join Failed");
        exit(EXIT_FAILURE);
    }

    res = pthread_join(keyBoard_thread, &thread_result);
    if(res != 0)
    {
        perror("Thread Join Failed");
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
}

I also attached my automatically dot file, the function call flow chart is automatically generated by pvtace

digraph DEMO {

  main [shape=rectangle]
  driver_TASK [shape=rectangle]
  DDI_DRIVER_Probe [shape=rectangle]
  _Driver_Clear [shape=ellipse]
  _Driver [shape=ellipse]
  DRIVER_Probe_Demo [shape=ellipse]
  DDI_DRIVER_Init [shape=rectangle]
  DRIVER_Init_Demo [shape=rectangle]
  _DRIVER_Init_Demo [shape=ellipse]
  DDI_DRIVER_Running [shape=rectangle]
  DRIVER_Running_Demo [shape=rectangle]
  _DRIVER_Running_Demo [shape=ellipse]
  keyBoard_TASK [shape=rectangle]
  main -> DBG_PrintColor [label="2 calls" fontsize="10"]
  main -> driver_TASK [label="1 calls" fontsize="10"] //this is correct
  driver_TASK -> DBG_PrintColor [label="6 calls" fontsize="10"]
  driver_TASK -> DDI_DRIVER_Probe [label="1 calls" fontsize="10"]
  driver_TASK -> DDI_DRIVER_Init [label="1 calls" fontsize="10"]
  driver_TASK -> DDI_DRIVER_Running [label="1 calls" fontsize="10"]
  driver_TASK -> keyBoard_TASK [label="1 calls" fontsize="10"] //this is not correct
  DDI_DRIVER_Probe -> _Driver_Clear [label="1 calls" fontsize="10"]
  DDI_DRIVER_Probe -> _Driver [label="1 calls" fontsize="10"]
  DDI_DRIVER_Probe -> DRIVER_Probe_Demo [label="1 calls" fontsize="10"]
  DDI_DRIVER_Init -> _Driver [label="1 calls" fontsize="10"]
  DDI_DRIVER_Init -> DRIVER_Init_Demo [label="1 calls" fontsize="10"]
  DRIVER_Init_Demo -> _DRIVER_Init_Demo [label="1 calls" fontsize="10"]
  DDI_DRIVER_Running -> _Driver [label="1 calls" fontsize="10"]
  DDI_DRIVER_Running -> DRIVER_Running_Demo [label="1 calls" fontsize="10"]
  DRIVER_Running_Demo -> _DRIVER_Running_Demo [label="1 calls" fontsize="10"]
  keyBoard_TASK -> DBG_PrintColor [label="6 calls" fontsize="10"]

}

Upvotes: 0

Views: 498

Answers (2)

Michael Burr
Michael Burr

Reputation: 340208

I assume that you are using the 'instrumental' library for collecting the call graph information (if not, you should indicate what you are using and/or what you do do in the __cyg_profile_func_enter() and __cyg_profile_func_exit() routines).

Looking at the implementation (available at http://www.suse.de/~krahmer/instrumental/), it's clear that the call graph information is not collected in a thread safe manner. Each function called is simply recorded in the log file as it's called, and the depth of the call graph is kept in a global variable (actually a static variable). Information about the call chain is also kept in a global array.

So what's happening is that something along the following line of events occurs:

__cyg_profile_func_enter()  - for main() on main thread
__cyg_profile_func_enter()  - for driver_TASK() on driver_thread
__cyg_profile_func_enter()  - for keyBoard_TASK() on keyboard_thread

...

The fact that these events happen to occur in this order, without intervening __cyg_profile_func_exit() events means that the instrumental library records things as if:

main()
|
+--- driver_TASK()
     |
     +--- keyBoard_TASK()

When there really should be separate call graphs for each thread (which would require thread awareness in the instrumentation). To fix the problem, you'll need to do one of the following:

  • find an instrumentation library that's thread aware
  • add thread awareness to the one you're using now
  • fix up the generated logs by hand (which might be simple if the thread functions are relatively simple, but could turn out to be a large/complicated task)

Upvotes: 2

Jens Gustedt
Jens Gustedt

Reputation: 78903

The problem must be in how you instrument the functions. Strictly speaking, main isn't calling either of these functions; launching a thread is not equivalent to a function call. Both of your functions should show just some system functions as their caller. main isn't on their call stack.

Now the relation between main and your two functions is a special dependency, and you should somehow track that differently.

Upvotes: 0

Related Questions