[sgen] Scan pinned objects in nursery as part of concurrent mark
[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 "config.h"
9 #include "mono-counters.h"
10 #include "mono-proclib.h"
11 #include "mono-os-mutex.h"
12
13 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16
17 struct _MonoCounter {
18         MonoCounter *next;
19         const char *name;
20         void *addr;
21         int type;
22         size_t size;
23 };
24
25 static MonoCounter *counters = NULL;
26 static mono_mutex_t counters_mutex;
27
28 static volatile gboolean initialized = FALSE;
29
30 static int valid_mask = 0;
31 static int set_mask = 0;
32
33 static GSList *register_callbacks = NULL;
34
35 static void initialize_system_counters (void);
36
37 /**
38  * mono_counter_get_variance:
39  * @counter: counter to get the variance
40  *
41  * Variance specifies how the counter value is expected to behave between any two samplings.
42  *
43  * Returns: the monotonicity of the counter.
44  */
45 int
46 mono_counter_get_variance (MonoCounter *counter)
47 {
48         return counter->type & MONO_COUNTER_VARIANCE_MASK;
49 }
50
51 /**
52  * mono_counter_get_unit:
53  * @counter: counter to get the unit
54  *
55  * The unit gives a high level view of the unit that the counter is measuring.
56  *
57  * Returns: the unit of the counter.
58  */
59 int
60 mono_counter_get_unit (MonoCounter *counter)
61 {
62         return counter->type & MONO_COUNTER_UNIT_MASK;
63 }
64
65 /**
66  * mono_counter_get_section:
67  * @counter: counter to get the section
68  *
69  * Sections are the unit of organization between all counters.
70  *
71  * Returns: the section of the counter.
72  */
73
74 int
75 mono_counter_get_section (MonoCounter *counter)
76 {
77         return counter->type & MONO_COUNTER_SECTION_MASK;
78 }
79
80 /**
81  * mono_counter_get_type:
82  * @counter: counter to get the type
83  *
84  * Returns the type used to strong the value of the counter.
85  *
86  * Returns:the type of the counter.
87  */
88 int
89 mono_counter_get_type (MonoCounter *counter)
90 {
91         return counter->type & MONO_COUNTER_TYPE_MASK;
92 }
93
94 /**
95  * mono_counter_get_name:
96  * @counter: counter to get the name
97  *
98  * Returns the counter name. The string should not be freed.
99  *
100  * Returns the name of the counter.
101  */
102
103 const char*
104 mono_counter_get_name (MonoCounter *counter)
105 {
106         return counter->name;
107 }
108
109 /**
110  * mono_counter_get_size:
111  * @counter: counter to get the max size of the counter
112  *
113  * Use the returned size to create the buffer used with mono_counters_sample
114  *
115  * Returns: the max size of the counter data.
116  */
117 size_t
118 mono_counter_get_size (MonoCounter *counter)
119 {
120         return counter->size;
121 }
122
123 /**
124  * mono_counters_enable:
125  * @section_mask: a mask listing the sections that will be displayed
126  *
127  * This is used to track which counters will be displayed.
128  */
129 void
130 mono_counters_enable (int section_mask)
131 {
132         valid_mask = section_mask & MONO_COUNTER_SECTION_MASK;
133 }
134
135 void
136 mono_counters_init (void)
137 {
138         if (initialized)
139                 return;
140
141         mono_os_mutex_init (&counters_mutex);
142
143         initialize_system_counters ();
144
145         initialized = TRUE;
146 }
147
148 static void
149 register_internal (const char *name, int type, void *addr, int size)
150 {
151         MonoCounter *counter;
152         GSList *register_callback;
153
154         g_assert (size >= 0);
155         if ((type & MONO_COUNTER_VARIANCE_MASK) == 0)
156                 type |= MONO_COUNTER_MONOTONIC;
157
158         mono_os_mutex_lock (&counters_mutex);
159
160         for (counter = counters; counter; counter = counter->next) {
161                 if (counter->addr == addr) {
162                         g_warning ("you are registering twice the same counter address");
163                         mono_os_mutex_unlock (&counters_mutex);
164                         return;
165                 }
166         }
167
168         counter = (MonoCounter *) malloc (sizeof (MonoCounter));
169         if (!counter) {
170                 mono_os_mutex_unlock (&counters_mutex);
171                 return;
172         }
173         counter->name = g_strdup (name);
174         counter->type = type;
175         counter->addr = addr;
176         counter->next = NULL;
177         counter->size = size;
178
179         set_mask |= type;
180
181         /* Append */
182         if (counters) {
183                 MonoCounter *item = counters;
184                 while (item->next)
185                         item = item->next;
186                 item->next = counter;
187         } else {
188                 counters = counter;
189         }
190
191         for (register_callback = register_callbacks; register_callback; register_callback = register_callback->next)
192                 ((MonoCounterRegisterCallback)register_callback->data) (counter);
193
194         mono_os_mutex_unlock (&counters_mutex);
195 }
196
197 /**
198  * mono_counters_register:
199  * @name: The name for this counters.
200  * @type: One of the possible MONO_COUNTER types, or MONO_COUNTER_CALLBACK for a function pointer.
201  * @addr: The address to register.
202  *
203  * Register addr as the address of a counter of type type.
204  * Note that @name must be a valid string at all times until
205  * mono_counters_dump () is called.
206  *
207  * This function should not be used with counter types that require an explicit size such as string
208  * as the counter size will be set to zero making them effectively useless.
209  *
210  *
211  * It may be a function pointer if MONO_COUNTER_CALLBACK is specified:
212  * the function should return the value and take no arguments.
213  */
214 void 
215 mono_counters_register (const char* name, int type, void *addr)
216 {
217         int size;
218         switch (type & MONO_COUNTER_TYPE_MASK) {
219         case MONO_COUNTER_INT:
220                 size = sizeof (int);
221                 break;
222         case MONO_COUNTER_UINT:
223                 size = sizeof (guint);
224                 break;
225         case MONO_COUNTER_LONG:
226         case MONO_COUNTER_TIME_INTERVAL:
227                 size = sizeof (gint64);
228                 break;
229         case MONO_COUNTER_ULONG:
230                 size = sizeof (guint64);
231                 break;
232         case MONO_COUNTER_WORD:
233                 size = sizeof (gssize);
234                 break;
235         case MONO_COUNTER_DOUBLE:
236                 size = sizeof (double);
237                 break;
238         case MONO_COUNTER_STRING:
239                 size = 0;
240                 break;
241         default:
242                 g_assert_not_reached ();
243         }
244
245         if (!initialized)
246                 g_debug ("counters not enabled");
247         else
248                 register_internal (name, type, addr, size);
249 }
250
251 /**
252  * mono_counters_register_with_size:
253  * @name: The name for this counters.
254  * @type: One of the possible MONO_COUNTER types, or MONO_COUNTER_CALLBACK for a function pointer.
255  * @addr: The address to register.
256  * @size: Max size of the counter data.
257  *
258  * Register addr as the address of a counter of type @type.
259  * Note that @name must be a valid string at all times until
260  * mono_counters_dump () is called.
261  *
262  * It may be a function pointer if MONO_COUNTER_CALLBACK is specified:
263  * the function should return the value and take no arguments.
264  *
265  * The value of @size is ignored for types with fixed size such as int and long.
266  *
267  * Use @size for types that can have dynamic size such as string.
268  *
269  * If @size is negative, it's silently converted to zero.
270  */
271 void
272 mono_counters_register_with_size (const char *name, int type, void *addr, int size)
273 {
274         if (!initialized)
275                 g_debug ("counters not enabled");
276         else
277                 register_internal (name, type, addr, size);
278 }
279
280 /**
281  * mono_counters_on_register
282  * @callback : function to callback when a counter is registered
283  *
284  * Add a callback that is going to be called when a counter is registered
285  */
286 void
287 mono_counters_on_register (MonoCounterRegisterCallback callback)
288 {
289         if (!initialized) {
290                 g_debug ("counters not enabled");
291                 return;
292         }
293
294         mono_os_mutex_lock (&counters_mutex);
295         register_callbacks = g_slist_append (register_callbacks, (gpointer) callback);
296         mono_os_mutex_unlock (&counters_mutex);
297 }
298
299 typedef int (*IntFunc) (void);
300 typedef guint (*UIntFunc) (void);
301 typedef gint64 (*LongFunc) (void);
302 typedef guint64 (*ULongFunc) (void);
303 typedef gssize (*PtrFunc) (void);
304 typedef double (*DoubleFunc) (void);
305 typedef char* (*StrFunc) (void);
306
307 static gint64
308 user_time (void)
309 {
310         return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_USER_TIME);
311 }
312
313 static gint64
314 system_time (void)
315 {
316         return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_SYSTEM_TIME);
317 }
318
319 static gint64
320 total_time (void)
321 {
322         return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_TOTAL_TIME);
323 }
324
325 static gint64
326 working_set (void)
327 {
328         return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_WORKING_SET);
329 }
330
331 static gint64
332 private_bytes (void)
333 {
334         return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_PRIVATE_BYTES);
335 }
336
337 static gint64
338 virtual_bytes (void)
339 {
340         return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_VIRTUAL_BYTES);
341 }
342
343 static gint64
344 page_faults (void)
345 {
346         return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_FAULTS);
347 }
348
349 static double
350 cpu_load (int kind)
351 {
352 #if defined(TARGET_WIN32)
353 #elif defined(TARGET_MACH)
354         double load [3];
355         if (getloadavg (load, 3) > 0)
356                 return load [kind];
357 #else
358         char buffer[512], *b;
359         int len, i;
360         FILE *f = fopen ("/proc/loadavg", "r");
361         if (f) {
362                 len = fread (buffer, 1, sizeof (buffer) - 1, f);
363                 fclose (f);
364                 if (len > 0) {
365                         buffer [len < 511 ? len : 511] = 0;
366                         b = buffer;
367                         for (i = 0; i < 3; i++) {
368                                 if (kind == i)
369                                         return strtod (b, NULL);
370                                 if (i < 2) {
371                                         b = strchr (b, ' ');
372                                         if (!b)
373                                                 return 0;
374                                         b += 1;
375                                 }
376                         }
377                 }
378         }
379 #endif
380         return 0;
381 }
382
383 static double
384 cpu_load_1min (void)
385 {
386         return cpu_load (0);
387 }
388
389 static double
390 cpu_load_5min (void)
391 {
392         return cpu_load (1);
393 }
394
395 static double
396 cpu_load_15min (void)
397 {
398         return cpu_load (2);
399 }
400
401 #define SYSCOUNTER_TIME (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_TIME | MONO_COUNTER_MONOTONIC | MONO_COUNTER_CALLBACK)
402 #define SYSCOUNTER_BYTES (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_BYTES | MONO_COUNTER_VARIABLE | MONO_COUNTER_CALLBACK)
403 #define SYSCOUNTER_COUNT (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_COUNT | MONO_COUNTER_MONOTONIC | MONO_COUNTER_CALLBACK)
404 #define SYSCOUNTER_LOAD (MONO_COUNTER_SYSTEM | MONO_COUNTER_DOUBLE | MONO_COUNTER_PERCENTAGE | MONO_COUNTER_VARIABLE | MONO_COUNTER_CALLBACK)
405
406 static void
407 initialize_system_counters (void)
408 {
409         register_internal ("User Time", SYSCOUNTER_TIME, (gpointer) &user_time, sizeof (gint64));
410         register_internal ("System Time", SYSCOUNTER_TIME, (gpointer) &system_time, sizeof (gint64));
411         register_internal ("Total Time", SYSCOUNTER_TIME, (gpointer) &total_time, sizeof (gint64));
412         register_internal ("Working Set", SYSCOUNTER_BYTES, (gpointer) &working_set, sizeof (gint64));
413         register_internal ("Private Bytes", SYSCOUNTER_BYTES, (gpointer) &private_bytes, sizeof (gint64));
414         register_internal ("Virtual Bytes", SYSCOUNTER_BYTES, (gpointer) &virtual_bytes, sizeof (gint64));
415         register_internal ("Page Faults", SYSCOUNTER_COUNT, (gpointer) &page_faults, sizeof (gint64));
416         register_internal ("CPU Load Average - 1min", SYSCOUNTER_LOAD, (gpointer) &cpu_load_1min, sizeof (double));
417         register_internal ("CPU Load Average - 5min", SYSCOUNTER_LOAD, (gpointer) &cpu_load_5min, sizeof (double));
418         register_internal ("CPU Load Average - 15min", SYSCOUNTER_LOAD, (gpointer) &cpu_load_15min, sizeof (double));
419 }
420
421 /**
422  * mono_counters_foreach:
423  * @cb: The callback that will be called for each counter.
424  * @user_data: Value passed as second argument of the callback.
425  *
426  * Iterate over all counters and call @cb for each one of them. Stop iterating if
427  * the callback returns FALSE.
428  *
429  */
430 void
431 mono_counters_foreach (CountersEnumCallback cb, gpointer user_data)
432 {
433         MonoCounter *counter;
434
435         if (!initialized) {
436                 g_debug ("counters not enabled");
437                 return;
438         }
439
440         mono_os_mutex_lock (&counters_mutex);
441
442         for (counter = counters; counter; counter = counter->next) {
443                 if (!cb (counter, user_data)) {
444                         mono_os_mutex_unlock (&counters_mutex);
445                         return;
446                 }
447         }
448
449         mono_os_mutex_unlock (&counters_mutex);
450 }
451
452 #define COPY_COUNTER(type,functype) do {        \
453                 size = sizeof (type);   \
454                 if (buffer_size < size) \
455                         size = -1;      \
456                 else                    \
457                         *(type*)buffer = cb ? ((functype)counter->addr) () : *(type*)counter->addr; \
458         } while (0);
459
460 /* lockless */
461 static int
462 sample_internal (MonoCounter *counter, void *buffer, int buffer_size)
463 {
464         int cb = counter->type & MONO_COUNTER_CALLBACK;
465         int size = -1;
466
467         char *strval;
468
469         switch (mono_counter_get_type (counter)) {
470         case MONO_COUNTER_INT:
471                 COPY_COUNTER (int, IntFunc);
472                 break;
473         case MONO_COUNTER_UINT:
474                 COPY_COUNTER (guint, UIntFunc);
475                 break;
476         case MONO_COUNTER_LONG:
477         case MONO_COUNTER_TIME_INTERVAL:
478                 COPY_COUNTER (gint64, LongFunc);
479                 break;
480         case MONO_COUNTER_ULONG:
481                 COPY_COUNTER (guint64, ULongFunc);
482                 break;
483         case MONO_COUNTER_WORD:
484                 COPY_COUNTER (gssize, PtrFunc);
485                 break;
486         case MONO_COUNTER_DOUBLE:
487                 COPY_COUNTER (double, DoubleFunc);
488                 break;
489         case MONO_COUNTER_STRING:
490                 if (buffer_size < counter->size) {
491                         size = -1;
492                 } else if (counter->size == 0) {
493                         size = 0;
494                 } else {
495                         strval = cb ? ((StrFunc)counter->addr) () : (char*)counter->addr;
496                         if (!strval) {
497                                 size = 0;
498                         } else {
499                                 size = counter->size;
500                                 strncpy ((char *) buffer, strval, size - 1);
501                                 ((char*)buffer)[size - 1] = '\0';
502                         }
503                 }
504         }
505
506         return size;
507 }
508
509 int
510 mono_counters_sample (MonoCounter *counter, void *buffer, int buffer_size)
511 {
512         if (!initialized) {
513                 g_debug ("counters not enabled");
514                 return -1;
515         }
516
517         return sample_internal (counter, buffer, buffer_size);
518 }
519
520 #define ENTRY_FMT "%-36s: "
521 static void
522 dump_counter (MonoCounter *counter, FILE *outfile) {
523         void *buffer = g_malloc0 (counter->size);
524         int size = sample_internal (counter, buffer, counter->size);
525
526         switch (counter->type & MONO_COUNTER_TYPE_MASK) {
527         case MONO_COUNTER_INT:
528                 fprintf (outfile, ENTRY_FMT "%d\n", counter->name, *(int*)buffer);
529                 break;
530         case MONO_COUNTER_UINT:
531                 fprintf (outfile, ENTRY_FMT "%u\n", counter->name, *(guint*)buffer);
532                 break;
533         case MONO_COUNTER_LONG:
534                 if ((counter->type & MONO_COUNTER_UNIT_MASK) == MONO_COUNTER_TIME)
535                         fprintf (outfile, ENTRY_FMT "%.2f ms\n", counter->name, (double)(*(gint64*)buffer) / 10000.0);
536                 else
537                         fprintf (outfile, ENTRY_FMT "%lld\n", counter->name, *(long long *)buffer);
538                 break;
539         case MONO_COUNTER_ULONG:
540                 if ((counter->type & MONO_COUNTER_UNIT_MASK) == MONO_COUNTER_TIME)
541                         fprintf (outfile, ENTRY_FMT "%.2f ms\n", counter->name, (double)(*(guint64*)buffer) / 10000.0);
542                 else
543                         fprintf (outfile, ENTRY_FMT "%llu\n", counter->name, *(unsigned long long *)buffer);
544                 break;
545         case MONO_COUNTER_WORD:
546                 fprintf (outfile, ENTRY_FMT "%zd\n", counter->name, *(gssize*)buffer);
547                 break;
548         case MONO_COUNTER_DOUBLE:
549                 fprintf (outfile, ENTRY_FMT "%.4f\n", counter->name, *(double*)buffer);
550                 break;
551         case MONO_COUNTER_STRING:
552                 fprintf (outfile, ENTRY_FMT "%s\n", counter->name, (size == 0) ? "(null)" : (char*)buffer);
553                 break;
554         case MONO_COUNTER_TIME_INTERVAL:
555                 fprintf (outfile, ENTRY_FMT "%.2f ms\n", counter->name, (double)(*(gint64*)buffer) / 1000.0);
556                 break;
557         }
558
559         g_free (buffer);
560 }
561
562 static const char
563 section_names [][10] = {
564         "JIT",
565         "GC",
566         "Metadata",
567         "Generics",
568         "Security",
569         "Runtime",
570         "System",
571 };
572
573 static void
574 mono_counters_dump_section (int section, int variance, FILE *outfile)
575 {
576         MonoCounter *counter = counters;
577         while (counter) {
578                 if ((counter->type & section) && (mono_counter_get_variance (counter) & variance))
579                         dump_counter (counter, outfile);
580                 counter = counter->next;
581         }
582 }
583
584 /**
585  * mono_counters_dump:
586  * @section_mask: The sections to dump counters for
587  * @outfile: a FILE to dump the results to
588  *
589  * Displays the counts of all the enabled counters registered. 
590  * To filter by variance, you can OR one or more variance with the specific section you want.
591  * Use MONO_COUNTER_SECTION_MASK to dump all categories of a specific variance.
592  */
593 void
594 mono_counters_dump (int section_mask, FILE *outfile)
595 {
596         int i, j;
597         int variance;
598         section_mask &= valid_mask;
599
600         if (!initialized)
601                 return;
602
603         mono_os_mutex_lock (&counters_mutex);
604
605         if (!counters) {
606                 mono_os_mutex_unlock (&counters_mutex);
607                 return;
608         }
609
610         variance = section_mask & MONO_COUNTER_VARIANCE_MASK;
611
612         /* If no variance mask is supplied, we default to all kinds. */
613         if (!variance)
614                 variance = MONO_COUNTER_VARIANCE_MASK;
615         section_mask &= ~MONO_COUNTER_VARIANCE_MASK;
616
617         for (j = 0, i = MONO_COUNTER_JIT; i < MONO_COUNTER_LAST_SECTION; j++, i <<= 1) {
618                 if ((section_mask & i) && (set_mask & i)) {
619                         fprintf (outfile, "\n%s statistics\n", section_names [j]);
620                         mono_counters_dump_section (i, variance, outfile);
621                 }
622         }
623
624         fflush (outfile);
625         mono_os_mutex_unlock (&counters_mutex);
626 }
627
628 /**
629  * mono_counters_cleanup:
630  *
631  * Perform any needed cleanup at process exit.
632  */
633 void
634 mono_counters_cleanup (void)
635 {
636         MonoCounter *counter;
637
638         if (!initialized)
639                 return;
640
641         mono_os_mutex_lock (&counters_mutex);
642
643         counter = counters;
644         counters = NULL;
645         while (counter) {
646                 MonoCounter *tmp = counter;
647                 counter = counter->next;
648                 free ((void*)tmp->name);
649                 free (tmp);
650         }
651
652         mono_os_mutex_unlock (&counters_mutex);
653 }
654
655 static MonoResourceCallback limit_reached = NULL;
656 static uintptr_t resource_limits [MONO_RESOURCE_COUNT * 2];
657
658 /**
659  * mono_runtime_resource_check_limit:
660  * @resource_type: one of the #MonoResourceType enum values
661  * @value: the current value of the resource usage
662  *
663  * Check if a runtime resource limit has been reached. This function
664  * is intended to be used by the runtime only.
665  */
666 void
667 mono_runtime_resource_check_limit (int resource_type, uintptr_t value)
668 {
669         if (!limit_reached)
670                 return;
671         /* check the hard limit first */
672         if (value > resource_limits [resource_type * 2 + 1]) {
673                 limit_reached (resource_type, value, 0);
674                 return;
675         }
676         if (value > resource_limits [resource_type * 2])
677                 limit_reached (resource_type, value, 1);
678 }
679
680 /**
681  * mono_runtime_resource_limit:
682  * @resource_type: one of the #MonoResourceType enum values
683  * @soft_limit: the soft limit value
684  * @hard_limit: the hard limit value
685  *
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  *
692  * Returns: 0 on error or a positive integer otherwise.
693  */
694 int
695 mono_runtime_resource_limit (int resource_type, uintptr_t soft_limit, uintptr_t hard_limit)
696 {
697         if (resource_type >= MONO_RESOURCE_COUNT || resource_type < 0)
698                 return 0;
699         if (soft_limit > hard_limit)
700                 return 0;
701         resource_limits [resource_type * 2] = soft_limit;
702         resource_limits [resource_type * 2 + 1] = hard_limit;
703         return 1;
704 }
705
706 /**
707  * mono_runtime_resource_set_callback:
708  * @callback: a function pointer
709  * 
710  * Set the callback to be invoked when a resource limit is reached.
711  * The callback will receive the resource type, the resource amount in resource-specific
712  * units and a flag indicating whether the soft or hard limit was reached.
713  */
714 void
715 mono_runtime_resource_set_callback (MonoResourceCallback callback)
716 {
717         limit_reached = callback;
718 }
719
720