e3d694a92fe148b90eb024b611df99c3605b0894
[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 #include "xmalloc.h"
42
43 #define MAX_CTX 128
44
45 typedef struct {
46         char key[32];
47         char value[96];
48         unsigned hash;
49 } ctx_t;
50
51 static ctx_t ctx_stack[MAX_CTX];
52
53 static unsigned long time_in_ev = 0;
54 static int ctx_sp     = -1;
55 static FILE *file_ev  = NULL;
56
57 static lc_timer_t *timer = NULL;
58
59 int stat_ev_enabled = 0;
60
61 typedef struct print_ev_t {
62         char               filter[128];
63         struct print_ev_t *next;
64 } print_ev_t;
65
66 static print_ev_t *print_events                = NULL;
67 static int         ctx_switch_since_last_print = 0;
68
69 #define get_time() lc_timer_elapsed_usec(timer)
70
71 void stat_ev_ctx_push(const char *key, const char *value)
72 {
73         if (file_ev) {
74                 unsigned long start = get_time();
75                 ctx_t *ctx    = &ctx_stack[ctx_sp + 1];
76                 unsigned hash = firm_fnv_hash_str(key);
77
78                 hash = HASH_COMBINE(hash, firm_fnv_hash_str(value));
79                 if (ctx_sp >= 0)
80                         hash = HASH_COMBINE(hash, ctx_stack[ctx_sp].hash);
81
82                 snprintf(ctx->key, array_size(ctx->key), "%s", key);
83                 snprintf(ctx->value, array_size(ctx->value), "%s", value);
84                 ctx->hash  = hash | 1;
85                 ++ctx_sp;
86
87                 fprintf(file_ev, "P %10x %30s %30s\n", ctx->hash, ctx->key, ctx->value);
88
89                 ctx_switch_since_last_print = 1;
90
91                 time_in_ev += get_time() - start;
92         }
93 }
94
95 void stat_ev_ctx_push_fobj(const char *key, const void *firm_object)
96 {
97         if (file_ev) {
98                 char buf[96];
99                 ir_snprintf(buf, sizeof(buf), "%+F", firm_object);
100                 stat_ev_ctx_push(key, buf);
101         }
102 }
103
104 void stat_ev_ctx_pop(void)
105 {
106         if (ctx_sp >= 0) {
107                 if (file_ev) {
108                         fprintf(file_ev, "O %10x\n", ctx_stack[ctx_sp].hash);
109                         ctx_switch_since_last_print = 1;
110                 }
111                 --ctx_sp;
112         }
113 }
114
115 static void maybe_print_context(void)
116 {
117         int i;
118
119         if(!ctx_switch_since_last_print)
120                 return;
121
122         for(i = 0; i <= ctx_sp; ++i) {
123                 if(i > 0)
124                         fputc(':', stderr);
125                 fputs(ctx_stack[i].value, stderr);
126         }
127         fputc('\n', stderr);
128         ctx_switch_since_last_print = 0;
129 }
130
131 void stat_ev_emit(const char *name, double value)
132 {
133         if (file_ev) {
134                 unsigned long start = get_time();
135                 unsigned         id = ctx_sp >= 0 ? ctx_stack[ctx_sp].hash : 0;
136
137                 fprintf(file_ev, "E %10x %30s %30f %10ld %10ld\n", id, name, value, start, time_in_ev);
138
139                 if(print_events != NULL) {
140                         print_ev_t *print_ev = print_events;
141                         while(print_ev != NULL) {
142                                 /* maybe wanna use regexes instead of strcmp? */
143                                 if(strstr(name, print_ev->filter) != NULL) {
144                                         maybe_print_context();
145                                         fprintf(stderr, "\t%20s  %30f\n", name, value);
146                                 }
147
148                                 print_ev = print_ev->next;
149                         }
150                 }
151
152                 time_in_ev += get_time() - start;
153         }
154 }
155
156 void stat_ev_begin(const char *prefix)
157 {
158         char buf[512];
159
160         snprintf(buf, sizeof(buf), "%s.ev", prefix);
161
162         stat_ev_enabled = 1;
163         ctx_sp          = -1;
164         time_in_ev      = 0;
165         print_events    = NULL;
166         file_ev         = fopen(buf, "wt");
167         timer           = lc_timer_register("stat_ev", "firm stat event timer");
168
169         lc_timer_start(timer);
170 }
171
172 void stat_ev_end(void)
173 {
174         print_ev_t *print_ev, *next;
175
176         if (timer)
177                 lc_timer_stop(timer);
178         if (file_ev)
179                 fclose(file_ev);
180
181         for (print_ev = print_events; print_ev != NULL; print_ev = next) {
182                 next = print_ev->next;
183                 free(print_ev);
184         }
185 }
186
187 void stat_ev_flush(void)
188 {
189         unsigned long start = get_time();
190         if (file_ev)
191                 fflush(file_ev);
192         time_in_ev += get_time() - start;
193 }
194
195 void stat_ev_print(const char *filter)
196 {
197         size_t len;
198         print_ev_t *print_ev = xmalloc(sizeof(print_ev[0]));
199
200         memset(print_ev, 0, sizeof(print_ev[0]));
201
202         len = strlen(filter) + 1;
203         if (len >= sizeof(print_ev->filter)) {
204                 fprintf(stderr, "Warning: capping event filter (too long)");
205                 len = sizeof(print_ev->filter);
206         }
207         memcpy(print_ev->filter, filter, len);
208         print_ev->filter[len-1] = 0;
209
210         print_ev->next = print_events;
211         print_events   = print_ev;
212 }