Add new counter type for time intervals.
[mono-project.git] / mono / utils / mono-counters.c
blobe55114beee80b12b5e29c90b0a3c28b68d93bfc6
1 /*
2 * Copyright 2006-2010 Novell
3 * Copyright 2011 Xamarin Inc
4 */
6 #include <stdlib.h>
7 #include <glib.h>
8 #include "mono-counters.h"
10 typedef struct _MonoCounter MonoCounter;
12 struct _MonoCounter {
13 MonoCounter *next;
14 const char *name;
15 void *addr;
16 int type;
19 static MonoCounter *counters = NULL;
20 static int valid_mask = 0;
21 static int set_mask = 0;
23 /**
24 * mono_counters_enable:
25 * @section_mask: a mask listing the sections that will be displayed
27 * This is used to track which counters will be displayed.
29 void
30 mono_counters_enable (int section_mask)
32 valid_mask = section_mask & MONO_COUNTER_SECTION_MASK;
35 /**
36 * mono_counters_register:
37 * @name: The name for this counters.
38 * @type: One of the possible MONO_COUNTER types, or MONO_COUNTER_CALLBACK for a function pointer.
39 * @addr: The address to register.
41 * Register addr as the address of a counter of type type.
42 * Note that @name must be a valid string at all times until
43 * mono_counters_dump () is called.
45 * It may be a function pointer if MONO_COUNTER_CALLBACK is specified:
46 * the function should return the value and take no arguments.
48 void
49 mono_counters_register (const char* name, int type, void *addr)
51 MonoCounter *counter;
52 if (!(type & valid_mask))
53 return;
54 counter = malloc (sizeof (MonoCounter));
55 if (!counter)
56 return;
57 counter->name = name;
58 counter->type = type;
59 counter->addr = addr;
60 counter->next = NULL;
62 set_mask |= type;
64 /* Append */
65 if (counters) {
66 MonoCounter *item = counters;
67 while (item->next)
68 item = item->next;
69 item->next = counter;
70 } else {
71 counters = counter;
75 typedef int (*IntFunc) (void);
76 typedef guint (*UIntFunc) (void);
77 typedef gint64 (*LongFunc) (void);
78 typedef guint64 (*ULongFunc) (void);
79 typedef gssize (*PtrFunc) (void);
80 typedef double (*DoubleFunc) (void);
81 typedef char* (*StrFunc) (void);
83 #define ENTRY_FMT "%-36s: "
84 static void
85 dump_counter (MonoCounter *counter, FILE *outfile) {
86 int intval;
87 guint uintval;
88 gint64 int64val;
89 guint64 uint64val;
90 gssize wordval;
91 double dval;
92 const char *str;
93 switch (counter->type & MONO_COUNTER_TYPE_MASK) {
94 case MONO_COUNTER_INT:
95 if (counter->type & MONO_COUNTER_CALLBACK)
96 intval = ((IntFunc)counter->addr) ();
97 else
98 intval = *(int*)counter->addr;
99 fprintf (outfile, ENTRY_FMT "%d\n", counter->name, intval);
100 break;
101 case MONO_COUNTER_UINT:
102 if (counter->type & MONO_COUNTER_CALLBACK)
103 uintval = ((UIntFunc)counter->addr) ();
104 else
105 uintval = *(guint*)counter->addr;
106 fprintf (outfile, ENTRY_FMT "%u\n", counter->name, uintval);
107 break;
108 case MONO_COUNTER_LONG:
109 if (counter->type & MONO_COUNTER_CALLBACK)
110 int64val = ((LongFunc)counter->addr) ();
111 else
112 int64val = *(gint64*)counter->addr;
113 fprintf (outfile, ENTRY_FMT "%lld\n", counter->name, (long long)int64val);
114 break;
115 case MONO_COUNTER_ULONG:
116 if (counter->type & MONO_COUNTER_CALLBACK)
117 uint64val = ((ULongFunc)counter->addr) ();
118 else
119 uint64val = *(guint64*)counter->addr;
120 fprintf (outfile, ENTRY_FMT "%llu\n", counter->name, (unsigned long long)uint64val);
121 break;
122 case MONO_COUNTER_WORD:
123 if (counter->type & MONO_COUNTER_CALLBACK)
124 wordval = ((PtrFunc)counter->addr) ();
125 else
126 wordval = *(gssize*)counter->addr;
127 #if SIZEOF_VOID_P == 8
128 fprintf (outfile, ENTRY_FMT "%lld\n", counter->name, (gint64)wordval);
129 #else
130 fprintf (outfile, ENTRY_FMT "%d\n", counter->name, (gint)wordval);
131 #endif
132 break;
133 case MONO_COUNTER_DOUBLE:
134 if (counter->type & MONO_COUNTER_CALLBACK)
135 dval = ((DoubleFunc)counter->addr) ();
136 else
137 dval = *(double*)counter->addr;
138 fprintf (outfile, ENTRY_FMT "%.4f\n", counter->name, dval);
139 break;
140 case MONO_COUNTER_STRING:
141 if (counter->type & MONO_COUNTER_CALLBACK)
142 str = ((StrFunc)counter->addr) ();
143 else
144 str = *(char**)counter->addr;
145 fprintf (outfile, ENTRY_FMT "%s\n", counter->name, str);
146 break;
147 case MONO_COUNTER_TIME_INTERVAL:
148 if (counter->type & MONO_COUNTER_CALLBACK)
149 int64val = ((LongFunc)counter->addr) ();
150 else
151 int64val = *(gint64*)counter->addr;
152 fprintf (outfile, ENTRY_FMT "%.2f ms\n", counter->name, (double)int64val / 1000.0);
153 break;
157 static const char
158 section_names [][10] = {
159 "JIT",
160 "GC",
161 "Metadata",
162 "Generics",
163 "Security"
166 static void
167 mono_counters_dump_section (int section, FILE *outfile)
169 MonoCounter *counter = counters;
170 while (counter) {
171 if (counter->type & section)
172 dump_counter (counter, outfile);
173 counter = counter->next;
178 * mono_counters_dump:
179 * @section_mask: The sections to dump counters for
180 * @outfile: a FILE to dump the results to
182 * Displays the counts of all the enabled counters registered.
184 void
185 mono_counters_dump (int section_mask, FILE *outfile)
187 int i, j;
188 section_mask &= valid_mask;
189 if (!counters)
190 return;
191 for (j = 0, i = MONO_COUNTER_JIT; i < MONO_COUNTER_LAST_SECTION; j++, i <<= 1) {
192 if ((section_mask & i) && (set_mask & i)) {
193 fprintf (outfile, "\n%s statistics\n", section_names [j]);
194 mono_counters_dump_section (i, outfile);
198 fflush (outfile);
202 * mono_counters_cleanup:
204 * Perform any needed cleanup at process exit.
206 void
207 mono_counters_cleanup (void)
209 MonoCounter *counter = counters;
210 while (counter) {
211 MonoCounter *tmp = counters;
212 counter = counter->next;
213 free (tmp);
215 counters = NULL;
218 static MonoResourceCallback limit_reached = NULL;
219 static uintptr_t resource_limits [MONO_RESOURCE_COUNT * 2];
222 * mono_runtime_resource_check_limit:
223 * @resource_type: one of the #MonoResourceType enum values
224 * @value: the current value of the resource usage
226 * Check if a runtime resource limit has been reached. This function
227 * is intended to be used by the runtime only.
229 void
230 mono_runtime_resource_check_limit (int resource_type, uintptr_t value)
232 if (!limit_reached)
233 return;
234 /* check the hard limit first */
235 if (value > resource_limits [resource_type * 2 + 1]) {
236 limit_reached (resource_type, value, 0);
237 return;
239 if (value > resource_limits [resource_type * 2])
240 limit_reached (resource_type, value, 1);
244 * mono_runtime_resource_limit:
245 * @resource_type: one of the #MonoResourceType enum values
246 * @soft_limit: the soft limit value
247 * @hard_limit: the hard limit value
249 * This function sets the soft and hard limit for runtime resources. When the limit
250 * is reached, a user-specified callback is called. The callback runs in a restricted
251 * environment, in which the world coult be stopped, so it can't take locks, perform
252 * allocations etc. The callback may be called multiple times once a limit has been reached
253 * if action is not taken to decrease the resource use.
255 * Returns: 0 on error or a positive integer otherwise.
258 mono_runtime_resource_limit (int resource_type, uintptr_t soft_limit, uintptr_t hard_limit)
260 if (resource_type >= MONO_RESOURCE_COUNT || resource_type < 0)
261 return 0;
262 if (soft_limit > hard_limit)
263 return 0;
264 resource_limits [resource_type * 2] = soft_limit;
265 resource_limits [resource_type * 2 + 1] = hard_limit;
266 return 1;
270 * mono_runtime_resource_set_callback:
271 * @callback: a function pointer
273 * Set the callback to be invoked when a resource limit is reached.
274 * The callback will receive the resource type, the resource amount in resource-specific
275 * units and a flag indicating whether the soft or hard limit was reached.
277 void
278 mono_runtime_resource_set_callback (MonoResourceCallback callback)
280 limit_reached = callback;