3 * Copyright 2006-2010 Novell
4 * Copyright 2011 Xamarin Inc
5 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11 #include "mono-counters.h"
12 #include "mono-proclib.h"
13 #include "mono-os-mutex.h"
27 static MonoCounter
*counters
= NULL
;
28 static mono_mutex_t counters_mutex
;
30 static volatile gboolean initialized
= FALSE
;
32 static int valid_mask
= 0;
33 static int set_mask
= 0;
35 static GSList
*register_callbacks
= NULL
;
37 static void initialize_system_counters (void);
40 * mono_counter_get_variance:
41 * \param counter counter to get the variance
43 * Variance specifies how the counter value is expected to behave between any two samplings.
45 * \returns the monotonicity of the counter.
48 mono_counter_get_variance (MonoCounter
*counter
)
50 return counter
->type
& MONO_COUNTER_VARIANCE_MASK
;
54 * mono_counter_get_unit:
55 * \param counter counter to get the unit
57 * The unit gives a high level view of the unit that the counter is measuring.
59 * \returns the unit of the counter.
62 mono_counter_get_unit (MonoCounter
*counter
)
64 return counter
->type
& MONO_COUNTER_UNIT_MASK
;
68 * mono_counter_get_section:
69 * \param counter counter to get the section
70 * Sections are the unit of organization between all counters.
71 * \returns the section of the counter.
75 mono_counter_get_section (MonoCounter
*counter
)
77 return counter
->type
& MONO_COUNTER_SECTION_MASK
;
81 * mono_counter_get_type:
82 * \param counter counter to get the type
83 * \returns the type used to store the value of the counter.
86 mono_counter_get_type (MonoCounter
*counter
)
88 return counter
->type
& MONO_COUNTER_TYPE_MASK
;
92 * mono_counter_get_name:
93 * \param counter counter to get the name
94 * \returns the counter name. The string should not be freed.
98 mono_counter_get_name (MonoCounter
*counter
)
100 return counter
->name
;
104 * mono_counter_get_size:
105 * \param counter counter to get the max size of the counter
106 * Use the returned size to create the buffer used with \c mono_counters_sample
107 * \returns the max size of the counter data.
110 mono_counter_get_size (MonoCounter
*counter
)
112 return counter
->size
;
116 * mono_counters_enable:
117 * \param sectionmask 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_init (void)
132 mono_os_mutex_init (&counters_mutex
);
134 initialize_system_counters ();
140 register_internal (const char *name
, int type
, void *addr
, int size
)
142 MonoCounter
*counter
;
143 GSList
*register_callback
;
145 g_assert (size
>= 0);
146 if ((type
& MONO_COUNTER_VARIANCE_MASK
) == 0)
147 type
|= MONO_COUNTER_MONOTONIC
;
149 mono_os_mutex_lock (&counters_mutex
);
151 for (counter
= counters
; counter
; counter
= counter
->next
) {
152 if (counter
->addr
== addr
) {
153 g_warning ("you are registering the same counter address twice: %s at %p", name
, addr
);
154 mono_os_mutex_unlock (&counters_mutex
);
159 counter
= (MonoCounter
*) g_malloc (sizeof (MonoCounter
));
161 mono_os_mutex_unlock (&counters_mutex
);
164 counter
->name
= g_strdup (name
);
165 counter
->type
= type
;
166 counter
->addr
= addr
;
167 counter
->next
= NULL
;
168 counter
->size
= size
;
174 MonoCounter
*item
= counters
;
177 item
->next
= counter
;
182 for (register_callback
= register_callbacks
; register_callback
; register_callback
= register_callback
->next
)
183 ((MonoCounterRegisterCallback
)register_callback
->data
) (counter
);
185 mono_os_mutex_unlock (&counters_mutex
);
189 * mono_counters_register:
190 * \param name The name for this counters.
191 * \param type One of the possible \c MONO_COUNTER types, or \c MONO_COUNTER_CALLBACK for a function pointer.
192 * \param addr The address to register.
194 * Register \p addr as the address of a counter of type type.
195 * Note that \p name must be a valid string at all times until
196 * \c mono_counters_dump() is called.
198 * This function should not be used with counter types that require an explicit size such as string
199 * as the counter size will be set to zero making them effectively useless.
201 * It may be a function pointer if \c MONO_COUNTER_CALLBACK is specified:
202 * the function should return the value and take no arguments.
205 mono_counters_register (const char* name
, int type
, void *addr
)
208 switch (type
& MONO_COUNTER_TYPE_MASK
) {
209 case MONO_COUNTER_INT
:
212 case MONO_COUNTER_UINT
:
213 size
= sizeof (guint
);
215 case MONO_COUNTER_LONG
:
216 case MONO_COUNTER_TIME_INTERVAL
:
217 size
= sizeof (gint64
);
219 case MONO_COUNTER_ULONG
:
220 size
= sizeof (guint64
);
222 case MONO_COUNTER_WORD
:
223 size
= sizeof (gssize
);
225 case MONO_COUNTER_DOUBLE
:
226 size
= sizeof (double);
228 case MONO_COUNTER_STRING
:
232 g_assert_not_reached ();
236 g_debug ("counters not enabled");
238 register_internal (name
, type
, addr
, size
);
242 * mono_counters_register_with_size:
243 * \param name The name for this counters.
244 * \param type One of the possible MONO_COUNTER types, or MONO_COUNTER_CALLBACK for a function pointer.
245 * \param addr The address to register.
246 * \param size Max size of the counter data.
248 * Register \p addr as the address of a counter of type \p type.
249 * Note that \p name must be a valid string at all times until
250 * \c mono_counters_dump() is called.
252 * It may be a function pointer if \c MONO_COUNTER_CALLBACK is specified:
253 * the function should return the value and take no arguments.
255 * The value of \p size is ignored for types with fixed size such as int and long.
257 * Use \p size for types that can have dynamic size such as string.
259 * If \p size is negative, it's silently converted to zero.
262 mono_counters_register_with_size (const char *name
, int type
, void *addr
, int size
)
265 g_debug ("counters not enabled");
267 register_internal (name
, type
, addr
, size
);
271 * mono_counters_on_register
272 * \param callback function to callback when a counter is registered
273 * Add a callback that is going to be called when a counter is registered
276 mono_counters_on_register (MonoCounterRegisterCallback callback
)
279 g_debug ("counters not enabled");
283 mono_os_mutex_lock (&counters_mutex
);
284 register_callbacks
= g_slist_append (register_callbacks
, (gpointer
) callback
);
285 mono_os_mutex_unlock (&counters_mutex
);
288 typedef int (*IntFunc
) (void);
289 typedef guint (*UIntFunc
) (void);
290 typedef gint64 (*LongFunc
) (void);
291 typedef guint64 (*ULongFunc
) (void);
292 typedef gssize (*PtrFunc
) (void);
293 typedef double (*DoubleFunc
) (void);
294 typedef char* (*StrFunc
) (void);
299 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_USER_TIME
);
305 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_SYSTEM_TIME
);
311 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_TOTAL_TIME
);
317 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_WORKING_SET
);
323 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_PRIVATE_BYTES
);
329 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_VIRTUAL_BYTES
);
335 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_FAULTS
);
341 return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_PAGED_BYTES
);
345 // If cpu_load gets inlined on Windows then cpu_load_1min, cpu_load_5min and cpu_load_15min can be folded into a single function and that will
346 // cause a failure when registering counters since the same function address will be used by all three functions. Preventing this method from being inlined
347 // will make sure the registered callback functions remains unique.
354 #if defined(TARGET_WIN32)
355 #elif defined(TARGET_MACH)
357 if (getloadavg (load
, 3) > 0)
360 char buffer
[512], *b
;
362 FILE *f
= fopen ("/proc/loadavg", "r");
364 len
= fread (buffer
, 1, sizeof (buffer
) - 1, f
);
367 buffer
[len
< 511 ? len
: 511] = 0;
369 for (i
= 0; i
< 3; i
++) {
371 return strtod (b
, NULL
);
398 cpu_load_15min (void)
403 #define SYSCOUNTER_TIME (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_TIME | MONO_COUNTER_MONOTONIC | MONO_COUNTER_CALLBACK)
404 #define SYSCOUNTER_BYTES (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_BYTES | MONO_COUNTER_VARIABLE | MONO_COUNTER_CALLBACK)
405 #define SYSCOUNTER_COUNT (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_COUNT | MONO_COUNTER_MONOTONIC | MONO_COUNTER_CALLBACK)
406 #define SYSCOUNTER_LOAD (MONO_COUNTER_SYSTEM | MONO_COUNTER_DOUBLE | MONO_COUNTER_PERCENTAGE | MONO_COUNTER_VARIABLE | MONO_COUNTER_CALLBACK)
409 initialize_system_counters (void)
411 register_internal ("User Time", SYSCOUNTER_TIME
, (gpointer
) &user_time
, sizeof (gint64
));
412 register_internal ("System Time", SYSCOUNTER_TIME
, (gpointer
) &system_time
, sizeof (gint64
));
413 register_internal ("Total Time", SYSCOUNTER_TIME
, (gpointer
) &total_time
, sizeof (gint64
));
414 register_internal ("Working Set", SYSCOUNTER_BYTES
, (gpointer
) &working_set
, sizeof (gint64
));
415 register_internal ("Private Bytes", SYSCOUNTER_BYTES
, (gpointer
) &private_bytes
, sizeof (gint64
));
416 register_internal ("Virtual Bytes", SYSCOUNTER_BYTES
, (gpointer
) &virtual_bytes
, sizeof (gint64
));
417 register_internal ("Page File Bytes", SYSCOUNTER_BYTES
, (gpointer
) &paged_bytes
, sizeof (gint64
));
418 register_internal ("Page Faults", SYSCOUNTER_COUNT
, (gpointer
) &page_faults
, sizeof (gint64
));
419 register_internal ("CPU Load Average - 1min", SYSCOUNTER_LOAD
, (gpointer
) &cpu_load_1min
, sizeof (double));
420 register_internal ("CPU Load Average - 5min", SYSCOUNTER_LOAD
, (gpointer
) &cpu_load_5min
, sizeof (double));
421 register_internal ("CPU Load Average - 15min", SYSCOUNTER_LOAD
, (gpointer
) &cpu_load_15min
, sizeof (double));
425 * mono_counters_foreach:
426 * \param cb The callback that will be called for each counter.
427 * \param user_data Value passed as second argument of the callback.
428 * Iterate over all counters and call \p cb for each one of them. Stop iterating if
429 * the callback returns FALSE.
432 mono_counters_foreach (CountersEnumCallback cb
, gpointer user_data
)
434 MonoCounter
*counter
;
437 g_debug ("counters not enabled");
441 mono_os_mutex_lock (&counters_mutex
);
443 for (counter
= counters
; counter
; counter
= counter
->next
) {
444 if (!cb (counter
, user_data
)) {
445 mono_os_mutex_unlock (&counters_mutex
);
450 mono_os_mutex_unlock (&counters_mutex
);
453 #define COPY_COUNTER(type,functype) do { \
454 size = sizeof (type); \
455 if (buffer_size < size) \
458 *(type*)buffer = cb ? ((functype)counter->addr) () : *(type*)counter->addr; \
463 sample_internal (MonoCounter
*counter
, void *buffer
, int buffer_size
)
465 int cb
= counter
->type
& MONO_COUNTER_CALLBACK
;
470 switch (mono_counter_get_type (counter
)) {
471 case MONO_COUNTER_INT
:
472 COPY_COUNTER (int, IntFunc
);
474 case MONO_COUNTER_UINT
:
475 COPY_COUNTER (guint
, UIntFunc
);
477 case MONO_COUNTER_LONG
:
478 case MONO_COUNTER_TIME_INTERVAL
:
479 COPY_COUNTER (gint64
, LongFunc
);
481 case MONO_COUNTER_ULONG
:
482 COPY_COUNTER (guint64
, ULongFunc
);
484 case MONO_COUNTER_WORD
:
485 COPY_COUNTER (gssize
, PtrFunc
);
487 case MONO_COUNTER_DOUBLE
:
488 COPY_COUNTER (double, DoubleFunc
);
490 case MONO_COUNTER_STRING
:
491 if (buffer_size
< counter
->size
) {
493 } else if (counter
->size
== 0) {
496 strval
= cb
? ((StrFunc
)counter
->addr
) () : (char*)counter
->addr
;
500 size
= counter
->size
;
501 memcpy ((char *) buffer
, strval
, size
- 1);
502 ((char*)buffer
)[size
- 1] = '\0';
511 mono_counters_sample (MonoCounter
*counter
, void *buffer
, int buffer_size
)
514 g_debug ("counters not enabled");
518 return sample_internal (counter
, buffer
, buffer_size
);
521 #define ENTRY_FMT "%-36s: "
523 dump_counter (MonoCounter
*counter
, FILE *outfile
) {
524 void *buffer
= g_malloc0 (counter
->size
);
525 int size
= sample_internal (counter
, buffer
, counter
->size
);
527 switch (counter
->type
& MONO_COUNTER_TYPE_MASK
) {
528 case MONO_COUNTER_INT
:
529 fprintf (outfile
, ENTRY_FMT
"%d\n", counter
->name
, *(int*)buffer
);
531 case MONO_COUNTER_UINT
:
532 fprintf (outfile
, ENTRY_FMT
"%u\n", counter
->name
, *(guint
*)buffer
);
534 case MONO_COUNTER_LONG
:
535 if ((counter
->type
& MONO_COUNTER_UNIT_MASK
) == MONO_COUNTER_TIME
)
536 fprintf (outfile
, ENTRY_FMT
"%.2f ms\n", counter
->name
, (double)(*(gint64
*)buffer
) / 10000.0);
538 fprintf (outfile
, ENTRY_FMT
"%lld\n", counter
->name
, *(long long *)buffer
);
540 case MONO_COUNTER_ULONG
:
541 if ((counter
->type
& MONO_COUNTER_UNIT_MASK
) == MONO_COUNTER_TIME
)
542 fprintf (outfile
, ENTRY_FMT
"%.2f ms\n", counter
->name
, (double)(*(guint64
*)buffer
) / 10000.0);
544 fprintf (outfile
, ENTRY_FMT
"%llu\n", counter
->name
, *(unsigned long long *)buffer
);
546 case MONO_COUNTER_WORD
:
547 fprintf (outfile
, ENTRY_FMT
"%lld\n", counter
->name
, (long long)*(gssize
*)buffer
);
549 case MONO_COUNTER_DOUBLE
:
550 fprintf (outfile
, ENTRY_FMT
"%.4f\n", counter
->name
, *(double*)buffer
);
552 case MONO_COUNTER_STRING
:
553 fprintf (outfile
, ENTRY_FMT
"%s\n", counter
->name
, (size
== 0) ? "(null)" : (char*)buffer
);
555 case MONO_COUNTER_TIME_INTERVAL
:
556 fprintf (outfile
, ENTRY_FMT
"%.2f ms\n", counter
->name
, (double)(*(gint64
*)buffer
) / 1000.0);
564 section_names
[][12] = {
572 "", // MONO_COUNTER_PERFCOUNTERS - not used.
577 mono_counters_dump_section (int section
, int variance
, FILE *outfile
)
579 MonoCounter
*counter
= counters
;
581 if ((counter
->type
& section
) && (mono_counter_get_variance (counter
) & variance
))
582 dump_counter (counter
, outfile
);
583 counter
= counter
->next
;
588 * mono_counters_dump:
589 * \param section_mask The sections to dump counters for
590 * \param outfile a FILE to dump the results to
591 * Displays the counts of all the enabled counters registered.
592 * To filter by variance, you can OR one or more variance with the specific section you want.
593 * Use \c MONO_COUNTER_SECTION_MASK to dump all categories of a specific variance.
596 mono_counters_dump (int section_mask
, FILE *outfile
)
600 section_mask
&= valid_mask
;
605 mono_os_mutex_lock (&counters_mutex
);
608 mono_os_mutex_unlock (&counters_mutex
);
612 variance
= section_mask
& MONO_COUNTER_VARIANCE_MASK
;
614 /* If no variance mask is supplied, we default to all kinds. */
616 variance
= MONO_COUNTER_VARIANCE_MASK
;
617 section_mask
&= ~MONO_COUNTER_VARIANCE_MASK
;
619 for (j
= 0, i
= MONO_COUNTER_JIT
; i
< MONO_COUNTER_LAST_SECTION
; j
++, i
<<= 1) {
620 if ((section_mask
& i
) && (set_mask
& i
)) {
621 fprintf (outfile
, "\n%s statistics\n", section_names
[j
]);
622 mono_counters_dump_section (i
, variance
, outfile
);
627 mono_os_mutex_unlock (&counters_mutex
);
631 * mono_counters_cleanup:
633 * Perform any needed cleanup at process exit.
636 mono_counters_cleanup (void)
638 MonoCounter
*counter
;
643 mono_os_mutex_lock (&counters_mutex
);
648 MonoCounter
*tmp
= counter
;
649 counter
= counter
->next
;
650 g_free ((void*)tmp
->name
);
654 mono_os_mutex_unlock (&counters_mutex
);
657 static MonoResourceCallback limit_reached
= NULL
;
658 static uintptr_t resource_limits
[MONO_RESOURCE_COUNT
* 2];
661 * mono_runtime_resource_check_limit:
662 * \param resource_type one of the \c MonoResourceType enum values
663 * \param value the current value of the resource usage
664 * Check if a runtime resource limit has been reached. This function
665 * is intended to be used by the runtime only.
668 mono_runtime_resource_check_limit (int resource_type
, uintptr_t value
)
672 /* check the hard limit first */
673 if (value
> resource_limits
[resource_type
* 2 + 1]) {
674 limit_reached (resource_type
, value
, 0);
677 if (value
> resource_limits
[resource_type
* 2])
678 limit_reached (resource_type
, value
, 1);
682 * mono_runtime_resource_limit:
683 * \param resource_type one of the \c MonoResourceType enum values
684 * \param soft_limit the soft limit value
685 * \param hard_limit the hard limit value
686 * This function sets the soft and hard limit for runtime resources. When the limit
687 * is reached, a user-specified callback is called. The callback runs in a restricted
688 * environment, in which the world coult be stopped, so it can't take locks, perform
689 * allocations etc. The callback may be called multiple times once a limit has been reached
690 * if action is not taken to decrease the resource use.
691 * \returns 0 on error or a positive integer otherwise.
694 mono_runtime_resource_limit (int resource_type
, uintptr_t soft_limit
, uintptr_t hard_limit
)
696 if (resource_type
>= MONO_RESOURCE_COUNT
|| resource_type
< 0)
698 if (soft_limit
> hard_limit
)
700 resource_limits
[resource_type
* 2] = soft_limit
;
701 resource_limits
[resource_type
* 2 + 1] = hard_limit
;
706 * mono_runtime_resource_set_callback:
707 * \param callback a function pointer
708 * Set the callback to be invoked when a resource limit is reached.
709 * The callback will receive the resource type, the resource amount in resource-specific
710 * units and a flag indicating whether the soft or hard limit was reached.
713 mono_runtime_resource_set_callback (MonoResourceCallback callback
)
715 limit_reached
= callback
;