1 /*===-- PathProfiling.c - Support library for path profiling --------------===*\
3 |* The LLVM Compiler Infrastructure
5 |* This file is distributed under the University of Illinois Open Source
6 |* License. See LICENSE.TXT for details.
8 |*===----------------------------------------------------------------------===*|
10 |* This file implements the call back routines for the path profiling
11 |* instrumentation pass. This should be used with the -insert-path-profiling
14 \*===----------------------------------------------------------------------===*/
16 #include "Profiling.h"
17 #include "llvm/Analysis/ProfileInfoTypes.h"
18 #include <sys/types.h>
26 /* note that this is used for functions with large path counts,
27 but it is unlikely those paths will ALL be executed */
28 #define ARBITRARY_HASH_BIN_COUNT 100
30 typedef struct pathHashEntry_s
{
33 struct pathHashEntry_s
* next
;
36 typedef struct pathHashTable_s
{
37 pathHashEntry_t
* hashBins
[ARBITRARY_HASH_BIN_COUNT
];
42 enum ProfilingStorageType type
;
47 /* pointer to the function table allocated in the instrumented program */
51 /* write an array table to file */
52 void writeArrayTable(uint32_t fNumber
, ftEntry_t
* ft
, uint32_t* funcCount
) {
53 int outFile
= getOutFile();
54 uint32_t arrayHeaderLocation
= 0;
55 uint32_t arrayCurrentLocation
= 0;
56 uint32_t arrayIterator
= 0;
57 uint32_t functionUsed
= 0;
58 uint32_t pathCounts
= 0;
60 /* look through each entry in the array to determine whether the function
61 was executed at all */
62 for( arrayIterator
= 0; arrayIterator
< ft
->size
; arrayIterator
++ ) {
63 uint32_t pc
= ((uint32_t*)ft
->array
)[arrayIterator
];
65 /* was this path executed? */
67 PathProfileTableEntry pte
;
68 pte
.pathNumber
= arrayIterator
;
72 /* one-time initialization stuff */
74 arrayHeaderLocation
= lseek(outFile
, 0, SEEK_CUR
);
75 lseek(outFile
, sizeof(PathProfileHeader
), SEEK_CUR
);
81 if (write(outFile
, &pte
, sizeof(PathProfileTableEntry
)) < 0) {
82 fprintf(stderr
, "error: unable to write path entry to output file.\n");
88 /* If this function was executed, write the header */
90 PathProfileHeader fHeader
;
91 fHeader
.fnNumber
= fNumber
;
92 fHeader
.numEntries
= pathCounts
;
94 arrayCurrentLocation
= lseek(outFile
, 0, SEEK_CUR
);
95 lseek(outFile
, arrayHeaderLocation
, SEEK_SET
);
97 if (write(outFile
, &fHeader
, sizeof(PathProfileHeader
)) < 0) {
99 "error: unable to write function header to output file.\n");
103 lseek(outFile
, arrayCurrentLocation
, SEEK_SET
);
107 inline uint32_t hash (uint32_t key
) {
108 /* this may benifit from a proper hash function */
109 return key
%ARBITRARY_HASH_BIN_COUNT
;
112 /* output a specific function's hash table to the profile file */
113 void writeHashTable(uint32_t functionNumber
, pathHashTable_t
* hashTable
) {
114 int outFile
= getOutFile();
115 PathProfileHeader header
;
118 header
.fnNumber
= functionNumber
;
119 header
.numEntries
= hashTable
->pathCounts
;
121 if (write(outFile
, &header
, sizeof(PathProfileHeader
)) < 0) {
122 fprintf(stderr
, "error: unable to write function header to output file.\n");
126 for (i
= 0; i
< ARBITRARY_HASH_BIN_COUNT
; i
++) {
127 pathHashEntry_t
* hashEntry
= hashTable
->hashBins
[i
];
130 pathHashEntry_t
* temp
;
132 PathProfileTableEntry pte
;
133 pte
.pathNumber
= hashEntry
->pathNumber
;
134 pte
.pathCounter
= hashEntry
->pathCount
;
136 if (write(outFile
, &pte
, sizeof(PathProfileTableEntry
)) < 0) {
137 fprintf(stderr
, "error: unable to write path entry to output file.\n");
142 hashEntry
= hashEntry
->next
;
149 /* Return a pointer to this path's specific path counter */
150 inline uint32_t* getPathCounter(uint32_t functionNumber
, uint32_t pathNumber
) {
151 pathHashTable_t
* hashTable
;
152 pathHashEntry_t
* hashEntry
;
153 uint32_t index
= hash(pathNumber
);
155 if( ft
[functionNumber
-1].array
== 0)
156 ft
[functionNumber
-1].array
= calloc(sizeof(pathHashTable_t
), 1);
158 hashTable
= (pathHashTable_t
*)((ftEntry_t
*)ft
)[functionNumber
-1].array
;
159 hashEntry
= hashTable
->hashBins
[index
];
162 if (hashEntry
->pathNumber
== pathNumber
) {
163 return &hashEntry
->pathCount
;
166 hashEntry
= hashEntry
->next
;
169 hashEntry
= malloc(sizeof(pathHashEntry_t
));
170 hashEntry
->pathNumber
= pathNumber
;
171 hashEntry
->pathCount
= 0;
172 hashEntry
->next
= hashTable
->hashBins
[index
];
173 hashTable
->hashBins
[index
] = hashEntry
;
174 hashTable
->pathCounts
++;
175 return &hashEntry
->pathCount
;
178 /* Increment a specific path's count */
179 void llvm_increment_path_count (uint32_t functionNumber
, uint32_t pathNumber
) {
180 uint32_t* pathCounter
= getPathCounter(functionNumber
, pathNumber
);
181 if( *pathCounter
< 0xffffffff )
185 /* Increment a specific path's count */
186 void llvm_decrement_path_count (uint32_t functionNumber
, uint32_t pathNumber
) {
187 uint32_t* pathCounter
= getPathCounter(functionNumber
, pathNumber
);
192 * Writes out a path profile given a function table, in the following format.
195 * | <-- 32 bits --> |
196 * +-----------------+-----------------+
197 * 0x00 | profileType | functionCount |
198 * +-----------------+-----------------+
199 * 0x08 | functionNum | profileEntries | // function 1
200 * +-----------------+-----------------+
201 * 0x10 | pathNumber | pathCounter | // entry 1.1
202 * +-----------------+-----------------+
203 * 0x18 | pathNumber | pathCounter | // entry 1.2
204 * +-----------------+-----------------+
205 * ... | ... | ... | // entry 1.n
206 * +-----------------+-----------------+
207 * ... | functionNum | profileEntries | // function 2
208 * +-----------------+-----------------+
209 * ... | pathNumber | pathCounter | // entry 2.1
210 * +-----------------+-----------------+
211 * ... | pathNumber | pathCounter | // entry 2.2
212 * +-----------------+-----------------+
213 * ... | ... | ... | // entry 2.n
214 * +-----------------+-----------------+
217 static void pathProfAtExitHandler() {
218 int outFile
= getOutFile();
220 uint32_t header
[2] = { PathInfo
, 0 };
221 uint32_t headerLocation
;
222 uint32_t currentLocation
;
224 /* skip over the header for now */
225 headerLocation
= lseek(outFile
, 0, SEEK_CUR
);
226 lseek(outFile
, 2*sizeof(uint32_t), SEEK_CUR
);
228 /* Iterate through each function */
229 for( i
= 0; i
< ftSize
; i
++ ) {
230 if( ft
[i
].type
== ProfilingArray
) {
231 writeArrayTable(i
+1,&ft
[i
],header
+ 1);
233 } else if( ft
[i
].type
== ProfilingHash
) {
234 /* If the hash exists, write it to file */
236 writeHashTable(i
+1,ft
[i
].array
);
243 /* Setup and write the path profile header */
244 currentLocation
= lseek(outFile
, 0, SEEK_CUR
);
245 lseek(outFile
, headerLocation
, SEEK_SET
);
247 if (write(outFile
, header
, sizeof(header
)) < 0) {
249 "error: unable to write path profile header to output file.\n");
253 lseek(outFile
, currentLocation
, SEEK_SET
);
255 /* llvm_start_path_profiling - This is the main entry point of the path
256 * profiling library. It is responsible for setting up the atexit handler.
258 int llvm_start_path_profiling(int argc
, const char** argv
,
259 void* functionTable
, uint32_t numElements
) {
260 int Ret
= save_arguments(argc
, argv
);
262 ftSize
= numElements
;
263 atexit(pathProfAtExitHandler
);