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