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