2 * Copyright 2006-2010 Novell
3 * Copyright 2011 Xamarin Inc
9 #include "mono-counters.h"
10 #include "mono-proclib.h"
23 static MonoCounter *counters = NULL;
24 static int valid_mask = 0;
25 static int set_mask = 0;
28 mono_counter_get_variance (MonoCounter *counter)
30 return counter->type & MONO_COUNTER_VARIANCE_MASK;
34 mono_counter_get_unit (MonoCounter *counter)
36 return counter->type & MONO_COUNTER_UNIT_MASK;
40 mono_counter_get_section (MonoCounter *counter)
42 return counter->type & MONO_COUNTER_SECTION_MASK;
46 mono_counter_get_type (MonoCounter *counter)
48 return counter->type & MONO_COUNTER_TYPE_MASK;
52 mono_counter_get_name (MonoCounter *counter)
58 mono_counter_get_size (MonoCounter *counter)
60 switch (mono_counter_get_type (counter)) {
61 case MONO_COUNTER_INT:
63 case MONO_COUNTER_UINT:
64 return sizeof (guint);
65 case MONO_COUNTER_LONG:
66 case MONO_COUNTER_TIME_INTERVAL:
67 return sizeof (gint64);
68 case MONO_COUNTER_ULONG:
69 return sizeof (guint64);
70 case MONO_COUNTER_WORD:
71 return sizeof (gssize);
72 case MONO_COUNTER_DOUBLE:
73 return sizeof (double);
74 case MONO_COUNTER_STRING:
77 g_assert_not_reached ();
82 * mono_counters_enable:
83 * @section_mask: a mask listing the sections that will be displayed
85 * This is used to track which counters will be displayed.
88 mono_counters_enable (int section_mask)
90 valid_mask = section_mask & MONO_COUNTER_SECTION_MASK;
94 * mono_counters_register:
95 * @name: The name for this counters.
96 * @type: One of the possible MONO_COUNTER types, or MONO_COUNTER_CALLBACK for a function pointer.
97 * @addr: The address to register.
99 * Register addr as the address of a counter of type type.
100 * Note that @name must be a valid string at all times until
101 * mono_counters_dump () is called.
103 * It may be a function pointer if MONO_COUNTER_CALLBACK is specified:
104 * the function should return the value and take no arguments.
107 mono_counters_register (const char* name, int type, void *addr)
109 MonoCounter *counter;
111 if ((type & MONO_COUNTER_VARIANCE_MASK) == 0)
112 type |= MONO_COUNTER_MONOTONIC;
114 counter = malloc (sizeof (MonoCounter));
117 counter->name = name;
118 counter->type = type;
119 counter->addr = addr;
120 counter->next = NULL;
126 MonoCounter *item = counters;
129 item->next = counter;
135 typedef int (*IntFunc) (void);
136 typedef guint (*UIntFunc) (void);
137 typedef gint64 (*LongFunc) (void);
138 typedef guint64 (*ULongFunc) (void);
139 typedef gssize (*PtrFunc) (void);
140 typedef double (*DoubleFunc) (void);
141 typedef char* (*StrFunc) (void);
143 #define ENTRY_FMT "%-36s: "
145 dump_counter (MonoCounter *counter, FILE *outfile) {
153 switch (counter->type & MONO_COUNTER_TYPE_MASK) {
154 case MONO_COUNTER_INT:
155 if (counter->type & MONO_COUNTER_CALLBACK)
156 intval = ((IntFunc)counter->addr) ();
158 intval = *(int*)counter->addr;
159 fprintf (outfile, ENTRY_FMT "%d\n", counter->name, intval);
161 case MONO_COUNTER_UINT:
162 if (counter->type & MONO_COUNTER_CALLBACK)
163 uintval = ((UIntFunc)counter->addr) ();
165 uintval = *(guint*)counter->addr;
166 fprintf (outfile, ENTRY_FMT "%u\n", counter->name, uintval);
168 case MONO_COUNTER_LONG:
169 if (counter->type & MONO_COUNTER_CALLBACK)
170 int64val = ((LongFunc)counter->addr) ();
172 int64val = *(gint64*)counter->addr;
173 if (mono_counter_get_unit (counter) == MONO_COUNTER_TIME)
174 fprintf (outfile, ENTRY_FMT "%.2f ms\n", counter->name, (double)int64val / 10000.0);
176 fprintf (outfile, ENTRY_FMT "%lld\n", counter->name, (long long)int64val);
178 case MONO_COUNTER_ULONG:
179 if (counter->type & MONO_COUNTER_CALLBACK)
180 uint64val = ((ULongFunc)counter->addr) ();
182 uint64val = *(guint64*)counter->addr;
183 fprintf (outfile, ENTRY_FMT "%llu\n", counter->name, (unsigned long long)uint64val);
185 case MONO_COUNTER_WORD:
186 if (counter->type & MONO_COUNTER_CALLBACK)
187 wordval = ((PtrFunc)counter->addr) ();
189 wordval = *(gssize*)counter->addr;
190 fprintf (outfile, ENTRY_FMT "%zd\n", counter->name, (gint64)wordval);
192 case MONO_COUNTER_DOUBLE:
193 if (counter->type & MONO_COUNTER_CALLBACK)
194 dval = ((DoubleFunc)counter->addr) ();
196 dval = *(double*)counter->addr;
197 fprintf (outfile, ENTRY_FMT "%.4f\n", counter->name, dval);
199 case MONO_COUNTER_STRING:
200 if (counter->type & MONO_COUNTER_CALLBACK)
201 str = ((StrFunc)counter->addr) ();
203 str = *(char**)counter->addr;
204 fprintf (outfile, ENTRY_FMT "%s\n", counter->name, str);
206 case MONO_COUNTER_TIME_INTERVAL:
207 if (counter->type & MONO_COUNTER_CALLBACK)
208 int64val = ((LongFunc)counter->addr) ();
210 int64val = *(gint64*)counter->addr;
211 fprintf (outfile, ENTRY_FMT "%.2f ms\n", counter->name, (double)int64val / 1000.0);
219 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_USER_TIME);
225 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_SYSTEM_TIME);
231 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_TOTAL_TIME);
237 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_WORKING_SET);
243 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_PRIVATE_BYTES);
249 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_VIRTUAL_BYTES);
255 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_FAULTS);
261 #if defined(TARGET_WIN32)
262 #elif defined(TARGET_MACH)
264 if (getloadavg (load, 3) > 0)
267 char buffer[512], *b;
269 FILE *f = fopen ("/proc/loadavg", "r");
271 len = fread (buffer, 1, sizeof (buffer) - 1, f);
273 buffer [len < 511 ? len : 511] = 0;
275 for (i = 0; i < 3; i++) {
277 return strtod (b, NULL);
310 static gboolean system_counters_initialized = FALSE;
312 #define SYSCOUNTER_TIME (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_TIME | MONO_COUNTER_MONOTONIC | MONO_COUNTER_CALLBACK)
313 #define SYSCOUNTER_BYTES (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_BYTES | MONO_COUNTER_VARIABLE | MONO_COUNTER_CALLBACK)
314 #define SYSCOUNTER_COUNT (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_COUNT | MONO_COUNTER_MONOTONIC | MONO_COUNTER_CALLBACK)
315 #define SYSCOUNTER_LOAD (MONO_COUNTER_SYSTEM | MONO_COUNTER_DOUBLE | MONO_COUNTER_PERCENTAGE | MONO_COUNTER_VARIABLE | MONO_COUNTER_CALLBACK)
318 initialize_system_counters ()
320 mono_counters_register ("User Time", SYSCOUNTER_TIME, &user_time);
321 mono_counters_register ("System Time", SYSCOUNTER_TIME, &system_time);
322 mono_counters_register ("Total Time", SYSCOUNTER_TIME, &total_time);
323 mono_counters_register ("Working Set", SYSCOUNTER_BYTES, &working_set);
324 mono_counters_register ("Private Bytes", SYSCOUNTER_BYTES, &private_bytes);
325 mono_counters_register ("Virtual Bytes", SYSCOUNTER_BYTES, &virtual_bytes);
326 mono_counters_register ("Page Faults", SYSCOUNTER_COUNT, &page_faults);
327 mono_counters_register ("CPU Load Average - 1min", SYSCOUNTER_LOAD, &cpu_load_1min);
328 mono_counters_register ("CPU Load Average - 5min", SYSCOUNTER_LOAD, &cpu_load_5min);
329 mono_counters_register ("CPU Load Average - 15min", SYSCOUNTER_LOAD, &cpu_load_15min);
331 system_counters_initialized = TRUE;
335 * mono_counters_foreach:
336 * @cb: The callback that will be called for each counter.
337 * @user_data: Value passed as second argument of the callback.
339 * Iterate over all counters and call @cb for each one of them. Stop iterating if
340 * the callback returns FALSE.
344 mono_counters_foreach (CountersEnumCallback cb, gpointer user_data)
346 MonoCounter *counter;
348 if (!system_counters_initialized)
349 initialize_system_counters ();
351 for (counter = counters; counter; counter = counter->next) {
352 if (!cb (counter, user_data))
357 #define COPY_COUNTER(type,functype) do { \
358 size = sizeof (type); \
359 if (buffer_size < size) \
361 type __var = cb ? ((functype)counter->addr) () : *(type*)counter->addr; \
362 memcpy (buffer, &__var, size); \
366 mono_counters_sample (MonoCounter *counter, void *buffer, int buffer_size)
368 int cb = counter->type & MONO_COUNTER_CALLBACK;
371 switch (mono_counter_get_type (counter)) {
372 case MONO_COUNTER_INT:
373 COPY_COUNTER (int, IntFunc);
375 case MONO_COUNTER_UINT:
376 COPY_COUNTER (guint, UIntFunc);
378 case MONO_COUNTER_LONG:
379 case MONO_COUNTER_TIME_INTERVAL:
380 COPY_COUNTER (gint64, LongFunc);
382 case MONO_COUNTER_ULONG:
383 COPY_COUNTER (guint64, ULongFunc);
385 case MONO_COUNTER_WORD:
386 COPY_COUNTER (gssize, PtrFunc);
388 case MONO_COUNTER_DOUBLE:
389 COPY_COUNTER (double, DoubleFunc);
391 case MONO_COUNTER_STRING:
392 // FIXME : add support for string sampling
400 section_names [][10] = {
411 mono_counters_dump_section (int section, FILE *outfile)
413 MonoCounter *counter = counters;
415 if ((counter->type & section) && (mono_counter_get_variance (counter) & section))
416 dump_counter (counter, outfile);
417 counter = counter->next;
422 * mono_counters_dump:
423 * @section_mask: The sections to dump counters for
424 * @outfile: a FILE to dump the results to
426 * Displays the counts of all the enabled counters registered.
427 * To filter by variance, you can OR one or more variance with the specific section you want.
428 * Use MONO_COUNTER_SECTION_MASK to dump all categories of a specific variance.
431 mono_counters_dump (int section_mask, FILE *outfile)
434 section_mask &= valid_mask;
438 /* If no variance mask is supplied, we default to all kinds. */
439 if (!(section_mask & MONO_COUNTER_VARIANCE_MASK))
440 section_mask |= MONO_COUNTER_VARIANCE_MASK;
442 for (j = 0, i = MONO_COUNTER_JIT; i < MONO_COUNTER_LAST_SECTION; j++, i <<= 1) {
443 if ((section_mask & i) && (set_mask & i)) {
444 fprintf (outfile, "\n%s statistics\n", section_names [j]);
445 mono_counters_dump_section (i | (section_mask & MONO_COUNTER_VARIANCE_MASK), outfile);
453 * mono_counters_cleanup:
455 * Perform any needed cleanup at process exit.
458 mono_counters_cleanup (void)
460 MonoCounter *counter = counters;
463 MonoCounter *tmp = counter;
464 counter = counter->next;
469 static MonoResourceCallback limit_reached = NULL;
470 static uintptr_t resource_limits [MONO_RESOURCE_COUNT * 2];
473 * mono_runtime_resource_check_limit:
474 * @resource_type: one of the #MonoResourceType enum values
475 * @value: the current value of the resource usage
477 * Check if a runtime resource limit has been reached. This function
478 * is intended to be used by the runtime only.
481 mono_runtime_resource_check_limit (int resource_type, uintptr_t value)
485 /* check the hard limit first */
486 if (value > resource_limits [resource_type * 2 + 1]) {
487 limit_reached (resource_type, value, 0);
490 if (value > resource_limits [resource_type * 2])
491 limit_reached (resource_type, value, 1);
495 * mono_runtime_resource_limit:
496 * @resource_type: one of the #MonoResourceType enum values
497 * @soft_limit: the soft limit value
498 * @hard_limit: the hard limit value
500 * This function sets the soft and hard limit for runtime resources. When the limit
501 * is reached, a user-specified callback is called. The callback runs in a restricted
502 * environment, in which the world coult be stopped, so it can't take locks, perform
503 * allocations etc. The callback may be called multiple times once a limit has been reached
504 * if action is not taken to decrease the resource use.
506 * Returns: 0 on error or a positive integer otherwise.
509 mono_runtime_resource_limit (int resource_type, uintptr_t soft_limit, uintptr_t hard_limit)
511 if (resource_type >= MONO_RESOURCE_COUNT || resource_type < 0)
513 if (soft_limit > hard_limit)
515 resource_limits [resource_type * 2] = soft_limit;
516 resource_limits [resource_type * 2 + 1] = hard_limit;
521 * mono_runtime_resource_set_callback:
522 * @callback: a function pointer
524 * Set the callback to be invoked when a resource limit is reached.
525 * The callback will receive the resource type, the resource amount in resource-specific
526 * units and a flag indicating whether the soft or hard limit was reached.
529 mono_runtime_resource_set_callback (MonoResourceCallback callback)
531 limit_reached = callback;