2009-08-18 Christian Hergert <chris@dronelabs.com>
[mono.git] / mono / utils / mono-counters.c
1 #include <stdlib.h>
2 #include <glib.h>
3 #include "mono-counters.h"
4
5 typedef struct _MonoCounter MonoCounter;
6
7 struct _MonoCounter {
8         MonoCounter *next;
9         const char *name;
10         void *addr;
11         int type;
12 };
13
14 static MonoCounter *counters = NULL;
15 static int valid_mask = 0;
16 static int set_mask = 0;
17
18 /**
19  * mono_counters_enable:
20  * @section_mask: a mask listing the sections that will be displayed
21  *
22  * This is used to track which counters will be displayed.
23  */
24 void
25 mono_counters_enable (int section_mask)
26 {
27         valid_mask = section_mask & MONO_COUNTER_SECTION_MASK;
28 }
29
30 /**
31  * mono_counters_register:
32  * @name: The name for this counters.
33  * @type: One of the possible MONO_COUNTER types, or MONO_COUNTER_CALLBACK for a function pointer.
34  * @addr: The address to register.
35  *
36  * Register addr as the address of a counter of type type.
37  * Note that @name must be a valid string at all times until
38  * mono_counters_dump () is called.
39  *
40  * It may be a function pointer if MONO_COUNTER_CALLBACK is specified:
41  * the function should return the value and take no arguments.
42  */
43 void 
44 mono_counters_register (const char* name, int type, void *addr)
45 {
46         MonoCounter *counter;
47         if (!(type & valid_mask))
48                 return;
49         counter = malloc (sizeof (MonoCounter));
50         if (!counter)
51                 return;
52         counter->name = name;
53         counter->type = type;
54         counter->addr = addr;
55         counter->next = NULL;
56
57         set_mask |= type;
58
59         /* Append */
60         if (counters) {
61                 MonoCounter *item = counters;
62                 while (item->next)
63                         item = item->next;
64                 item->next = counter;
65         } else {
66                 counters = counter;
67         }
68 }
69
70 typedef int (*IntFunc) (void);
71 typedef guint (*UIntFunc) (void);
72 typedef gint64 (*LongFunc) (void);
73 typedef guint64 (*ULongFunc) (void);
74 typedef gssize (*PtrFunc) (void);
75 typedef double (*DoubleFunc) (void);
76 typedef char* (*StrFunc) (void);
77
78 #define ENTRY_FMT "%-36s: "
79 static void
80 dump_counter (MonoCounter *counter, FILE *outfile) {
81         int intval;
82         guint uintval;
83         gint64 int64val;
84         guint64 uint64val;
85         gssize wordval;
86         double dval;
87         const char *str;
88         switch (counter->type & MONO_COUNTER_TYPE_MASK) {
89         case MONO_COUNTER_INT:
90               if (counter->type & MONO_COUNTER_CALLBACK)
91                       intval = ((IntFunc)counter->addr) ();
92               else
93                       intval = *(int*)counter->addr;
94               fprintf (outfile, ENTRY_FMT "%d\n", counter->name, intval);
95               break;
96         case MONO_COUNTER_UINT:
97               if (counter->type & MONO_COUNTER_CALLBACK)
98                       uintval = ((UIntFunc)counter->addr) ();
99               else
100                       uintval = *(guint*)counter->addr;
101               fprintf (outfile, ENTRY_FMT "%u\n", counter->name, uintval);
102               break;
103         case MONO_COUNTER_LONG:
104               if (counter->type & MONO_COUNTER_CALLBACK)
105                       int64val = ((LongFunc)counter->addr) ();
106               else
107                       int64val = *(gint64*)counter->addr;
108               fprintf (outfile, ENTRY_FMT "%lld\n", counter->name, (long long)int64val);
109               break;
110         case MONO_COUNTER_ULONG:
111               if (counter->type & MONO_COUNTER_CALLBACK)
112                       uint64val = ((ULongFunc)counter->addr) ();
113               else
114                       uint64val = *(guint64*)counter->addr;
115               fprintf (outfile, ENTRY_FMT "%llu\n", counter->name, (unsigned long long)uint64val);
116               break;
117         case MONO_COUNTER_WORD:
118               if (counter->type & MONO_COUNTER_CALLBACK)
119                       wordval = ((PtrFunc)counter->addr) ();
120               else
121                       wordval = *(gssize*)counter->addr;
122 #if SIZEOF_VOID_P == 8
123               fprintf (outfile, ENTRY_FMT "%lld\n", counter->name, (gint64)wordval);
124 #else
125               fprintf (outfile, ENTRY_FMT "%d\n", counter->name, (gint)wordval);
126 #endif
127               break;
128         case MONO_COUNTER_DOUBLE:
129               if (counter->type & MONO_COUNTER_CALLBACK)
130                       dval = ((DoubleFunc)counter->addr) ();
131               else
132                       dval = *(double*)counter->addr;
133               fprintf (outfile, ENTRY_FMT "%.2f\n", counter->name, dval);
134               break;
135         case MONO_COUNTER_STRING:
136               if (counter->type & MONO_COUNTER_CALLBACK)
137                       str = ((StrFunc)counter->addr) ();
138               else
139                       str = *(char**)counter->addr;
140               fprintf (outfile, ENTRY_FMT "%s\n", counter->name, str);
141               break;
142         }
143 }
144
145 static const char
146 section_names [][10] = {
147         "JIT",
148         "GC",
149         "Metadata",
150         "Generics",
151         "Security"
152 };
153
154 static void
155 mono_counters_dump_section (int section, FILE *outfile)
156 {
157         MonoCounter *counter = counters;
158         while (counter) {
159                 if (counter->type & section)
160                         dump_counter (counter, outfile);
161                 counter = counter->next;
162         }
163 }
164
165 /**
166  * mono_counters_dump:
167  * @section_mask: The sections to dump counters for
168  * @outfile: a FILE to dump the results to
169  *
170  * Displays the counts of all the enabled counters registered. 
171  */
172 void
173 mono_counters_dump (int section_mask, FILE *outfile)
174 {
175         int i, j;
176         section_mask &= valid_mask;
177         if (!counters)
178                 return;
179         for (j = 0, i = MONO_COUNTER_JIT; i < MONO_COUNTER_LAST_SECTION; j++, i <<= 1) {
180                 if ((section_mask & i) && (set_mask & i)) {
181                         fprintf (outfile, "\n%s statistics\n", section_names [j]);
182                         mono_counters_dump_section (i, outfile);
183                 }
184         }
185 }
186
187 /**
188  * mono_counters_cleanup:
189  *
190  * Perform any needed cleanup at process exit.
191  */
192 void
193 mono_counters_cleanup (void)
194 {
195         MonoCounter *counter = counters;
196         while (counter) {
197                 MonoCounter *tmp = counters;
198                 counter = counter->next;
199                 free (tmp);
200         }
201         counters = NULL;
202 }
203