3.4. Using the Time-Stamp Counter (TSC) Register with Function Entry/Exit HooksΒΆ
The Time-Stamp Counter can be combined with the Function Entry/Exit Hooks feature available in the compiler to generate a quick profiler.
When the Entry/Exit hooks feature is enabled using the --entry_hook
and --exit_hook
options, the compiler inserts a call to an entry hook on entry to each function in the program. The compiler also inserts a call to an exit hook on exit of each function. Refer to the C7000 Optimizing C/C++ Compiler User's Guide (SPRUIG8) for details, and search for the section on Enabling Entry Hook and Exit Hook Functions.
The following example uses entry and exit hooks with the __TSC
register to implement a simple profiler.
hook.h
1// hook.h
2
3#ifndef __hook__
4#define __hook__
5
6#include <stdint.h>
7#include <c7x.h>
8
9// An enum to indicate if a timestamp is associated with
10// function entry or exit
11typedef enum { PD_ENTRY=0, PD_EXIT } PD_Mode;
12
13// Struct for data associated with a single timestamp
14typedef struct {
15 uint64_t function_address;
16 uint64_t timestamp;
17 PD_Mode mode;
18} ProfileData;
19
20void __entry_hook(void (*addr)());
21void __entry_hook(void (*addr)());
22void ProfileData_init();
23void ProfileData_print();
24
25static inline uint64_t get_tsc()
26{
27 // The TSC (Time Stamp Counter) is a read-only register that
28 // is set to 0 on device reset and increments by 1 for each
29 // C7000 CPU clock cycle. It is readable in all supervisor
30 // and user modes.
31 return __TSC;
32}
33
34#endif /* __hook__ */
hook.cpp
1// hook.cpp
2
3#include "hook.h"
4#include <stdio.h>
5
6#define MAX_ENTRIES (64)
7
8// Array to store profile data
9ProfileData table[MAX_ENTRIES];
10int index = 0;
11
12// Entry hook function used to record cycle count on entry into function
13void __entry_hook(void (*addr)())
14{
15 if (index >= MAX_ENTRIES) return;
16
17 table[index].function_address = (uint64_t) addr;
18 table[index].mode = PD_ENTRY;
19 table[index].timestamp = get_tsc();
20 index++;
21}
22
23// Exit hook function used to record cycle count on exit from function
24void __exit_hook(void (*addr)())
25{
26 if (index >= MAX_ENTRIES) return;
27
28 table[index].timestamp = get_tsc();
29 table[index].function_address = (uint64_t) addr;
30 table[index].mode = PD_EXIT;
31 index++;
32}
33
34void ProfileData_init()
35{
36 for (int i = 0; i < MAX_ENTRIES; i++)
37 {
38 table[i].function_address = 0;
39 table[i].mode = PD_ENTRY;
40 table[i].timestamp = 0;
41 }
42}
43
44void ProfileData_print()
45{
46 for (int i = 0; i < MAX_ENTRIES; i++)
47 if (table[i].function_address != 0)
48 {
49 printf("0x%lx, %d, %lu\n",
50 table[i].function_address,
51 table[i].mode,
52 table[i].timestamp);
53 }
54}
Files with functions that need to be profiled are compiled using the --entry_hook ``, ``--entry_parm=address
, --exit_hook
, and --exit_parm=address
options.
When an application is built with the entry/exit hooks in this example, the table is populated with profile data. For example, execution of the code snippet below results in the following table being emitted:
main.cpp
1// hook.cpp
2
3#include "hook.h"
4#include <stdio.h>
5
6#define MAX_ENTRIES (64)
7
8// Array to store profile data
9ProfileData table[MAX_ENTRIES];
10int index = 0;
11
12// Entry hook function used to record cycle count on entry into function
13void __entry_hook(void (*addr)())
14{
15 if (index >= MAX_ENTRIES) return;
16
17 table[index].function_address = (uint64_t) addr;
18 table[index].mode = PD_ENTRY;
19 table[index].timestamp = get_tsc();
20 index++;
21}
22
23// Exit hook function used to record cycle count on exit from function
24void __exit_hook(void (*addr)())
25{
26 if (index >= MAX_ENTRIES) return;
27
28 table[index].timestamp = get_tsc();
29 table[index].function_address = (uint64_t) addr;
30 table[index].mode = PD_EXIT;
31 index++;
32}
33
34void ProfileData_init()
35{
36 for (int i = 0; i < MAX_ENTRIES; i++)
37 {
38 table[i].function_address = 0;
39 table[i].mode = PD_ENTRY;
40 table[i].timestamp = 0;
41 }
42}
43
44void ProfileData_print()
45{
46 for (int i = 0; i < MAX_ENTRIES; i++)
47 if (table[i].function_address != 0)
48 {
49 printf("0x%lx, %d, %lu\n",
50 table[i].function_address,
51 table[i].mode,
52 table[i].timestamp);
53 }
54}
Table output:
0x7004, 0, 8100
0x6fc0, 0, 8516
0x6fc0, 1, 8931
0x6fc0, 0, 9061
0x6fc0, 1, 9476
0x7004, 1, 9603