add support to print some events in a human readable format to stderr
[libfirm] / ir / stat / statev.c
1 /*
2  * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief       Statistic events.
23  * @author      Sebastian Hack
24  * @date        17.06.2007
25  * @version     $Id$
26  */
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <assert.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35
36 #include <libcore/lc_timing.h>
37
38 #include "util.h"
39 #include "hashptr.h"
40 #include "irprintf.h"
41
42 #define MAX_CTX 128
43
44 typedef struct {
45         char key[32];
46         char value[96];
47         unsigned hash;
48 } ctx_t;
49
50 static ctx_t ctx_stack[MAX_CTX];
51
52 static unsigned long time_in_ev = 0;
53 static int ctx_sp     = -1;
54 static FILE *file_ev  = NULL;
55
56 static lc_timer_t *timer = NULL;
57
58 int stat_ev_enabled = 0;
59
60 typedef struct print_ev_t {
61         char               filter[128];
62         struct print_ev_t *next;
63 } print_ev_t;
64
65 static print_ev_t *print_events                = NULL;
66 static int         ctx_switch_since_last_print = 0;
67
68 #define get_time() lc_timer_elapsed_usec(timer)
69
70 void stat_ev_ctx_push(const char *key, const char *value)
71 {
72         if (file_ev) {
73                 unsigned long start = get_time();
74                 ctx_t *ctx    = &ctx_stack[ctx_sp + 1];
75                 unsigned hash = firm_fnv_hash_str(key);
76
77                 hash = HASH_COMBINE(hash, firm_fnv_hash_str(value));
78                 if (ctx_sp >= 0)
79                         hash = HASH_COMBINE(hash, ctx_stack[ctx_sp].hash);
80
81                 snprintf(ctx->key, array_size(ctx->key), "%s", key);
82                 snprintf(ctx->value, array_size(ctx->value), "%s", value);
83                 ctx->hash  = hash | 1;
84                 ++ctx_sp;
85
86                 fprintf(file_ev, "P %10x %30s %30s\n", ctx->hash, ctx->key, ctx->value);
87
88                 ctx_switch_since_last_print = 1;
89
90                 time_in_ev += get_time() - start;
91         }
92 }
93
94 void stat_ev_ctx_push_fobj(const char *key, const void *firm_object)
95 {
96         if (file_ev) {
97                 char buf[96];
98                 ir_snprintf(buf, sizeof(buf), "%+F", firm_object);
99                 stat_ev_ctx_push(key, buf);
100         }
101 }
102
103 void stat_ev_ctx_pop(void)
104 {
105         if (ctx_sp >= 0) {
106                 if (file_ev) {
107                         fprintf(file_ev, "O %10x\n", ctx_stack[ctx_sp].hash);
108                         ctx_switch_since_last_print = 1;
109                 }
110                 --ctx_sp;
111         }
112 }
113
114 static void maybe_print_context(void)
115 {
116         int i;
117
118         if(!ctx_switch_since_last_print)
119                 return;
120
121         for(i = 0; i <= ctx_sp; ++i) {
122                 if(i > 0)
123                         fputc(':', stderr);
124                 fputs(ctx_stack[i].value, stderr);
125         }
126         fputc('\n', stderr);
127         ctx_switch_since_last_print = 0;
128 }
129
130 void stat_ev_emit(const char *name, double value)
131 {
132         if (file_ev) {
133                 unsigned long start = get_time();
134                 unsigned         id = ctx_sp >= 0 ? ctx_stack[ctx_sp].hash : 0;
135
136                 fprintf(file_ev, "E %10x %30s %30f %10ld %10ld\n", id, name, value, start, time_in_ev);
137
138                 if(print_events != NULL) {
139                         print_ev_t *print_ev = print_events;
140                         while(print_ev != NULL) {
141                                 /* maybe wanna use regexes instead of strcmp? */
142                                 if(strstr(name, print_ev->filter) != NULL) {
143                                         maybe_print_context();
144                                         fprintf(stderr, "\t%20s  %30f\n", name, value);
145                                 }
146
147                                 print_ev = print_ev->next;
148                         }
149                 }
150
151                 time_in_ev += get_time() - start;
152         }
153 }
154
155 void stat_ev_begin(const char *prefix)
156 {
157         char buf[512];
158
159         snprintf(buf, sizeof(buf), "%s.ev", prefix);
160
161         stat_ev_enabled = 1;
162         ctx_sp          = -1;
163         time_in_ev      = 0;
164         print_events    = NULL;
165         file_ev         = fopen(buf, "wt");
166         timer           = lc_timer_register("stat_ev", "firm stat event timer");
167
168         lc_timer_start(timer);
169 }
170
171 void stat_ev_end(void)
172 {
173         if (timer)
174                 lc_timer_stop(timer);
175         if (file_ev)
176                 fclose(file_ev);
177
178         print_ev_t *print_ev = print_events;
179         while(print_ev != NULL) {
180                 print_ev_t *next = print_ev->next;
181                 free(print_ev);
182                 print_ev = next;
183         }
184 }
185
186 void stat_ev_flush(void)
187 {
188         unsigned long start = get_time();
189         if (file_ev)
190                 fflush(file_ev);
191         time_in_ev += get_time() - start;
192 }
193
194 void stat_ev_print(const char *filter)
195 {
196         print_ev_t *print_ev = malloc(sizeof(print_ev[0]));
197         memset(print_ev, 0, sizeof(print_ev[0]));
198
199         size_t len = strlen(filter) + 1;
200         if(len >= sizeof(print_ev->filter)) {
201                 fprintf(stderr, "Warning: capping event filter (too long)");
202                 len = sizeof(print_ev->filter);
203         }
204         memcpy(print_ev->filter, filter, len);
205         print_ev->filter[len-1] = 0;
206
207         print_ev->next = print_events;
208         print_events   = print_ev;
209 }