becopyheur2: Cache the admissible registers eagerly.
[libfirm] / support / libfirmprof / instrument.c
1 /**
2  * Helper code to output instrumentation results.
3  * This file is a supplement to libFirm. It is public domain.
4  *  @author Matthias Braun, Steven Schaefer
5  */
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdlib.h>
9
10 /* Prevent the compiler from mangling the name of this function. */
11 void __init_firmprof(const char*, unsigned int*, size_t)
12      asm("__init_firmprof");
13
14 typedef struct _profile_counter_t {
15         const char *filename;
16         unsigned   *counters;
17         unsigned    len;
18         struct _profile_counter_t *next;
19 } profile_counter_t;
20
21 static profile_counter_t *counters = NULL;
22
23 /**
24  * Write counter values to profiling output file.
25  * We define our output format to be a sequence of 32-bit unsigned integer
26  * values stored in little endian format.
27  */
28 void write_little_endian(unsigned *counter, unsigned len, FILE *f)
29 {
30         unsigned i;
31
32         for (i = 0; i < len; ++i) {
33                 unsigned      v = counter[i];
34                 unsigned char bytes[4];
35
36                 bytes[0] = ((v >>  0) & 0xff);
37                 bytes[1] = ((v >>  8) & 0xff);
38                 bytes[2] = ((v >> 16) & 0xff);
39                 bytes[3] = ((v >> 24) & 0xff);
40
41                 fwrite(bytes, 1, 4, f);
42         }
43 }
44
45 static void write_profiles(void)
46 {
47         profile_counter_t *counter = counters;
48         while (counter != NULL) {
49                 profile_counter_t *next = counter->next;
50                 FILE *f = fopen(counter->filename, "wb");
51                 if (f == NULL) {
52                         perror("Warning: couldn't open file for writing profiling data");
53                 } else {
54                         fputs("firmprof", f);
55                         write_little_endian(counter->counters, counter->len, f);
56                         fclose(f);
57                 }
58                 free(counter);
59                 counter = next;
60         }
61 }
62
63 /**
64  * Register a new profile counter. This is called by separate constructors
65  * for each translation unit. Incidentally, referring to this function as
66  * "__init_firmprof" is perfectly linker friendly.
67  */
68 void __init_firmprof(const char *filename,
69                       unsigned int *counts, size_t len)
70 {
71         static int initialized = 0;
72         profile_counter_t *counter;
73
74         if (!initialized) {
75                 initialized = 1;
76                 atexit(write_profiles);
77         }
78
79         counter = (profile_counter_t*) malloc(sizeof(*counter));
80         if (counter == NULL)
81                 return;
82
83         counter->filename = filename;
84         counter->counters = counts;
85         counter->next     = counters;
86         counter->len      = len;
87
88         counters = counter;
89 }