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