2 * Copyright 2006-2010 Novell
3 * Copyright 2011 Xamarin Inc
8 #include "mono-counters.h"
10 typedef struct _MonoCounter MonoCounter
;
19 static MonoCounter
*counters
= NULL
;
20 static int valid_mask
= 0;
21 static int set_mask
= 0;
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.
30 mono_counters_enable (int section_mask
)
32 valid_mask
= section_mask
& MONO_COUNTER_SECTION_MASK
;
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.
49 mono_counters_register (const char* name
, int type
, void *addr
)
52 if (!(type
& valid_mask
))
54 counter
= malloc (sizeof (MonoCounter
));
66 MonoCounter
*item
= counters
;
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: "
85 dump_counter (MonoCounter
*counter
, FILE *outfile
) {
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
) ();
98 intval
= *(int*)counter
->addr
;
99 fprintf (outfile
, ENTRY_FMT
"%d\n", counter
->name
, intval
);
101 case MONO_COUNTER_UINT
:
102 if (counter
->type
& MONO_COUNTER_CALLBACK
)
103 uintval
= ((UIntFunc
)counter
->addr
) ();
105 uintval
= *(guint
*)counter
->addr
;
106 fprintf (outfile
, ENTRY_FMT
"%u\n", counter
->name
, uintval
);
108 case MONO_COUNTER_LONG
:
109 if (counter
->type
& MONO_COUNTER_CALLBACK
)
110 int64val
= ((LongFunc
)counter
->addr
) ();
112 int64val
= *(gint64
*)counter
->addr
;
113 fprintf (outfile
, ENTRY_FMT
"%lld\n", counter
->name
, (long long)int64val
);
115 case MONO_COUNTER_ULONG
:
116 if (counter
->type
& MONO_COUNTER_CALLBACK
)
117 uint64val
= ((ULongFunc
)counter
->addr
) ();
119 uint64val
= *(guint64
*)counter
->addr
;
120 fprintf (outfile
, ENTRY_FMT
"%llu\n", counter
->name
, (unsigned long long)uint64val
);
122 case MONO_COUNTER_WORD
:
123 if (counter
->type
& MONO_COUNTER_CALLBACK
)
124 wordval
= ((PtrFunc
)counter
->addr
) ();
126 wordval
= *(gssize
*)counter
->addr
;
127 #if SIZEOF_VOID_P == 8
128 fprintf (outfile
, ENTRY_FMT
"%lld\n", counter
->name
, (gint64
)wordval
);
130 fprintf (outfile
, ENTRY_FMT
"%d\n", counter
->name
, (gint
)wordval
);
133 case MONO_COUNTER_DOUBLE
:
134 if (counter
->type
& MONO_COUNTER_CALLBACK
)
135 dval
= ((DoubleFunc
)counter
->addr
) ();
137 dval
= *(double*)counter
->addr
;
138 fprintf (outfile
, ENTRY_FMT
"%.4f\n", counter
->name
, dval
);
140 case MONO_COUNTER_STRING
:
141 if (counter
->type
& MONO_COUNTER_CALLBACK
)
142 str
= ((StrFunc
)counter
->addr
) ();
144 str
= *(char**)counter
->addr
;
145 fprintf (outfile
, ENTRY_FMT
"%s\n", counter
->name
, str
);
147 case MONO_COUNTER_TIME_INTERVAL
:
148 if (counter
->type
& MONO_COUNTER_CALLBACK
)
149 int64val
= ((LongFunc
)counter
->addr
) ();
151 int64val
= *(gint64
*)counter
->addr
;
152 fprintf (outfile
, ENTRY_FMT
"%.2f ms\n", counter
->name
, (double)int64val
/ 1000.0);
158 section_names
[][10] = {
167 mono_counters_dump_section (int section
, FILE *outfile
)
169 MonoCounter
*counter
= counters
;
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.
185 mono_counters_dump (int section_mask
, FILE *outfile
)
188 section_mask
&= valid_mask
;
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
);
202 * mono_counters_cleanup:
204 * Perform any needed cleanup at process exit.
207 mono_counters_cleanup (void)
209 MonoCounter
*counter
= counters
;
211 MonoCounter
*tmp
= counters
;
212 counter
= counter
->next
;
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.
230 mono_runtime_resource_check_limit (int resource_type
, uintptr_t value
)
234 /* check the hard limit first */
235 if (value
> resource_limits
[resource_type
* 2 + 1]) {
236 limit_reached (resource_type
, value
, 0);
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)
262 if (soft_limit
> hard_limit
)
264 resource_limits
[resource_type
* 2] = soft_limit
;
265 resource_limits
[resource_type
* 2 + 1] = hard_limit
;
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.
278 mono_runtime_resource_set_callback (MonoResourceCallback callback
)
280 limit_reached
= callback
;