2 * Copyright 2006-2010 Novell
3 * Copyright 2011 Xamarin Inc
9 #include "mono-counters.h"
10 #include "mono-proclib.h"
24 static MonoCounter *counters = NULL;
25 static int valid_mask = 0;
26 static int set_mask = 0;
29 * mono_counter_get_variance:
30 * @counter: counter to get the variance
32 * Variance specifies how the counter value is expected to behave between any two samplings.
34 * Returns: the monotonicity of the counter.
37 mono_counter_get_variance (MonoCounter *counter)
39 return counter->type & MONO_COUNTER_VARIANCE_MASK;
43 * mono_counter_get_unit:
44 * @counter: counter to get the unit
46 * The unit gives a high level view of the unit that the counter is measuring.
48 * Returns: the unit of the counter.
51 mono_counter_get_unit (MonoCounter *counter)
53 return counter->type & MONO_COUNTER_UNIT_MASK;
57 * mono_counter_get_section:
58 * @counter: counter to get the section
60 * Sections are the unit of organization between all counters.
62 * Returns: the section of the counter.
66 mono_counter_get_section (MonoCounter *counter)
68 return counter->type & MONO_COUNTER_SECTION_MASK;
72 * mono_counter_get_type:
73 * @counter: counter to get the type
75 * Returns the type used to strong the value of the counter.
77 * Returns:the type of the counter.
80 mono_counter_get_type (MonoCounter *counter)
82 return counter->type & MONO_COUNTER_TYPE_MASK;
86 * mono_counter_get_name:
87 * @counter: counter to get the name
89 * Returns the counter name. The string should not be freed.
91 * Returns the name of the counter.
95 mono_counter_get_name (MonoCounter *counter)
101 * mono_counter_get_size:
102 * @counter: counter to get the max size of the counter
104 * Use the returned size to create the buffer used with mono_counters_sample
106 * Returns: the max size of the counter data.
109 mono_counter_get_size (MonoCounter *counter)
111 return counter->size;
115 * mono_counters_enable:
116 * @section_mask: a mask listing the sections that will be displayed
118 * This is used to track which counters will be displayed.
121 mono_counters_enable (int section_mask)
123 valid_mask = section_mask & MONO_COUNTER_SECTION_MASK;
127 * mono_counters_register:
128 * @name: The name for this counters.
129 * @type: One of the possible MONO_COUNTER types, or MONO_COUNTER_CALLBACK for a function pointer.
130 * @addr: The address to register.
132 * Register addr as the address of a counter of type type.
133 * Note that @name must be a valid string at all times until
134 * mono_counters_dump () is called.
136 * This function should not be used with counter types that require an explicit size such as string
137 * as the counter size will be set to zero making them effectively useless.
140 * It may be a function pointer if MONO_COUNTER_CALLBACK is specified:
141 * the function should return the value and take no arguments.
144 mono_counters_register (const char* name, int type, void *addr)
147 switch (type & MONO_COUNTER_TYPE_MASK) {
148 case MONO_COUNTER_INT:
151 case MONO_COUNTER_UINT:
152 size = sizeof (guint);
154 case MONO_COUNTER_LONG:
155 case MONO_COUNTER_TIME_INTERVAL:
156 size = sizeof (gint64);
158 case MONO_COUNTER_ULONG:
159 size = sizeof (guint64);
161 case MONO_COUNTER_WORD:
162 size = sizeof (gssize);
164 case MONO_COUNTER_DOUBLE:
165 size = sizeof (double);
167 case MONO_COUNTER_STRING:
171 g_assert_not_reached ();
173 mono_counters_register_with_size (name, type, addr, size);
177 * mono_counters_register_with_size:
178 * @name: The name for this counters.
179 * @type: One of the possible MONO_COUNTER types, or MONO_COUNTER_CALLBACK for a function pointer.
180 * @addr: The address to register.
181 * @size: Max size of the counter data.
183 * Register addr as the address of a counter of type @type.
184 * Note that @name must be a valid string at all times until
185 * mono_counters_dump () is called.
187 * It may be a function pointer if MONO_COUNTER_CALLBACK is specified:
188 * the function should return the value and take no arguments.
190 * The value of @size is ignored for types with fixed size such as int and long.
192 * Use @size for types that can have dynamic size such as string.
194 * If @size is negative, it's silently converted to zero.
197 mono_counters_register_with_size (const char *name, int type, void *addr, int size)
199 MonoCounter *counter;
201 if ((type & MONO_COUNTER_VARIANCE_MASK) == 0)
202 type |= MONO_COUNTER_MONOTONIC;
206 counter = malloc (sizeof (MonoCounter));
209 counter->name = name;
210 counter->type = type;
211 counter->addr = addr;
212 counter->next = NULL;
213 counter->size = size;
219 MonoCounter *item = counters;
222 item->next = counter;
228 typedef int (*IntFunc) (void);
229 typedef guint (*UIntFunc) (void);
230 typedef gint64 (*LongFunc) (void);
231 typedef guint64 (*ULongFunc) (void);
232 typedef gssize (*PtrFunc) (void);
233 typedef double (*DoubleFunc) (void);
234 typedef char* (*StrFunc) (void);
236 #define ENTRY_FMT "%-36s: "
238 dump_counter (MonoCounter *counter, FILE *outfile) {
239 void *buffer = g_malloc0 (counter->size);
240 mono_counters_sample (counter, buffer, counter->size);
242 switch (counter->type & MONO_COUNTER_TYPE_MASK) {
243 case MONO_COUNTER_INT:
244 fprintf (outfile, ENTRY_FMT "%d\n", counter->name, *(int*)buffer);
246 case MONO_COUNTER_UINT:
247 fprintf (outfile, ENTRY_FMT "%u\n", counter->name, *(guint*)buffer);
249 case MONO_COUNTER_LONG:
250 if ((counter->type & MONO_COUNTER_UNIT_MASK) == MONO_COUNTER_TIME)
251 fprintf (outfile, ENTRY_FMT "%.2f ms\n", counter->name, (double)(*(gint64*)buffer) / 10000.0);
253 fprintf (outfile, ENTRY_FMT "%lld\n", counter->name, *(gint64*)buffer);
255 case MONO_COUNTER_ULONG:
256 fprintf (outfile, ENTRY_FMT "%llu\n", counter->name, *(guint64*)buffer);
258 case MONO_COUNTER_WORD:
259 fprintf (outfile, ENTRY_FMT "%zd\n", counter->name, *(gssize*)buffer);
261 case MONO_COUNTER_DOUBLE:
262 fprintf (outfile, ENTRY_FMT "%.4f\n", counter->name, *(double*)buffer);
264 case MONO_COUNTER_STRING:
265 fprintf (outfile, ENTRY_FMT "%s\n", counter->name, (counter->size == 0) ? "(null)" : (char*)buffer);
267 case MONO_COUNTER_TIME_INTERVAL:
268 fprintf (outfile, ENTRY_FMT "%.2f ms\n", counter->name, (double)(*(gint64*)buffer) / 1000.0);
278 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_USER_TIME);
284 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_SYSTEM_TIME);
290 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_TOTAL_TIME);
296 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_WORKING_SET);
302 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_PRIVATE_BYTES);
308 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_VIRTUAL_BYTES);
314 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_FAULTS);
320 #if defined(TARGET_WIN32)
321 #elif defined(TARGET_MACH)
323 if (getloadavg (load, 3) > 0)
326 char buffer[512], *b;
328 FILE *f = fopen ("/proc/loadavg", "r");
330 len = fread (buffer, 1, sizeof (buffer) - 1, f);
332 buffer [len < 511 ? len : 511] = 0;
334 for (i = 0; i < 3; i++) {
336 return strtod (b, NULL);
364 cpu_load_15min (void)
369 static gboolean system_counters_initialized = FALSE;
371 #define SYSCOUNTER_TIME (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_TIME | MONO_COUNTER_MONOTONIC | MONO_COUNTER_CALLBACK)
372 #define SYSCOUNTER_BYTES (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_BYTES | MONO_COUNTER_VARIABLE | MONO_COUNTER_CALLBACK)
373 #define SYSCOUNTER_COUNT (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_COUNT | MONO_COUNTER_MONOTONIC | MONO_COUNTER_CALLBACK)
374 #define SYSCOUNTER_LOAD (MONO_COUNTER_SYSTEM | MONO_COUNTER_DOUBLE | MONO_COUNTER_PERCENTAGE | MONO_COUNTER_VARIABLE | MONO_COUNTER_CALLBACK)
377 initialize_system_counters (void)
379 mono_counters_register ("User Time", SYSCOUNTER_TIME, &user_time);
380 mono_counters_register ("System Time", SYSCOUNTER_TIME, &system_time);
381 mono_counters_register ("Total Time", SYSCOUNTER_TIME, &total_time);
382 mono_counters_register ("Working Set", SYSCOUNTER_BYTES, &working_set);
383 mono_counters_register ("Private Bytes", SYSCOUNTER_BYTES, &private_bytes);
384 mono_counters_register ("Virtual Bytes", SYSCOUNTER_BYTES, &virtual_bytes);
385 mono_counters_register ("Page Faults", SYSCOUNTER_COUNT, &page_faults);
386 mono_counters_register ("CPU Load Average - 1min", SYSCOUNTER_LOAD, &cpu_load_1min);
387 mono_counters_register ("CPU Load Average - 5min", SYSCOUNTER_LOAD, &cpu_load_5min);
388 mono_counters_register ("CPU Load Average - 15min", SYSCOUNTER_LOAD, &cpu_load_15min);
390 system_counters_initialized = TRUE;
394 * mono_counters_foreach:
395 * @cb: The callback that will be called for each counter.
396 * @user_data: Value passed as second argument of the callback.
398 * Iterate over all counters and call @cb for each one of them. Stop iterating if
399 * the callback returns FALSE.
403 mono_counters_foreach (CountersEnumCallback cb, gpointer user_data)
405 MonoCounter *counter;
407 if (!system_counters_initialized)
408 initialize_system_counters ();
410 for (counter = counters; counter; counter = counter->next) {
411 if (!cb (counter, user_data))
416 #define COPY_COUNTER(type,functype) do { \
417 size = sizeof (type); \
418 if (buffer_size < size) \
420 *(type*)buffer = cb ? ((functype)counter->addr) () : *(type*)counter->addr; \
424 mono_counters_sample (MonoCounter *counter, void *buffer, int buffer_size)
426 int cb = counter->type & MONO_COUNTER_CALLBACK;
431 switch (mono_counter_get_type (counter)) {
432 case MONO_COUNTER_INT:
433 COPY_COUNTER (int, IntFunc);
435 case MONO_COUNTER_UINT:
436 COPY_COUNTER (guint, UIntFunc);
438 case MONO_COUNTER_LONG:
439 case MONO_COUNTER_TIME_INTERVAL:
440 COPY_COUNTER (gint64, LongFunc);
442 case MONO_COUNTER_ULONG:
443 COPY_COUNTER (guint64, ULongFunc);
445 case MONO_COUNTER_WORD:
446 COPY_COUNTER (gssize, PtrFunc);
448 case MONO_COUNTER_DOUBLE:
449 COPY_COUNTER (double, DoubleFunc);
451 case MONO_COUNTER_STRING:
452 if (buffer_size < counter->size)
454 if (counter->size == 0)
456 strval = cb ? ((StrFunc)counter->addr) () : (char*)counter->addr;
459 size = counter->size;
460 strncpy (buffer, strval, size - 1);
461 ((char*)buffer)[size - 1] = '\0';
468 section_names [][10] = {
479 mono_counters_dump_section (int section, int variance, FILE *outfile)
481 MonoCounter *counter = counters;
483 if ((counter->type & section) && (mono_counter_get_variance (counter) & variance))
484 dump_counter (counter, outfile);
485 counter = counter->next;
490 * mono_counters_dump:
491 * @section_mask: The sections to dump counters for
492 * @outfile: a FILE to dump the results to
494 * Displays the counts of all the enabled counters registered.
495 * To filter by variance, you can OR one or more variance with the specific section you want.
496 * Use MONO_COUNTER_SECTION_MASK to dump all categories of a specific variance.
499 mono_counters_dump (int section_mask, FILE *outfile)
503 section_mask &= valid_mask;
507 variance = section_mask & MONO_COUNTER_VARIANCE_MASK;
509 /* If no variance mask is supplied, we default to all kinds. */
511 variance = MONO_COUNTER_VARIANCE_MASK;
512 section_mask &= ~MONO_COUNTER_VARIANCE_MASK;
514 for (j = 0, i = MONO_COUNTER_JIT; i < MONO_COUNTER_LAST_SECTION; j++, i <<= 1) {
515 if ((section_mask & i) && (set_mask & i)) {
516 fprintf (outfile, "\n%s statistics\n", section_names [j]);
517 mono_counters_dump_section (i, variance, outfile);
525 * mono_counters_cleanup:
527 * Perform any needed cleanup at process exit.
530 mono_counters_cleanup (void)
532 MonoCounter *counter = counters;
535 MonoCounter *tmp = counter;
536 counter = counter->next;
541 static MonoResourceCallback limit_reached = NULL;
542 static uintptr_t resource_limits [MONO_RESOURCE_COUNT * 2];
545 * mono_runtime_resource_check_limit:
546 * @resource_type: one of the #MonoResourceType enum values
547 * @value: the current value of the resource usage
549 * Check if a runtime resource limit has been reached. This function
550 * is intended to be used by the runtime only.
553 mono_runtime_resource_check_limit (int resource_type, uintptr_t value)
557 /* check the hard limit first */
558 if (value > resource_limits [resource_type * 2 + 1]) {
559 limit_reached (resource_type, value, 0);
562 if (value > resource_limits [resource_type * 2])
563 limit_reached (resource_type, value, 1);
567 * mono_runtime_resource_limit:
568 * @resource_type: one of the #MonoResourceType enum values
569 * @soft_limit: the soft limit value
570 * @hard_limit: the hard limit value
572 * This function sets the soft and hard limit for runtime resources. When the limit
573 * is reached, a user-specified callback is called. The callback runs in a restricted
574 * environment, in which the world coult be stopped, so it can't take locks, perform
575 * allocations etc. The callback may be called multiple times once a limit has been reached
576 * if action is not taken to decrease the resource use.
578 * Returns: 0 on error or a positive integer otherwise.
581 mono_runtime_resource_limit (int resource_type, uintptr_t soft_limit, uintptr_t hard_limit)
583 if (resource_type >= MONO_RESOURCE_COUNT || resource_type < 0)
585 if (soft_limit > hard_limit)
587 resource_limits [resource_type * 2] = soft_limit;
588 resource_limits [resource_type * 2 + 1] = hard_limit;
593 * mono_runtime_resource_set_callback:
594 * @callback: a function pointer
596 * Set the callback to be invoked when a resource limit is reached.
597 * The callback will receive the resource type, the resource amount in resource-specific
598 * units and a flag indicating whether the soft or hard limit was reached.
601 mono_runtime_resource_set_callback (MonoResourceCallback callback)
603 limit_reached = callback;