0

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:

  • main call driver_TASK
  • main call keyBoard_TASK

however, it becomes

  • main call driver_TASK
  • driver_TASK call keyboard_TASK

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"]

}
Regexident
  • 29,441
  • 10
  • 93
  • 100
How Chen
  • 1,340
  • 2
  • 17
  • 37

2 Answers2

2

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)
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
0

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.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • thanks for you comment, can I understand that, both of my `driver_TASK` and `keyBoard_TASK` are called by `pthread_create` – How Chen Sep 20 '12 at 08:03
  • No, they are not "called" by that. `pthread_create` happens inside the thread of `main`. The two threads are launched by the system kernel and have neither `main` nor `pthread_create` on their call stack. – Jens Gustedt Sep 20 '12 at 08:27