Merge pull request #901 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mono / utils / mono-counters.c
1 /*
2  * Copyright 2006-2010 Novell
3  * Copyright 2011 Xamarin Inc
4  */
5
6 #include <stdlib.h>
7 #include <glib.h>
8 #include "mono-counters.h"
9
10 typedef struct _MonoCounter MonoCounter;
11
12 struct _MonoCounter {
13         MonoCounter *next;
14         const char *name;
15         void *addr;
16         int type;
17 };
18
19 static MonoCounter *counters = NULL;
20 static int valid_mask = 0;
21 static int set_mask = 0;
22
23 /**
24  * mono_counters_enable:
25  * @section_mask: a mask listing the sections that will be displayed
26  *
27  * This is used to track which counters will be displayed.
28  */
29 void
30 mono_counters_enable (int section_mask)
31 {
32         valid_mask = section_mask & MONO_COUNTER_SECTION_MASK;
33 }
34
35 /**
36  * mono_counters_register:
37  * @name: The name for this counters.
38  * @type: One of the possible MONO_COUNTER types, or MONO_COUNTER_CALLBACK for a function pointer.
39  * @addr: The address to register.
40  *
41  * Register addr as the address of a counter of type type.
42  * Note that @name must be a valid string at all times until
43  * mono_counters_dump () is called.
44  *
45  * It may be a function pointer if MONO_COUNTER_CALLBACK is specified:
46  * the function should return the value and take no arguments.
47  */
48 void 
49 mono_counters_register (const char* name, int type, void *addr)
50 {
51         MonoCounter *counter;
52         if (!(type & valid_mask))
53                 return;
54         counter = malloc (sizeof (MonoCounter));
55         if (!counter)
56                 return;
57         counter->name = name;
58         counter->type = type;
59         counter->addr = addr;
60         counter->next = NULL;
61
62         set_mask |= type;
63
64         /* Append */
65         if (counters) {
66                 MonoCounter *item = counters;
67                 while (item->next)
68                         item = item->next;
69                 item->next = counter;
70         } else {
71                 counters = counter;
72         }
73 }
74
75 typedef int (*IntFunc) (void);
76 typedef guint (*UIntFunc) (void);
77 typedef gint64 (*LongFunc) (void);
78 typedef guint64 (*ULongFunc) (void);
79 typedef gssize (*PtrFunc) (void);
80 typedef double (*DoubleFunc) (void);
81 typedef char* (*StrFunc) (void);
82
83 #define ENTRY_FMT "%-36s: "
84 static void
85 dump_counter (MonoCounter *counter, FILE *outfile) {
86         int intval;
87         guint uintval;
88         gint64 int64val;
89         guint64 uint64val;
90         gssize wordval;
91         double dval;
92         const char *str;
93         switch (counter->type & MONO_COUNTER_TYPE_MASK) {
94         case MONO_COUNTER_INT:
95               if (counter->type & MONO_COUNTER_CALLBACK)
96                       intval = ((IntFunc)counter->addr) ();
97               else
98                       intval = *(int*)counter->addr;
99               fprintf (outfile, ENTRY_FMT "%d\n", counter->name, intval);
100               break;
101         case MONO_COUNTER_UINT:
102               if (counter->type & MONO_COUNTER_CALLBACK)
103                       uintval = ((UIntFunc)counter->addr) ();
104               else
105                       uintval = *(guint*)counter->addr;
106               fprintf (outfile, ENTRY_FMT "%u\n", counter->name, uintval);
107               break;
108         case MONO_COUNTER_LONG:
109               if (counter->type & MONO_COUNTER_CALLBACK)
110                       int64val = ((LongFunc)counter->addr) ();
111               else
112                       int64val = *(gint64*)counter->addr;
113               fprintf (outfile, ENTRY_FMT "%lld\n", counter->name, (long long)int64val);
114               break;
115         case MONO_COUNTER_ULONG:
116               if (counter->type & MONO_COUNTER_CALLBACK)
117                       uint64val = ((ULongFunc)counter->addr) ();
118               else
119                       uint64val = *(guint64*)counter->addr;
120               fprintf (outfile, ENTRY_FMT "%llu\n", counter->name, (unsigned long long)uint64val);
121               break;
122         case MONO_COUNTER_WORD:
123               if (counter->type & MONO_COUNTER_CALLBACK)
124                       wordval = ((PtrFunc)counter->addr) ();
125               else
126                       wordval = *(gssize*)counter->addr;
127 #if SIZEOF_VOID_P == 8
128               fprintf (outfile, ENTRY_FMT "%lld\n", counter->name, (gint64)wordval);
129 #else
130               fprintf (outfile, ENTRY_FMT "%d\n", counter->name, (gint)wordval);
131 #endif
132               break;
133         case MONO_COUNTER_DOUBLE:
134               if (counter->type & MONO_COUNTER_CALLBACK)
135                       dval = ((DoubleFunc)counter->addr) ();
136               else
137                       dval = *(double*)counter->addr;
138               fprintf (outfile, ENTRY_FMT "%.4f\n", counter->name, dval);
139               break;
140         case MONO_COUNTER_STRING:
141               if (counter->type & MONO_COUNTER_CALLBACK)
142                       str = ((StrFunc)counter->addr) ();
143               else
144                       str = *(char**)counter->addr;
145               fprintf (outfile, ENTRY_FMT "%s\n", counter->name, str);
146               break;
147         case MONO_COUNTER_TIME_INTERVAL:
148             if (counter->type & MONO_COUNTER_CALLBACK)
149                       int64val = ((LongFunc)counter->addr) ();
150             else
151                       int64val = *(gint64*)counter->addr;
152             fprintf (outfile, ENTRY_FMT "%.2f ms\n", counter->name, (double)int64val / 1000.0);
153             break;
154         }
155 }
156
157 static const char
158 section_names [][10] = {
159         "JIT",
160         "GC",
161         "Metadata",
162         "Generics",
163         "Security"
164 };
165
166 static void
167 mono_counters_dump_section (int section, FILE *outfile)
168 {
169         MonoCounter *counter = counters;
170         while (counter) {
171                 if (counter->type & section)
172                         dump_counter (counter, outfile);
173                 counter = counter->next;
174         }
175 }
176
177 /**
178  * mono_counters_dump:
179  * @section_mask: The sections to dump counters for
180  * @outfile: a FILE to dump the results to
181  *
182  * Displays the counts of all the enabled counters registered. 
183  */
184 void
185 mono_counters_dump (int section_mask, FILE *outfile)
186 {
187         int i, j;
188         section_mask &= valid_mask;
189         if (!counters)
190                 return;
191         for (j = 0, i = MONO_COUNTER_JIT; i < MONO_COUNTER_LAST_SECTION; j++, i <<= 1) {
192                 if ((section_mask & i) && (set_mask & i)) {
193                         fprintf (outfile, "\n%s statistics\n", section_names [j]);
194                         mono_counters_dump_section (i, outfile);
195                 }
196         }
197
198         fflush (outfile);
199 }
200
201 /**
202  * mono_counters_cleanup:
203  *
204  * Perform any needed cleanup at process exit.
205  */
206 void
207 mono_counters_cleanup (void)
208 {
209         MonoCounter *counter = counters;
210         counters = NULL;
211         while (counter) {
212                 MonoCounter *tmp = counter;
213                 counter = counter->next;
214                 free (tmp);
215         }
216 }
217
218 static MonoResourceCallback limit_reached = NULL;
219 static uintptr_t resource_limits [MONO_RESOURCE_COUNT * 2];
220
221 /**
222  * mono_runtime_resource_check_limit:
223  * @resource_type: one of the #MonoResourceType enum values
224  * @value: the current value of the resource usage
225  *
226  * Check if a runtime resource limit has been reached. This function
227  * is intended to be used by the runtime only.
228  */
229 void
230 mono_runtime_resource_check_limit (int resource_type, uintptr_t value)
231 {
232         if (!limit_reached)
233                 return;
234         /* check the hard limit first */
235         if (value > resource_limits [resource_type * 2 + 1]) {
236                 limit_reached (resource_type, value, 0);
237                 return;
238         }
239         if (value > resource_limits [resource_type * 2])
240                 limit_reached (resource_type, value, 1);
241 }
242
243 /**
244  * mono_runtime_resource_limit:
245  * @resource_type: one of the #MonoResourceType enum values
246  * @soft_limit: the soft limit value
247  * @hard_limit: the hard limit value
248  *
249  * This function sets the soft and hard limit for runtime resources. When the limit
250  * is reached, a user-specified callback is called. The callback runs in a restricted
251  * environment, in which the world coult be stopped, so it can't take locks, perform
252  * allocations etc. The callback may be called multiple times once a limit has been reached
253  * if action is not taken to decrease the resource use.
254  *
255  * Returns: 0 on error or a positive integer otherwise.
256  */
257 int
258 mono_runtime_resource_limit (int resource_type, uintptr_t soft_limit, uintptr_t hard_limit)
259 {
260         if (resource_type >= MONO_RESOURCE_COUNT || resource_type < 0)
261                 return 0;
262         if (soft_limit > hard_limit)
263                 return 0;
264         resource_limits [resource_type * 2] = soft_limit;
265         resource_limits [resource_type * 2 + 1] = hard_limit;
266         return 1;
267 }
268
269 /**
270  * mono_runtime_resource_set_callback:
271  * @callback: a function pointer
272  * 
273  * Set the callback to be invoked when a resource limit is reached.
274  * The callback will receive the resource type, the resource amount in resource-specific
275  * units and a flag indicating whether the soft or hard limit was reached.
276  */
277 void
278 mono_runtime_resource_set_callback (MonoResourceCallback callback)
279 {
280         limit_reached = callback;
281 }
282
283