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 "llvm/Support/DataTypes.h"
19 #include <sys/types.h>
20 #if !defined(_MSC_VER) && !defined(__MINGW32__)
29 /* Must use __inline in Microsoft C */
31 #define inline __inline
34 /* note that this is used for functions with large path counts,
35 but it is unlikely those paths will ALL be executed */
36 #define ARBITRARY_HASH_BIN_COUNT 100
38 typedef struct pathHashEntry_s
{
41 struct pathHashEntry_s
* next
;
44 typedef struct pathHashTable_s
{
45 pathHashEntry_t
* hashBins
[ARBITRARY_HASH_BIN_COUNT
];
50 enum ProfilingStorageType type
;
55 /* pointer to the function table allocated in the instrumented program */
59 /* write an array table to file */
60 void writeArrayTable(uint32_t fNumber
, ftEntry_t
* ft
, uint32_t* funcCount
) {
61 int outFile
= getOutFile();
62 uint32_t arrayHeaderLocation
= 0;
63 uint32_t arrayCurrentLocation
= 0;
64 uint32_t arrayIterator
= 0;
65 uint32_t functionUsed
= 0;
66 uint32_t pathCounts
= 0;
68 /* look through each entry in the array to determine whether the function
69 was executed at all */
70 for( arrayIterator
= 0; arrayIterator
< ft
->size
; arrayIterator
++ ) {
71 uint32_t pc
= ((uint32_t*)ft
->array
)[arrayIterator
];
73 /* was this path executed? */
75 PathProfileTableEntry pte
;
76 pte
.pathNumber
= arrayIterator
;
80 /* one-time initialization stuff */
82 arrayHeaderLocation
= lseek(outFile
, 0, SEEK_CUR
);
83 lseek(outFile
, sizeof(PathProfileHeader
), SEEK_CUR
);
89 if (write(outFile
, &pte
, sizeof(PathProfileTableEntry
)) < 0) {
90 fprintf(stderr
, "error: unable to write path entry to output file.\n");
96 /* If this function was executed, write the header */
98 PathProfileHeader fHeader
;
99 fHeader
.fnNumber
= fNumber
;
100 fHeader
.numEntries
= pathCounts
;
102 arrayCurrentLocation
= lseek(outFile
, 0, SEEK_CUR
);
103 lseek(outFile
, arrayHeaderLocation
, SEEK_SET
);
105 if (write(outFile
, &fHeader
, sizeof(PathProfileHeader
)) < 0) {
107 "error: unable to write function header to output file.\n");
111 lseek(outFile
, arrayCurrentLocation
, SEEK_SET
);
115 static inline uint32_t hash (uint32_t key
) {
116 /* this may benefit from a proper hash function */
117 return key
%ARBITRARY_HASH_BIN_COUNT
;
120 /* output a specific function's hash table to the profile file */
121 void writeHashTable(uint32_t functionNumber
, pathHashTable_t
* hashTable
) {
122 int outFile
= getOutFile();
123 PathProfileHeader header
;
126 header
.fnNumber
= functionNumber
;
127 header
.numEntries
= hashTable
->pathCounts
;
129 if (write(outFile
, &header
, sizeof(PathProfileHeader
)) < 0) {
130 fprintf(stderr
, "error: unable to write function header to output file.\n");
134 for (i
= 0; i
< ARBITRARY_HASH_BIN_COUNT
; i
++) {
135 pathHashEntry_t
* hashEntry
= hashTable
->hashBins
[i
];
138 pathHashEntry_t
* temp
;
140 PathProfileTableEntry pte
;
141 pte
.pathNumber
= hashEntry
->pathNumber
;
142 pte
.pathCounter
= hashEntry
->pathCount
;
144 if (write(outFile
, &pte
, sizeof(PathProfileTableEntry
)) < 0) {
145 fprintf(stderr
, "error: unable to write path entry to output file.\n");
150 hashEntry
= hashEntry
->next
;
157 /* Return a pointer to this path's specific path counter */
158 static inline uint32_t* getPathCounter(uint32_t functionNumber
,
159 uint32_t pathNumber
) {
160 pathHashTable_t
* hashTable
;
161 pathHashEntry_t
* hashEntry
;
162 uint32_t index
= hash(pathNumber
);
164 if( ft
[functionNumber
-1].array
== 0)
165 ft
[functionNumber
-1].array
= calloc(sizeof(pathHashTable_t
), 1);
167 hashTable
= (pathHashTable_t
*)((ftEntry_t
*)ft
)[functionNumber
-1].array
;
168 hashEntry
= hashTable
->hashBins
[index
];
171 if (hashEntry
->pathNumber
== pathNumber
) {
172 return &hashEntry
->pathCount
;
175 hashEntry
= hashEntry
->next
;
178 hashEntry
= malloc(sizeof(pathHashEntry_t
));
179 hashEntry
->pathNumber
= pathNumber
;
180 hashEntry
->pathCount
= 0;
181 hashEntry
->next
= hashTable
->hashBins
[index
];
182 hashTable
->hashBins
[index
] = hashEntry
;
183 hashTable
->pathCounts
++;
184 return &hashEntry
->pathCount
;
187 /* Increment a specific path's count */
188 void llvm_increment_path_count (uint32_t functionNumber
, uint32_t pathNumber
) {
189 uint32_t* pathCounter
= getPathCounter(functionNumber
, pathNumber
);
190 if( *pathCounter
< 0xffffffff )
194 /* Increment a specific path's count */
195 void llvm_decrement_path_count (uint32_t functionNumber
, uint32_t pathNumber
) {
196 uint32_t* pathCounter
= getPathCounter(functionNumber
, pathNumber
);
201 * Writes out a path profile given a function table, in the following format.
204 * | <-- 32 bits --> |
205 * +-----------------+-----------------+
206 * 0x00 | profileType | functionCount |
207 * +-----------------+-----------------+
208 * 0x08 | functionNum | profileEntries | // function 1
209 * +-----------------+-----------------+
210 * 0x10 | pathNumber | pathCounter | // entry 1.1
211 * +-----------------+-----------------+
212 * 0x18 | pathNumber | pathCounter | // entry 1.2
213 * +-----------------+-----------------+
214 * ... | ... | ... | // entry 1.n
215 * +-----------------+-----------------+
216 * ... | functionNum | profileEntries | // function 2
217 * +-----------------+-----------------+
218 * ... | pathNumber | pathCounter | // entry 2.1
219 * +-----------------+-----------------+
220 * ... | pathNumber | pathCounter | // entry 2.2
221 * +-----------------+-----------------+
222 * ... | ... | ... | // entry 2.n
223 * +-----------------+-----------------+
226 static void pathProfAtExitHandler(void) {
227 int outFile
= getOutFile();
229 uint32_t header
[2] = { PathInfo
, 0 };
230 uint32_t headerLocation
;
231 uint32_t currentLocation
;
233 /* skip over the header for now */
234 headerLocation
= lseek(outFile
, 0, SEEK_CUR
);
235 lseek(outFile
, 2*sizeof(uint32_t), SEEK_CUR
);
237 /* Iterate through each function */
238 for( i
= 0; i
< ftSize
; i
++ ) {
239 if( ft
[i
].type
== ProfilingArray
) {
240 writeArrayTable(i
+1,&ft
[i
],header
+ 1);
242 } else if( ft
[i
].type
== ProfilingHash
) {
243 /* If the hash exists, write it to file */
245 writeHashTable(i
+1,ft
[i
].array
);
252 /* Setup and write the path profile header */
253 currentLocation
= lseek(outFile
, 0, SEEK_CUR
);
254 lseek(outFile
, headerLocation
, SEEK_SET
);
256 if (write(outFile
, header
, sizeof(header
)) < 0) {
258 "error: unable to write path profile header to output file.\n");
262 lseek(outFile
, currentLocation
, SEEK_SET
);
264 /* llvm_start_path_profiling - This is the main entry point of the path
265 * profiling library. It is responsible for setting up the atexit handler.
267 int llvm_start_path_profiling(int argc
, const char** argv
,
268 void* functionTable
, uint32_t numElements
) {
269 int Ret
= save_arguments(argc
, argv
);
271 ftSize
= numElements
;
272 atexit(pathProfAtExitHandler
);