| [4d61ad0] | 1 | #include <stdio.h>
|
|---|
| 2 | #include <stdlib.h>
|
|---|
| 3 | #include <string.h>
|
|---|
| 4 | #include <signal.h>
|
|---|
| 5 | #include <sys/types.h>
|
|---|
| 6 | #include <unistd.h>
|
|---|
| 7 | #include <time.h>
|
|---|
| 8 | #include <unistd.h>
|
|---|
| 9 |
|
|---|
| 10 | // Access to the cycle counter
|
|---|
| 11 | #define rdtscll(val) \
|
|---|
| 12 | __asm__ __volatile__ ("rdtsc" : "=A" (val))
|
|---|
| 13 |
|
|---|
| 14 | #define ENABLE_LINE_RECORDING 1
|
|---|
| 15 |
|
|---|
| 16 | unsigned long long int mytime_() {
|
|---|
| 17 | unsigned long long int time;
|
|---|
| 18 |
|
|---|
| 19 | rdtscll(time);
|
|---|
| 20 | return time ;
|
|---|
| 21 | }
|
|---|
| 22 |
|
|---|
| 23 | // Access to stacks size
|
|---|
| 24 | extern long int bigStackSize;
|
|---|
| 25 | extern long int smallstacksize_();
|
|---|
| 26 |
|
|---|
| 27 |
|
|---|
| 28 | // Declaration of the event list data structures
|
|---|
| 29 | #define ARRAY_SIZE 100000
|
|---|
| 30 | struct event {
|
|---|
| 31 | int kind;
|
|---|
| 32 | char *function;
|
|---|
| 33 | int len;
|
|---|
| 34 | unsigned long long int time;
|
|---|
| 35 | int stacksize;
|
|---|
| 36 | #ifdef ENABLE_LINE_RECORDING
|
|---|
| 37 | int line;
|
|---|
| 38 | #endif
|
|---|
| 39 | };
|
|---|
| 40 |
|
|---|
| 41 | struct list_node {
|
|---|
| 42 | struct event array[ARRAY_SIZE];
|
|---|
| 43 | struct list_node *next;
|
|---|
| 44 | };
|
|---|
| 45 | static struct list_node hdcell = { .next = 0 };
|
|---|
| 46 | static struct list_node *tlcell = &hdcell;
|
|---|
| 47 | static int cell_index = 0;
|
|---|
| 48 |
|
|---|
| 49 | // Function to traverse the list of events
|
|---|
| 50 | static void traverse_event_list(void (*process)(struct event *ev, void *data), void *data) {
|
|---|
| 51 | struct list_node *c = &hdcell;
|
|---|
| 52 |
|
|---|
| 53 | while (c) {
|
|---|
| 54 | int max = c->next ? ARRAY_SIZE : cell_index;
|
|---|
| 55 | int i;
|
|---|
| 56 | for (i = 0; i < max; ++i)
|
|---|
| 57 | process(&c->array[i], data);
|
|---|
| 58 | c = c->next;
|
|---|
| 59 | }
|
|---|
| 60 | }
|
|---|
| 61 |
|
|---|
| 62 |
|
|---|
| 63 | // Declaration of profiling functions
|
|---|
| 64 | #if 1
|
|---|
| 65 | #define profiledebug
|
|---|
| 66 | #else
|
|---|
| 67 | #define profiledebug(type) \
|
|---|
| 68 | printf("%50s %02u %022llu %010lu %li\n", buffer, type, mytime_(), bigStackSize, smallstacksize_());
|
|---|
| 69 | #endif
|
|---|
| 70 | enum { BEGIN = 1, END, ENDFWD, BEGINSNAPSHOT, ENDSNAPSHOT, ENDORIG };
|
|---|
| 71 |
|
|---|
| 72 | int init = 0;
|
|---|
| 73 | unsigned long long int beginning_of_time = 0;
|
|---|
| 74 | inline static void profile_real(char *function, int flen, int kind) {
|
|---|
| 75 | static struct list_node *new = 0;
|
|---|
| 76 | if (cell_index >= ARRAY_SIZE) {
|
|---|
| 77 | new = (struct list_node*)calloc(1, sizeof(struct list_node));
|
|---|
| 78 | tlcell->next = new;
|
|---|
| 79 | tlcell = new;
|
|---|
| 80 | new->next = 0;
|
|---|
| 81 | cell_index = 0;
|
|---|
| 82 | }
|
|---|
| 83 | static unsigned long long int time;
|
|---|
| 84 | time = mytime_();
|
|---|
| 85 | if (init == 0)
|
|---|
| 86 | beginning_of_time = time, init = 1;
|
|---|
| 87 | tlcell->array[cell_index].kind = kind;
|
|---|
| 88 | tlcell->array[cell_index].function = function;
|
|---|
| 89 | tlcell->array[cell_index].len = flen;
|
|---|
| 90 | tlcell->array[cell_index].time = time - beginning_of_time;
|
|---|
| 91 | tlcell->array[cell_index].stacksize = bigStackSize + smallstacksize_();
|
|---|
| 92 | #if 0
|
|---|
| 93 | printf("%016llu %09lu %02hhu ", time-beginning_of_time, bigStackSize + smallstacksize_(), kind);
|
|---|
| 94 | fwrite(function, 1, flen, stdout);
|
|---|
| 95 | printf("\n");
|
|---|
| 96 | #endif
|
|---|
| 97 | cell_index++;
|
|---|
| 98 | }
|
|---|
| 99 |
|
|---|
| 100 | #define declare_profile(suffix,type) \
|
|---|
| 101 | void profile##suffix##_(char *function, int flen) {\
|
|---|
| 102 | profile_real(function, flen, type);\
|
|---|
| 103 | }
|
|---|
| 104 |
|
|---|
| 105 | declare_profile(begin,BEGIN)
|
|---|
| 106 | declare_profile(end,END)
|
|---|
| 107 | declare_profile(endfwd,ENDFWD)
|
|---|
| 108 | declare_profile(beginsnapshot,BEGINSNAPSHOT)
|
|---|
| 109 | declare_profile(endsnapshot,ENDSNAPSHOT)
|
|---|
| 110 | declare_profile(endorig,ENDORIG)
|
|---|
| 111 |
|
|---|
| 112 | #ifdef ENABLE_LINE_RECORDING
|
|---|
| 113 | static int current_line_number = 0;
|
|---|
| 114 |
|
|---|
| 115 | void profileline_(int *line) {
|
|---|
| 116 | current_line_number = *line;
|
|---|
| 117 | }
|
|---|
| 118 | #endif
|
|---|
| 119 |
|
|---|
| 120 | // Hashtable data structure
|
|---|
| 121 | #define hashtbl_size 4093
|
|---|
| 122 | struct hash_cell {
|
|---|
| 123 | char *function;
|
|---|
| 124 | int len;
|
|---|
| 125 | } hashtbl[hashtbl_size];
|
|---|
| 126 | // Count of the used element in the hashtable
|
|---|
| 127 | int hashtbl_count;
|
|---|
| 128 |
|
|---|
| 129 | // Simple hash function
|
|---|
| 130 | static inline unsigned int hash(unsigned int u) {
|
|---|
| 131 | return ((u % hashtbl_size) * 1024 ) % hashtbl_size;
|
|---|
| 132 | }
|
|---|
| 133 |
|
|---|
| 134 | // Simple hash function on strings
|
|---|
| 135 | static inline unsigned int hash_string(char *string, int flen) {
|
|---|
| 136 | unsigned int ret = 0x55555555;
|
|---|
| 137 | while (flen--)
|
|---|
| 138 | ret *= ((unsigned char)*string++ * hashtbl_size);
|
|---|
| 139 | return hash(ret);
|
|---|
| 140 | }
|
|---|
| 141 |
|
|---|
| 142 | // Min macro
|
|---|
| 143 | #define min(a,b) (a < b ? a : b)
|
|---|
| 144 |
|
|---|
| 145 | // Get the id of a string address, allocate a bucket if new
|
|---|
| 146 | static int get(char *function, int flen) {
|
|---|
| 147 | int h = hash_string(function, flen);
|
|---|
| 148 | while (hashtbl[h].function) {
|
|---|
| 149 | if (strncmp(hashtbl[h].function, function, min(flen, hashtbl[h].len)) == 0)
|
|---|
| 150 | break;
|
|---|
| 151 | h = hash(h);
|
|---|
| 152 | }
|
|---|
| 153 | hashtbl[h].function = function;
|
|---|
| 154 | hashtbl[h].len = flen;
|
|---|
| 155 | return h;
|
|---|
| 156 | }
|
|---|
| 157 |
|
|---|
| 158 | // Functions to serialize integers and known length strings
|
|---|
| 159 | static inline void fwrite_int(FILE *f, int i) {
|
|---|
| 160 | fwrite(&i, sizeof(int), 1, f);
|
|---|
| 161 | }
|
|---|
| 162 | static inline void fwrite_llint(FILE *f, unsigned long long int i) {
|
|---|
| 163 | fwrite(&i, sizeof(unsigned long long int), 1, f);
|
|---|
| 164 | }
|
|---|
| 165 | static inline void fwrite_string(FILE *f, char *str, int len) {
|
|---|
| 166 | fwrite_int(f, len);
|
|---|
| 167 | fwrite(str, (unsigned int) len, 1, f);
|
|---|
| 168 | }
|
|---|
| 169 |
|
|---|
| 170 | // Function to build the hashtable of function names
|
|---|
| 171 | static void add_event_to_hashtable(struct event *ev, void *data);
|
|---|
| 172 | static void build_hashtable() {
|
|---|
| 173 |
|
|---|
| 174 | // Initialize the hashtable
|
|---|
| 175 | memset(hashtbl, 0, sizeof(struct hash_cell)*hashtbl_size);
|
|---|
| 176 | /** Fill the hashtbl */
|
|---|
| 177 | traverse_event_list(add_event_to_hashtable, 0);
|
|---|
| 178 | /** Compute the size of the hashtbl */
|
|---|
| 179 | hashtbl_count = 0;
|
|---|
| 180 | int i;
|
|---|
| 181 | for (i=0; i < hashtbl_size; ++i)
|
|---|
| 182 | if (hashtbl[i].function)
|
|---|
| 183 | hashtbl_count++;
|
|---|
| 184 | }
|
|---|
| 185 | static void add_event_to_hashtable(struct event *ev, void *data) {
|
|---|
| 186 | int h = get(ev->function, ev->len);
|
|---|
| 187 | }
|
|---|
| 188 |
|
|---|
| 189 |
|
|---|
| 190 | // Serialize event list into a file named tapenade.prof
|
|---|
| 191 | struct print_args {
|
|---|
| 192 | FILE *prof;
|
|---|
| 193 | struct event **stack;
|
|---|
| 194 | int *stack_counter;
|
|---|
| 195 | };
|
|---|
| 196 | static void print_an_event(struct event *ev, void *data);
|
|---|
| 197 | void printprofile_() {
|
|---|
| 198 | int i = 0;
|
|---|
| 199 | FILE *prof = fopen("tapenade.prof", "w");
|
|---|
| 200 | if (!prof) {
|
|---|
| 201 | perror("Can't open tapenade.prof");
|
|---|
| 202 | exit(1);
|
|---|
| 203 | }
|
|---|
| 204 | // Compress the output;
|
|---|
| 205 | // Generate a hashtable of the functions name
|
|---|
| 206 | // use it to make a map from function name
|
|---|
| 207 | // to numeric id
|
|---|
| 208 | build_hashtable();
|
|---|
| 209 |
|
|---|
| 210 | // Position at the beginning
|
|---|
| 211 | fseek(prof, 0, SEEK_SET);
|
|---|
| 212 |
|
|---|
| 213 | // Dump the hash table
|
|---|
| 214 | fwrite_int(prof, hashtbl_count);
|
|---|
| 215 | for (i=0; i < hashtbl_size; ++i)
|
|---|
| 216 | if (hashtbl[i].function) {
|
|---|
| 217 | fwrite_int(prof, i);
|
|---|
| 218 | char *string = hashtbl[i].function;
|
|---|
| 219 | int string_length = hashtbl[i].len;
|
|---|
| 220 | fwrite_string(prof, string, string_length);
|
|---|
| 221 | }
|
|---|
| 222 |
|
|---|
| 223 | // Dump the events
|
|---|
| 224 | struct list_node *c = &hdcell;
|
|---|
| 225 | struct event *stack[1000];
|
|---|
| 226 | int stack_counter = -1;
|
|---|
| 227 | struct print_args args = {
|
|---|
| 228 | .prof = prof,
|
|---|
| 229 | .stack = stack,
|
|---|
| 230 | .stack_counter = &stack_counter
|
|---|
| 231 | };
|
|---|
| 232 | traverse_event_list(print_an_event, &args);
|
|---|
| 233 |
|
|---|
| 234 | // For program that aborts too abruptly ( with STOP )
|
|---|
| 235 | // Use the return stack image to recreate EXIT events
|
|---|
| 236 | for (i=stack_counter; i>-1;i--) {
|
|---|
| 237 | struct event *cur = stack[i];
|
|---|
| 238 | int h = get(cur->function, cur->len);
|
|---|
| 239 | fwrite_int(prof, h);
|
|---|
| 240 | fwrite_int(prof, 2); // Explicit ending
|
|---|
| 241 | fwrite_llint(prof, cur->time);
|
|---|
| 242 | fwrite_int(prof, cur->stacksize);
|
|---|
| 243 | }
|
|---|
| 244 | fclose(prof);
|
|---|
| 245 | }
|
|---|
| 246 | void halt_();
|
|---|
| 247 | // Utility function for printprofile
|
|---|
| 248 | static void print_an_event(struct event *ev, void *data) {
|
|---|
| 249 | struct print_args *args = (struct print_args*)data;
|
|---|
| 250 | static unsigned long long int last_time = 0;
|
|---|
| 251 |
|
|---|
| 252 | int h = get(ev->function, ev->len);
|
|---|
| 253 | // Keep trace of the return stack depth and values
|
|---|
| 254 | switch (ev->kind) {
|
|---|
| 255 | case 1:
|
|---|
| 256 | *(args->stack_counter) += 1;
|
|---|
| 257 | args->stack[*(args->stack_counter)] = ev;
|
|---|
| 258 | break;
|
|---|
| 259 | case 2:
|
|---|
| 260 | *(args->stack_counter) -= 1;
|
|---|
| 261 | break;
|
|---|
| 262 | }
|
|---|
| 263 | //DEBUG printf("Time: %llu\n", ev->time - begin_time);
|
|---|
| 264 | if (last_time && ev->time <= last_time) {
|
|---|
| 265 | printf("Erreur time <= last_time: %llu <= %llu\n", time, last_time);
|
|---|
| 266 | halt_();
|
|---|
| 267 | }
|
|---|
| 268 | fwrite_int(args->prof, h);
|
|---|
| 269 | fwrite_int(args->prof, ev->kind);
|
|---|
| 270 | fwrite_llint(args->prof, ev->time);
|
|---|
| 271 | fwrite_int(args->prof, ev->stacksize);
|
|---|
| 272 | last_time = ev->time;
|
|---|
| 273 | }
|
|---|
| 274 |
|
|---|
| 275 | #include <signal.h>
|
|---|
| 276 | void halt_() {
|
|---|
| 277 | kill(getpid(), SIGTRAP);
|
|---|
| 278 | }
|
|---|