2 * Copyright 2006-2010 Novell
3 * Copyright 2011 Xamarin Inc
8 #include "mono-counters.h"
17 static MonoCounter *counters = NULL;
18 static int valid_mask = 0;
19 static int set_mask = 0;
22 mono_counter_get_variance (MonoCounter *counter)
24 return counter->type & MONO_COUNTER_VARIANCE_MASK;
28 mono_counter_get_unit (MonoCounter *counter)
30 return counter->type & MONO_COUNTER_UNIT_MASK;
34 * mono_counters_enable:
35 * @section_mask: a mask listing the sections that will be displayed
37 * This is used to track which counters will be displayed.
40 mono_counters_enable (int section_mask)
42 valid_mask = section_mask & MONO_COUNTER_SECTION_MASK;
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.
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.
55 * It may be a function pointer if MONO_COUNTER_CALLBACK is specified:
56 * the function should return the value and take no arguments.
59 mono_counters_register (const char* name, int type, void *addr)
62 if (!(type & valid_mask))
65 if ((type & MONO_COUNTER_VARIANCE_MASK) == 0)
66 type |= MONO_COUNTER_MONOTONIC;
68 counter = malloc (sizeof (MonoCounter));
80 MonoCounter *item = counters;
89 typedef int (*IntFunc) (void);
90 typedef guint (*UIntFunc) (void);
91 typedef gint64 (*LongFunc) (void);
92 typedef guint64 (*ULongFunc) (void);
93 typedef gssize (*PtrFunc) (void);
94 typedef double (*DoubleFunc) (void);
95 typedef char* (*StrFunc) (void);
97 #define ENTRY_FMT "%-36s: "
99 dump_counter (MonoCounter *counter, FILE *outfile) {
107 switch (counter->type & MONO_COUNTER_TYPE_MASK) {
108 case MONO_COUNTER_INT:
109 if (counter->type & MONO_COUNTER_CALLBACK)
110 intval = ((IntFunc)counter->addr) ();
112 intval = *(int*)counter->addr;
113 fprintf (outfile, ENTRY_FMT "%d\n", counter->name, intval);
115 case MONO_COUNTER_UINT:
116 if (counter->type & MONO_COUNTER_CALLBACK)
117 uintval = ((UIntFunc)counter->addr) ();
119 uintval = *(guint*)counter->addr;
120 fprintf (outfile, ENTRY_FMT "%u\n", counter->name, uintval);
122 case MONO_COUNTER_LONG:
123 if (counter->type & MONO_COUNTER_CALLBACK)
124 int64val = ((LongFunc)counter->addr) ();
126 int64val = *(gint64*)counter->addr;
127 if (mono_counter_get_unit (counter) == MONO_COUNTER_TIME)
128 fprintf (outfile, ENTRY_FMT "%.2f ms\n", counter->name, (double)int64val / 10000.0);
130 fprintf (outfile, ENTRY_FMT "%lld\n", counter->name, (long long)int64val);
132 case MONO_COUNTER_ULONG:
133 if (counter->type & MONO_COUNTER_CALLBACK)
134 uint64val = ((ULongFunc)counter->addr) ();
136 uint64val = *(guint64*)counter->addr;
137 fprintf (outfile, ENTRY_FMT "%llu\n", counter->name, (unsigned long long)uint64val);
139 case MONO_COUNTER_WORD:
140 if (counter->type & MONO_COUNTER_CALLBACK)
141 wordval = ((PtrFunc)counter->addr) ();
143 wordval = *(gssize*)counter->addr;
144 fprintf (outfile, ENTRY_FMT "%zd\n", counter->name, (gint64)wordval);
146 case MONO_COUNTER_DOUBLE:
147 if (counter->type & MONO_COUNTER_CALLBACK)
148 dval = ((DoubleFunc)counter->addr) ();
150 dval = *(double*)counter->addr;
151 fprintf (outfile, ENTRY_FMT "%.4f\n", counter->name, dval);
153 case MONO_COUNTER_STRING:
154 if (counter->type & MONO_COUNTER_CALLBACK)
155 str = ((StrFunc)counter->addr) ();
157 str = *(char**)counter->addr;
158 fprintf (outfile, ENTRY_FMT "%s\n", counter->name, str);
160 case MONO_COUNTER_TIME_INTERVAL:
161 if (counter->type & MONO_COUNTER_CALLBACK)
162 int64val = ((LongFunc)counter->addr) ();
164 int64val = *(gint64*)counter->addr;
165 fprintf (outfile, ENTRY_FMT "%.2f ms\n", counter->name, (double)int64val / 1000.0);
172 * mono_counters_foreach:
173 * @cb: The callback that will be called for each counter.
174 * @user_data: Value passed as second argument of the callback.
176 * Iterate over all counters and call @cb for each one of them. Stop iterating if
177 * the callback returns FALSE.
181 mono_counters_foreach (CountersEnumCallback cb, gpointer user_data)
183 MonoCounter *counter;
185 for (counter = counters; counter; counter = counter->next) {
186 if (!cb (counter, user_data))
192 section_names [][10] = {
203 mono_counters_dump_section (int section, FILE *outfile)
205 MonoCounter *counter = counters;
207 if ((counter->type & section) && (mono_counter_get_variance (counter) & section))
208 dump_counter (counter, outfile);
209 counter = counter->next;
214 * mono_counters_dump:
215 * @section_mask: The sections to dump counters for
216 * @outfile: a FILE to dump the results to
218 * Displays the counts of all the enabled counters registered.
219 * To filter by variance, you can OR one or more variance with the specific section you want.
220 * Use MONO_COUNTER_SECTION_MASK to dump all categories of a specific variance.
223 mono_counters_dump (int section_mask, FILE *outfile)
226 section_mask &= valid_mask;
230 /* If no variance mask is supplied, we default to all kinds. */
231 if (!(section_mask & MONO_COUNTER_VARIANCE_MASK))
232 section_mask |= MONO_COUNTER_VARIANCE_MASK;
234 for (j = 0, i = MONO_COUNTER_JIT; i < MONO_COUNTER_LAST_SECTION; j++, i <<= 1) {
235 if ((section_mask & i) && (set_mask & i)) {
236 fprintf (outfile, "\n%s statistics\n", section_names [j]);
237 mono_counters_dump_section (i | (section_mask & MONO_COUNTER_VARIANCE_MASK), outfile);
245 * mono_counters_cleanup:
247 * Perform any needed cleanup at process exit.
250 mono_counters_cleanup (void)
252 MonoCounter *counter = counters;
255 MonoCounter *tmp = counter;
256 counter = counter->next;
261 static MonoResourceCallback limit_reached = NULL;
262 static uintptr_t resource_limits [MONO_RESOURCE_COUNT * 2];
265 * mono_runtime_resource_check_limit:
266 * @resource_type: one of the #MonoResourceType enum values
267 * @value: the current value of the resource usage
269 * Check if a runtime resource limit has been reached. This function
270 * is intended to be used by the runtime only.
273 mono_runtime_resource_check_limit (int resource_type, uintptr_t value)
277 /* check the hard limit first */
278 if (value > resource_limits [resource_type * 2 + 1]) {
279 limit_reached (resource_type, value, 0);
282 if (value > resource_limits [resource_type * 2])
283 limit_reached (resource_type, value, 1);
287 * mono_runtime_resource_limit:
288 * @resource_type: one of the #MonoResourceType enum values
289 * @soft_limit: the soft limit value
290 * @hard_limit: the hard limit value
292 * This function sets the soft and hard limit for runtime resources. When the limit
293 * is reached, a user-specified callback is called. The callback runs in a restricted
294 * environment, in which the world coult be stopped, so it can't take locks, perform
295 * allocations etc. The callback may be called multiple times once a limit has been reached
296 * if action is not taken to decrease the resource use.
298 * Returns: 0 on error or a positive integer otherwise.
301 mono_runtime_resource_limit (int resource_type, uintptr_t soft_limit, uintptr_t hard_limit)
303 if (resource_type >= MONO_RESOURCE_COUNT || resource_type < 0)
305 if (soft_limit > hard_limit)
307 resource_limits [resource_type * 2] = soft_limit;
308 resource_limits [resource_type * 2 + 1] = hard_limit;
313 * mono_runtime_resource_set_callback:
314 * @callback: a function pointer
316 * Set the callback to be invoked when a resource limit is reached.
317 * The callback will receive the resource type, the resource amount in resource-specific
318 * units and a flag indicating whether the soft or hard limit was reached.
321 mono_runtime_resource_set_callback (MonoResourceCallback callback)
323 limit_reached = callback;