4 * Performance counters support.
6 * Author: Paolo Molaro (lupus@ximian.com)
8 * Copyright 2008-2009 Novell, Inc (http://www.novell.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #if defined (__OpenBSD__)
21 #include <sys/param.h>
23 #ifdef HAVE_SYS_TYPES_H
24 #include <sys/types.h>
26 #ifdef HAVE_SYS_TIME_H
29 #if defined (__APPLE__)
30 #include <mach/message.h>
31 #include <mach/mach_host.h>
32 #include <mach/host_info.h>
34 #if defined (__NetBSD__) || defined (__APPLE__)
35 #include <sys/sysctl.h>
37 #include "metadata/mono-perfcounters.h"
38 #include "metadata/appdomain.h"
39 #include "metadata/object-internals.h"
41 #include "metadata/class-internals.h"
42 #include "utils/mono-time.h"
43 #include "utils/mono-mmap.h"
44 #include "utils/mono-proclib.h"
45 #include "utils/mono-networkinterfaces.h"
46 #include "utils/mono-error-internals.h"
47 #include "utils/atomic.h"
48 #include <mono/io-layer/io-layer.h>
50 /* map of CounterSample.cs */
51 struct _MonoCounterSample {
54 gint64 counterFrequency;
55 gint64 systemFrequency;
57 gint64 timeStamp100nSec;
58 gint64 counterTimeStamp;
62 #ifndef DISABLE_PERFCOUNTERS
63 /* map of PerformanceCounterType.cs */
65 NumberOfItemsHEX32=0x00000000,
66 NumberOfItemsHEX64=0x00000100,
67 NumberOfItems32=0x00010000,
68 NumberOfItems64=0x00010100,
69 CounterDelta32=0x00400400,
70 CounterDelta64=0x00400500,
71 SampleCounter=0x00410400,
72 CountPerTimeInterval32=0x00450400,
73 CountPerTimeInterval64=0x00450500,
74 RateOfCountsPerSecond32=0x10410400,
75 RateOfCountsPerSecond64=0x10410500,
76 RawFraction=0x20020400,
77 CounterTimer=0x20410500,
78 Timer100Ns=0x20510500,
79 SampleFraction=0x20C20400,
80 CounterTimerInverse=0x21410500,
81 Timer100NsInverse=0x21510500,
82 CounterMultiTimer=0x22410500,
83 CounterMultiTimer100Ns=0x22510500,
84 CounterMultiTimerInverse=0x23410500,
85 CounterMultiTimer100NsInverse=0x23510500,
86 AverageTimer32=0x30020400,
87 ElapsedTime=0x30240500,
88 AverageCount64=0x40020500,
89 SampleBase=0x40030401,
90 AverageBase=0x40030402,
92 CounterMultiBase=0x42030500
95 /* maps a small integer type to the counter types above */
97 simple_type_to_type [] = {
98 NumberOfItemsHEX32, NumberOfItemsHEX64,
99 NumberOfItems32, NumberOfItems64,
100 CounterDelta32, CounterDelta64,
101 SampleCounter, CountPerTimeInterval32,
102 CountPerTimeInterval64, RateOfCountsPerSecond32,
103 RateOfCountsPerSecond64, RawFraction,
104 CounterTimer, Timer100Ns,
105 SampleFraction, CounterTimerInverse,
106 Timer100NsInverse, CounterMultiTimer,
107 CounterMultiTimer100Ns, CounterMultiTimerInverse,
108 CounterMultiTimer100NsInverse, AverageTimer32,
109 ElapsedTime, AverageCount64,
110 SampleBase, AverageBase,
111 RawBase, CounterMultiBase
125 NetworkInterfaceInstance,
129 #define PERFCTR_CAT(id,name,help,type,inst,first_counter) CATEGORY_ ## id,
130 #define PERFCTR_COUNTER(id,name,help,type,field)
132 #include "mono-perfcounters-def.h"
137 #undef PERFCTR_COUNTER
138 #define PERFCTR_CAT(id,name,help,type,inst,first_counter) CATEGORY_START_ ## id = -1,
139 #define PERFCTR_COUNTER(id,name,help,type,field) COUNTER_ ## id,
140 /* each counter is assigned an id starting from 0 inside the category */
142 #include "mono-perfcounters-def.h"
147 #undef PERFCTR_COUNTER
148 #define PERFCTR_CAT(id,name,help,type,inst,first_counter)
149 #define PERFCTR_COUNTER(id,name,help,type,field) CCOUNTER_ ## id,
150 /* this is used just to count the number of counters */
152 #include "mono-perfcounters-def.h"
156 static mono_mutex_t perfctr_mutex;
157 #define perfctr_lock() mono_os_mutex_lock (&perfctr_mutex)
158 #define perfctr_unlock() mono_os_mutex_unlock (&perfctr_mutex)
163 unsigned short counters_start;
164 unsigned short counters_size;
165 unsigned short data_start;
166 MonoPerfCounters counters;
171 binary format of custom counters in shared memory, starting from MonoSharedArea* + data_start;
173 struct stanza_header {
174 byte stanza_type; // FTYPE_*
176 ushort stanza_length; // includeas header
181 // perfcat and perfinstance are 4-bytes aligned
185 ushort length; // includes the counters
187 ushort counters_data_size;
189 char name[]; // null terminated
190 char help[]; // null terminated
191 // perfcounters follow
194 char name[]; // null terminated
195 char help[]; // null terminated
200 struct perfinstance {
202 byte data_offset; // offset of counters from beginning of struct
204 uint category_offset; // offset of category in the shared area
205 char name[]; // null terminated
206 // data follows: this is always 8-byte aligned
212 FTYPE_CATEGORY = 'C',
214 FTYPE_PREDEF_INSTANCE = 'P', // an instance of a predef counter
215 FTYPE_INSTANCE = 'I',
228 unsigned short num_counters;
229 unsigned short counters_data_size;
231 /* variable length data follows */
235 // SharedCounter counters_info [num_counters]
240 unsigned int category_offset;
241 /* variable length data follows */
242 char instance_name [1];
249 /* variable length data follows */
260 unsigned int instance_type : 6;
268 unsigned short offset; // offset inside MonoPerfCounters
273 #undef PERFCTR_COUNTER
274 #define PERFCTR_CAT(id,name,help,type,inst,first_counter) {name, help, CATEGORY_ ## id, type, inst ## Instance, CCOUNTER_ ## first_counter},
275 #define PERFCTR_COUNTER(id,name,help,type,field)
276 static const CategoryDesc
277 predef_categories [] = {
278 #include "mono-perfcounters-def.h"
279 {NULL, NULL, NUM_CATEGORIES, -1, 0, NUM_COUNTERS}
283 #undef PERFCTR_COUNTER
284 #define PERFCTR_CAT(id,name,help,type,inst,first_counter)
285 #define PERFCTR_COUNTER(id,name,help,type,field) {name, help, COUNTER_ ## id, G_STRUCT_OFFSET (MonoPerfCounters, field), type},
286 static const CounterDesc
287 predef_counters [] = {
288 #include "mono-perfcounters-def.h"
289 {NULL, NULL, -1, 0, 0}
293 * We have several different classes of counters:
295 * *) runtime counters
297 * *) user-defined counters
298 * *) windows counters (the implementation on windows will use this)
300 * To easily handle the differences we create a vtable for each class that contains the
301 * function pointers with the actual implementation to access the counters.
303 typedef struct _ImplVtable ImplVtable;
305 typedef MonoBoolean (*SampleFunc) (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample* sample);
306 typedef gint64 (*UpdateFunc) (ImplVtable *vtable, MonoBoolean do_incr, gint64 value);
307 typedef void (*CleanupFunc) (ImplVtable *vtable);
323 MonoPerfCounters *counters;
329 SharedInstance *instance_desc;
330 SharedCounter *counter_desc;
334 create_vtable (void *arg, SampleFunc sample, UpdateFunc update)
336 ImplVtable *vtable = g_new0 (ImplVtable, 1);
338 vtable->sample = sample;
339 vtable->update = update;
343 MonoPerfCounters *mono_perfcounters = NULL;
344 static MonoSharedArea *shared_area = NULL;
351 /* maps a pid to a ExternalSArea pointer */
352 static GHashTable *pid_to_shared_area = NULL;
354 static MonoSharedArea *
355 load_sarea_for_pid (int pid)
358 MonoSharedArea *area = NULL;
361 if (pid_to_shared_area == NULL)
362 pid_to_shared_area = g_hash_table_new (NULL, NULL);
363 data = (ExternalSArea *)g_hash_table_lookup (pid_to_shared_area, GINT_TO_POINTER (pid));
365 area = (MonoSharedArea *)mono_shared_area_for_pid (GINT_TO_POINTER (pid));
367 data = g_new (ExternalSArea, 1);
370 g_hash_table_insert (pid_to_shared_area, GINT_TO_POINTER (pid), data);
373 area = (MonoSharedArea *)data->sarea;
381 unref_pid_unlocked (int pid)
384 data = (ExternalSArea *)g_hash_table_lookup (pid_to_shared_area, GINT_TO_POINTER (pid));
387 if (!data->refcount) {
388 g_hash_table_remove (pid_to_shared_area, GINT_TO_POINTER (pid));
389 mono_shared_area_unload (data->sarea);
396 predef_cleanup (ImplVtable *vtable)
398 PredefVtable *vt = (PredefVtable*)vtable;
399 /* ExternalSArea *data; */
402 if (!pid_to_shared_area) {
406 unref_pid_unlocked (vt->pid);
411 mono_determine_physical_ram_size (void)
413 #if defined (TARGET_WIN32)
414 MEMORYSTATUSEX memstat;
416 memstat.dwLength = sizeof (memstat);
417 GlobalMemoryStatusEx (&memstat);
418 return (guint64)memstat.ullTotalPhys;
419 #elif defined (__NetBSD__) || defined (__APPLE__)
433 size_t size_sys = sizeof (value);
435 sysctl (mib, 2, &value, &size_sys, NULL, 0);
439 return (guint64)value;
440 #elif defined (HAVE_SYSCONF)
441 guint64 page_size = 0, num_pages = 0;
443 /* sysconf works on most *NIX operating systems, if your system doesn't have it or if it
444 * reports invalid values, please add your OS specific code below. */
446 page_size = (guint64)sysconf (_SC_PAGESIZE);
449 #ifdef _SC_PHYS_PAGES
450 num_pages = (guint64)sysconf (_SC_PHYS_PAGES);
453 if (!page_size || !num_pages) {
454 g_warning ("Your operating system's sysconf (3) function doesn't correctly report physical memory size!");
458 return page_size * num_pages;
465 mono_determine_physical_ram_available_size (void)
467 #if defined (TARGET_WIN32)
468 MEMORYSTATUSEX memstat;
470 memstat.dwLength = sizeof (memstat);
471 GlobalMemoryStatusEx (&memstat);
472 return (guint64)memstat.ullAvailPhys;
474 #elif defined (__NetBSD__)
475 struct vmtotal vm_total;
483 #if defined (VM_METER)
489 len = sizeof (vm_total);
490 sysctl (mib, 2, &vm_total, &len, NULL, 0);
496 len = sizeof (page_size);
497 sysctl (mib, 2, &page_size, &len, NULL, 0
499 return ((guint64) value.t_free * page_size) / 1024;
500 #elif defined (__APPLE__)
501 mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
502 mach_port_t host = mach_host_self();
504 vm_statistics_data_t vmstat;
507 ret = host_statistics(host, HOST_VM_INFO, (host_info_t)&vmstat, &count);
508 } while (ret == KERN_ABORTED);
510 if (ret != KERN_SUCCESS) {
511 g_warning ("Mono was unable to retrieve memory usage!");
515 host_page_size(host, &page_size);
516 return (guint64) vmstat.free_count * page_size;
518 #elif defined (HAVE_SYSCONF)
519 guint64 page_size = 0, num_pages = 0;
521 /* sysconf works on most *NIX operating systems, if your system doesn't have it or if it
522 * reports invalid values, please add your OS specific code below. */
524 page_size = (guint64)sysconf (_SC_PAGESIZE);
527 #ifdef _SC_AVPHYS_PAGES
528 num_pages = (guint64)sysconf (_SC_AVPHYS_PAGES);
531 if (!page_size || !num_pages) {
532 g_warning ("Your operating system's sysconf (3) function doesn't correctly report physical memory size!");
536 return page_size * num_pages;
543 mono_perfcounters_init (void)
545 int d_offset = G_STRUCT_OFFSET (MonoSharedArea, data);
549 mono_os_mutex_init_recursive (&perfctr_mutex);
551 shared_area = (MonoSharedArea *)mono_shared_area ();
552 shared_area->counters_start = G_STRUCT_OFFSET (MonoSharedArea, counters);
553 shared_area->counters_size = sizeof (MonoPerfCounters);
554 shared_area->data_start = d_offset;
555 shared_area->size = 4096;
556 mono_perfcounters = &shared_area->counters;
560 perfctr_type_compress (int type)
563 for (i = 0; i < G_N_ELEMENTS (simple_type_to_type); ++i) {
564 if (simple_type_to_type [i] == type)
567 /* NumberOfItems32 */
572 shared_data_reserve_room (int size, int ftype)
574 SharedHeader* header;
575 unsigned char *p = (unsigned char *)shared_area + shared_area->data_start;
576 unsigned char *end = (unsigned char *)shared_area + shared_area->size;
581 unsigned short *next;
582 if (*p == FTYPE_END) {
583 if (size < (end - p))
589 next = (unsigned short*)(p + 2);
590 if (*p == FTYPE_DELETED) {
591 /* we reuse only if it's the same size */
601 header = (SharedHeader*)p;
602 header->ftype = ftype;
603 header->extra = 0; /* data_offset could overflow here, so we leave this field unused */
609 typedef gboolean (*SharedFunc) (SharedHeader *header, void *data);
612 foreach_shared_item_in_area (unsigned char *p, unsigned char *end, SharedFunc func, void *data)
615 unsigned short *next;
618 next = (unsigned short*)(p + 2);
619 if (!func ((SharedHeader*)p, data))
628 foreach_shared_item (SharedFunc func, void *data)
630 unsigned char *p = (unsigned char *)shared_area + shared_area->data_start;
631 unsigned char *end = (unsigned char *)shared_area + shared_area->size;
633 foreach_shared_item_in_area (p, end, func, data);
637 mono_string_compare_ascii (MonoString *str, const char *ascii_str)
639 /* FIXME: make this case insensitive */
640 guint16 *strc = mono_string_chars (str);
641 while (*strc == *ascii_str++) {
646 return *strc - *(const unsigned char *)(ascii_str - 1);
655 category_search (SharedHeader *header, void *data)
657 CatSearch *search = (CatSearch *)data;
658 if (header->ftype == FTYPE_CATEGORY) {
659 SharedCategory *cat = (SharedCategory*)header;
660 if (mono_string_compare_ascii (search->name, cat->name) == 0) {
668 static SharedCategory*
669 find_custom_category (MonoString *name)
674 foreach_shared_item (category_search, &search);
679 category_collect (SharedHeader *header, void *data)
681 GSList **list = (GSList **)data;
682 if (header->ftype == FTYPE_CATEGORY) {
683 *list = g_slist_prepend (*list, header);
689 get_custom_categories (void) {
691 foreach_shared_item (category_collect, &list);
696 custom_category_counters (SharedCategory* cat)
698 char *p = cat->name + strlen (cat->name) + 1;
699 p += strlen (p) + 1; /* skip category help */
703 static SharedCounter*
704 find_custom_counter (SharedCategory* cat, MonoString *name)
707 char *p = custom_category_counters (cat);
708 for (i = 0; i < cat->num_counters; ++i) {
709 SharedCounter *counter = (SharedCounter*)p;
710 if (mono_string_compare_ascii (name, counter->name) == 0)
712 p += 2; /* skip counter type */
713 p += strlen (p) + 1; /* skip counter name */
714 p += strlen (p) + 1; /* skip counter help */
720 unsigned int cat_offset;
723 SharedInstance* result;
728 instance_search (SharedHeader *header, void *data)
730 InstanceSearch *search = (InstanceSearch *)data;
731 if (header->ftype == FTYPE_INSTANCE) {
732 SharedInstance *ins = (SharedInstance*)header;
733 if (search->cat_offset == ins->category_offset) {
735 if (strcmp (search->name, ins->instance_name) == 0) {
736 search->result = ins;
740 search->list = g_slist_prepend (search->list, ins);
747 static SharedInstance*
748 find_custom_instance (SharedCategory* cat, char *name)
750 InstanceSearch search;
751 search.cat_offset = (char*)cat - (char*)shared_area;
755 search.result = NULL;
756 foreach_shared_item (instance_search, &search);
757 return search.result;
761 get_custom_instances_list (SharedCategory* cat)
763 InstanceSearch search;
764 search.cat_offset = (char*)cat - (char*)shared_area;
768 search.result = NULL;
769 foreach_shared_item (instance_search, &search);
774 custom_category_help (SharedCategory* cat)
776 return cat->name + strlen (cat->name) + 1;
779 static const CounterDesc*
780 get_counter_in_category (const CategoryDesc *desc, MonoString *counter)
782 const CounterDesc *cdesc = &predef_counters [desc->first_counter];
783 const CounterDesc *end = &predef_counters [desc [1].first_counter];
784 for (; cdesc < end; ++cdesc) {
785 if (mono_string_compare_ascii (counter, cdesc->name) == 0)
791 /* fill the info in sample (except the raw value) */
793 fill_sample (MonoCounterSample *sample)
795 sample->timeStamp = mono_100ns_ticks ();
796 sample->timeStamp100nSec = sample->timeStamp;
797 sample->counterTimeStamp = sample->timeStamp;
798 sample->counterFrequency = 10000000;
799 sample->systemFrequency = 10000000;
800 // the real basevalue needs to be get from a different counter...
801 sample->baseValue = 0;
805 id_from_string (MonoString *instance, gboolean is_process)
809 if (mono_string_length (instance)) {
810 char *id_str = mono_string_to_utf8_checked (instance, &error);
811 mono_error_raise_exception (&error); /* FIXME don't raise here */
813 id = strtol (id_str, &end, 0);
814 if (end == id_str && !is_process)
822 get_cpu_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
824 MonoProcessError error;
825 int id = GPOINTER_TO_INT (vtable->arg);
829 fill_sample (sample);
830 sample->baseValue = 1;
832 sample->counterType = predef_counters [predef_categories [CATEGORY_CPU].first_counter + id].type;
834 case COUNTER_CPU_USER_TIME:
835 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_USER_TIME, &error);
837 case COUNTER_CPU_PRIV_TIME:
838 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_PRIV_TIME, &error);
840 case COUNTER_CPU_INTR_TIME:
841 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_INTR_TIME, &error);
843 case COUNTER_CPU_DCP_TIME:
844 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_DCP_TIME, &error);
846 case COUNTER_CPU_PROC_TIME:
847 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_IDLE_TIME, &error);
854 cpu_get_impl (MonoString* counter, MonoString* instance, int *type, MonoBoolean *custom)
856 int id = id_from_string (instance, FALSE) << 5;
857 const CounterDesc *cdesc;
859 /* increase the shift above and the mask also in the implementation functions */
860 //g_assert (32 > desc [1].first_counter - desc->first_counter);
861 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_CPU], counter))) {
863 return create_vtable (GINT_TO_POINTER (id | cdesc->id), get_cpu_counter, NULL);
869 get_network_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
871 MonoNetworkError error = MONO_NETWORK_ERROR_OTHER;
872 NetworkVtableArg *narg = (NetworkVtableArg*) vtable->arg;
874 fill_sample (sample);
877 sample->counterType = predef_counters [predef_categories [CATEGORY_NETWORK].first_counter + narg->id].type;
879 case COUNTER_NETWORK_BYTESRECSEC:
880 sample->rawValue = mono_network_get_data (narg->name, MONO_NETWORK_BYTESREC, &error);
882 case COUNTER_NETWORK_BYTESSENTSEC:
883 sample->rawValue = mono_network_get_data (narg->name, MONO_NETWORK_BYTESSENT, &error);
885 case COUNTER_NETWORK_BYTESTOTALSEC:
886 sample->rawValue = mono_network_get_data (narg->name, MONO_NETWORK_BYTESTOTAL, &error);
890 if (error == MONO_NETWORK_ERROR_NONE)
897 network_cleanup (ImplVtable *vtable)
899 NetworkVtableArg *narg;
904 narg = (NetworkVtableArg *)vtable->arg;
915 network_get_impl (MonoString* counter, MonoString* instance, int *type, MonoBoolean *custom)
918 const CounterDesc *cdesc;
919 NetworkVtableArg *narg;
924 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_NETWORK], counter))) {
925 instance_name = mono_string_to_utf8_checked (instance, &error);
926 mono_error_raise_exception (&error); /* FIXME don't raise here */
927 narg = g_new0 (NetworkVtableArg, 1);
928 narg->id = cdesc->id;
929 narg->name = instance_name;
931 vtable = create_vtable (narg, get_network_counter, NULL);
932 vtable->cleanup = network_cleanup;
939 get_process_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
941 int id = GPOINTER_TO_INT (vtable->arg);
947 fill_sample (sample);
948 sample->baseValue = 1;
950 sample->counterType = predef_counters [predef_categories [CATEGORY_PROC].first_counter + id].type;
952 case COUNTER_PROC_USER_TIME:
953 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_USER_TIME);
955 case COUNTER_PROC_PRIV_TIME:
956 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_SYSTEM_TIME);
958 case COUNTER_PROC_PROC_TIME:
959 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_TOTAL_TIME);
961 case COUNTER_PROC_THREADS:
962 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_NUM_THREADS);
964 case COUNTER_PROC_VBYTES:
965 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_VIRTUAL_BYTES);
967 case COUNTER_PROC_WSET:
968 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_WORKING_SET);
970 case COUNTER_PROC_PBYTES:
971 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_PRIVATE_BYTES);
978 process_get_impl (MonoString* counter, MonoString* instance, int *type, MonoBoolean *custom)
980 int id = id_from_string (instance, TRUE) << 5;
981 const CounterDesc *cdesc;
983 /* increase the shift above and the mask also in the implementation functions */
984 //g_assert (32 > desc [1].first_counter - desc->first_counter);
985 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_PROC], counter))) {
987 return create_vtable (GINT_TO_POINTER (id | cdesc->id), get_process_counter, NULL);
993 mono_mem_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
995 int id = GPOINTER_TO_INT (vtable->arg);
997 fill_sample (sample);
998 sample->baseValue = 1;
1000 sample->counterType = predef_counters [predef_categories [CATEGORY_MONO_MEM].first_counter + id].type;
1002 case COUNTER_MEM_NUM_OBJECTS:
1003 sample->rawValue = 0;
1005 case COUNTER_MEM_PHYS_TOTAL:
1006 sample->rawValue = mono_determine_physical_ram_size ();;
1008 case COUNTER_MEM_PHYS_AVAILABLE:
1009 sample->rawValue = mono_determine_physical_ram_available_size ();;
1016 mono_mem_get_impl (MonoString* counter, MonoString* instance, int *type, MonoBoolean *custom)
1018 const CounterDesc *cdesc;
1020 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_MONO_MEM], counter))) {
1021 *type = cdesc->type;
1022 return create_vtable (GINT_TO_POINTER ((gint) cdesc->id), mono_mem_counter, NULL);
1028 predef_readonly_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
1030 PredefVtable *vt = (PredefVtable *)vtable;
1031 const CounterDesc *desc;
1032 int cat_id = GPOINTER_TO_INT (vtable->arg);
1033 int id = cat_id >> 16;
1036 fill_sample (sample);
1037 sample->baseValue = 1;
1039 desc = &predef_counters [predef_categories [cat_id].first_counter + id];
1040 sample->counterType = desc->type;
1041 /* FIXME: check that the offset fits inside imported counters */
1042 /*g_print ("loading %s at %d\n", desc->name, desc->offset);*/
1043 sample->rawValue = *(guint32*)((char*)vt->counters + desc->offset);
1048 predef_vtable (void *arg, MonoString *instance)
1051 MonoSharedArea *area;
1052 PredefVtable *vtable;
1053 char *pids = mono_string_to_utf8_checked (instance, &error);
1054 mono_error_raise_exception (&error); /* FIXME don't raise here */
1059 area = load_sarea_for_pid (pid);
1063 vtable = g_new (PredefVtable, 1);
1064 vtable->vtable.arg = arg;
1065 vtable->vtable.sample = predef_readonly_counter;
1066 vtable->vtable.cleanup = predef_cleanup;
1067 vtable->counters = (MonoPerfCounters*)((char*)area + area->counters_start);
1070 return (ImplVtable*)vtable;
1073 /* consider storing the pointer directly in vtable->arg, so the runtime overhead is lower:
1074 * this needs some way to set sample->counterType as well, though.
1077 predef_writable_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
1079 int cat_id = GPOINTER_TO_INT (vtable->arg);
1080 int id = cat_id >> 16;
1083 fill_sample (sample);
1084 sample->baseValue = 1;
1086 sample->counterType = predef_counters [predef_categories [cat_id].first_counter + id].type;
1090 case COUNTER_EXC_THROWN:
1091 sample->rawValue = mono_perfcounters->exceptions_thrown;
1095 case CATEGORY_ASPNET:
1097 case COUNTER_ASPNET_REQ_Q:
1098 sample->rawValue = mono_perfcounters->aspnet_requests_queued;
1100 case COUNTER_ASPNET_REQ_TOTAL:
1101 sample->rawValue = mono_perfcounters->aspnet_requests;
1105 case CATEGORY_THREADPOOL:
1107 case COUNTER_THREADPOOL_WORKITEMS:
1108 sample->rawValue = mono_perfcounters->threadpool_workitems;
1110 case COUNTER_THREADPOOL_IOWORKITEMS:
1111 sample->rawValue = mono_perfcounters->threadpool_ioworkitems;
1113 case COUNTER_THREADPOOL_THREADS:
1114 sample->rawValue = mono_perfcounters->threadpool_threads;
1116 case COUNTER_THREADPOOL_IOTHREADS:
1117 sample->rawValue = mono_perfcounters->threadpool_iothreads;
1123 case COUNTER_JIT_BYTES:
1124 sample->rawValue = mono_perfcounters->jit_bytes;
1126 case COUNTER_JIT_METHODS:
1127 sample->rawValue = mono_perfcounters->jit_methods;
1129 case COUNTER_JIT_TIME:
1130 sample->rawValue = mono_perfcounters->jit_time;
1132 case COUNTER_JIT_BYTES_PSEC:
1133 sample->rawValue = mono_perfcounters->jit_bytes;
1135 case COUNTER_JIT_FAILURES:
1136 sample->rawValue = mono_perfcounters->jit_failures;
1145 predef_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
1147 guint32 *volatile ptr = NULL;
1148 gint64 *volatile ptr64 = NULL;
1149 int cat_id = GPOINTER_TO_INT (vtable->arg);
1150 int id = cat_id >> 16;
1153 case CATEGORY_ASPNET:
1155 case COUNTER_ASPNET_REQ_Q: ptr = &mono_perfcounters->aspnet_requests_queued; break;
1156 case COUNTER_ASPNET_REQ_TOTAL: ptr = &mono_perfcounters->aspnet_requests; break;
1159 case CATEGORY_THREADPOOL:
1161 case COUNTER_THREADPOOL_WORKITEMS: ptr64 = (gint64 *) &mono_perfcounters->threadpool_workitems; break;
1162 case COUNTER_THREADPOOL_IOWORKITEMS: ptr64 = (gint64 *) &mono_perfcounters->threadpool_ioworkitems; break;
1163 case COUNTER_THREADPOOL_THREADS: ptr = &mono_perfcounters->threadpool_threads; break;
1164 case COUNTER_THREADPOOL_IOTHREADS: ptr = &mono_perfcounters->threadpool_iothreads; break;
1171 return InterlockedIncrement ((gint32 *) ptr); /* FIXME: sign */
1173 return InterlockedDecrement ((gint32 *) ptr); /* FIXME: sign */
1178 /* this can be non-atomic */
1183 /* FIXME: we need to do this atomically */
1184 /* No InterlockedIncrement64() yet */
1187 return InterlockedIncrement64 (ptr);
1189 return InterlockedDecrement64 (ptr);
1195 /* this can be non-atomic */
1203 predef_writable_get_impl (int cat, MonoString* counter, MonoString* instance, int *type, MonoBoolean *custom)
1205 const CounterDesc *cdesc;
1207 if ((cdesc = get_counter_in_category (&predef_categories [cat], counter))) {
1208 *type = cdesc->type;
1209 if (instance == NULL || mono_string_compare_ascii (instance, "") == 0)
1210 return create_vtable (GINT_TO_POINTER ((cdesc->id << 16) | cat), predef_writable_counter, predef_writable_update);
1212 return predef_vtable (GINT_TO_POINTER ((cdesc->id << 16) | cat), instance);
1218 custom_writable_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
1220 CustomVTable *counter_data = (CustomVTable *)vtable;
1222 fill_sample (sample);
1223 sample->baseValue = 1;
1225 sample->counterType = simple_type_to_type [counter_data->counter_desc->type];
1227 sample->rawValue = 0;
1229 sample->rawValue = *(guint64*)vtable->arg;
1234 custom_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
1236 /* FIXME: check writability */
1237 guint64 *ptr = (guint64 *)vtable->arg;
1240 /* FIXME: we need to do this atomically */
1244 /* this can be non-atomic */
1251 static SharedInstance*
1252 custom_get_instance (SharedCategory *cat, SharedCounter *scounter, char* name)
1254 SharedInstance* inst;
1257 inst = find_custom_instance (cat, name);
1260 size = sizeof (SharedInstance) + strlen (name);
1263 size += (sizeof (guint64) * cat->num_counters);
1265 inst = (SharedInstance*) shared_data_reserve_room (size, FTYPE_INSTANCE);
1271 inst->category_offset = (char*)cat - (char*)shared_area;
1272 cat->num_instances++;
1273 /* now copy the variable data */
1274 p = inst->instance_name;
1276 p += strlen (name) + 1;
1283 custom_vtable (SharedCounter *scounter, SharedInstance* inst, char *data)
1285 CustomVTable* vtable;
1286 vtable = g_new0 (CustomVTable, 1);
1287 vtable->vtable.arg = data;
1288 vtable->vtable.sample = custom_writable_counter;
1289 vtable->vtable.update = custom_writable_update;
1290 vtable->instance_desc = inst;
1291 vtable->counter_desc = scounter;
1293 return (ImplVtable*)vtable;
1297 custom_get_value_address (SharedCounter *scounter, SharedInstance* sinst)
1299 int offset = sizeof (SharedInstance) + strlen (sinst->instance_name);
1302 offset += scounter->seq_num * sizeof (guint64);
1303 return (char*)sinst + offset;
1307 custom_get_impl (SharedCategory *cat, MonoString* counter, MonoString* instance, int *type)
1310 SharedCounter *scounter;
1311 SharedInstance* inst;
1314 scounter = find_custom_counter (cat, counter);
1317 *type = simple_type_to_type [scounter->type];
1318 name = mono_string_to_utf8_checked (counter, &error);
1319 mono_error_raise_exception (&error); /* FIXME don't raise here */
1320 inst = custom_get_instance (cat, scounter, name);
1324 return custom_vtable (scounter, inst, (char *)custom_get_value_address (scounter, inst));
1327 static const CategoryDesc*
1328 find_category (MonoString *category)
1331 for (i = 0; i < NUM_CATEGORIES; ++i) {
1332 if (mono_string_compare_ascii (category, predef_categories [i].name) == 0)
1333 return &predef_categories [i];
1339 mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString* instance,
1340 MonoString* machine, int *type, MonoBoolean *custom)
1342 const CategoryDesc *cdesc;
1343 /* no support for counters on other machines */
1344 if (mono_string_compare_ascii (machine, "."))
1346 cdesc = find_category (category);
1348 SharedCategory *scat = find_custom_category (category);
1352 return custom_get_impl (scat, counter, instance, type);
1354 switch (cdesc->id) {
1356 return cpu_get_impl (counter, instance, type, custom);
1358 return process_get_impl (counter, instance, type, custom);
1359 case CATEGORY_MONO_MEM:
1360 return mono_mem_get_impl (counter, instance, type, custom);
1361 case CATEGORY_NETWORK:
1362 return network_get_impl (counter, instance, type, custom);
1366 case CATEGORY_REMOTING:
1367 case CATEGORY_LOADING:
1368 case CATEGORY_THREAD:
1369 case CATEGORY_INTEROP:
1370 case CATEGORY_SECURITY:
1371 case CATEGORY_ASPNET:
1372 case CATEGORY_THREADPOOL:
1373 return predef_writable_get_impl (cdesc->id, counter, instance, type, custom);
1379 mono_perfcounter_get_sample (void *impl, MonoBoolean only_value, MonoCounterSample *sample)
1381 ImplVtable *vtable = (ImplVtable *)impl;
1382 if (vtable && vtable->sample)
1383 return vtable->sample (vtable, only_value, sample);
1388 mono_perfcounter_update_value (void *impl, MonoBoolean do_incr, gint64 value)
1390 ImplVtable *vtable = (ImplVtable *)impl;
1391 if (vtable && vtable->update)
1392 return vtable->update (vtable, do_incr, value);
1397 mono_perfcounter_free_data (void *impl)
1399 ImplVtable *vtable = (ImplVtable *)impl;
1400 if (vtable && vtable->cleanup)
1401 vtable->cleanup (vtable);
1405 /* Category icalls */
1407 mono_perfcounter_category_del (MonoString *name)
1409 const CategoryDesc *cdesc;
1410 SharedCategory *cat;
1411 cdesc = find_category (name);
1412 /* can't delete a predefined category */
1416 cat = find_custom_category (name);
1417 /* FIXME: check the semantics, if deleting a category means also deleting the instances */
1418 if (!cat || cat->num_instances) {
1422 cat->header.ftype = FTYPE_DELETED;
1428 mono_perfcounter_category_help (MonoString *category, MonoString *machine)
1430 const CategoryDesc *cdesc;
1431 /* no support for counters on other machines */
1432 if (mono_string_compare_ascii (machine, "."))
1434 cdesc = find_category (category);
1436 SharedCategory *scat = find_custom_category (category);
1439 return mono_string_new (mono_domain_get (), custom_category_help (scat));
1441 return mono_string_new (mono_domain_get (), cdesc->help);
1445 * Check if the category named @category exists on @machine. If @counter is not NULL, return
1446 * TRUE only if a counter with that name exists in the category.
1449 mono_perfcounter_category_exists (MonoString *counter, MonoString *category, MonoString *machine)
1451 const CategoryDesc *cdesc;
1452 /* no support for counters on other machines */
1453 if (mono_string_compare_ascii (machine, "."))
1455 cdesc = find_category (category);
1457 SharedCategory *scat = find_custom_category (category);
1460 /* counter is allowed to be null */
1463 /* search through the custom category */
1464 return find_custom_counter (scat, counter) != NULL;
1466 /* counter is allowed to be null */
1469 if (get_counter_in_category (cdesc, counter))
1474 /* C map of the type with the same name */
1480 } CounterCreationData;
1483 * Since we'll keep a copy of the category per-process, we should also make sure
1484 * categories with the same name are compatible.
1487 mono_perfcounter_create (MonoString *category, MonoString *help, int type, MonoArray *items)
1492 int num_counters = mono_array_length (items);
1493 int counters_data_size;
1496 char **counter_info = NULL;
1498 SharedCategory *cat;
1500 /* FIXME: ensure there isn't a category created already */
1501 name = mono_string_to_utf8_checked (category, &error);
1502 if (!mono_error_ok (&error))
1504 chelp = mono_string_to_utf8_checked (help, &error);
1505 if (!mono_error_ok (&error))
1507 counter_info = g_new0 (char*, num_counters * 2);
1508 /* calculate the size we need structure size + name/help + 2 0 string terminators */
1509 size = G_STRUCT_OFFSET (SharedCategory, name) + strlen (name) + strlen (chelp) + 2;
1510 for (i = 0; i < num_counters; ++i) {
1511 CounterCreationData *data = mono_array_get (items, CounterCreationData*, i);
1512 counter_info [i * 2] = mono_string_to_utf8_checked (data->name, &error);
1513 if (!mono_error_ok (&error))
1515 counter_info [i * 2 + 1] = mono_string_to_utf8_checked (data->help, &error);
1516 if (!mono_error_ok (&error))
1518 size += sizeof (SharedCounter) + 1; /* 1 is for the help 0 terminator */
1520 for (i = 0; i < num_counters * 2; ++i) {
1521 if (!counter_info [i])
1523 size += strlen (counter_info [i]) + 1;
1527 counters_data_size = num_counters * 8; /* optimize for size later */
1531 cat = (SharedCategory*) shared_data_reserve_room (size, FTYPE_CATEGORY);
1536 cat->num_counters = num_counters;
1537 cat->counters_data_size = counters_data_size;
1538 /* now copy the vaiable data */
1541 p += strlen (name) + 1;
1543 p += strlen (chelp) + 1;
1544 for (i = 0; i < num_counters; ++i) {
1545 CounterCreationData *data = mono_array_get (items, CounterCreationData*, i);
1546 /* emit the SharedCounter structures */
1547 *p++ = perfctr_type_compress (data->type);
1549 strcpy (p, counter_info [i * 2]);
1550 p += strlen (counter_info [i * 2]) + 1;
1551 strcpy (p, counter_info [i * 2 + 1]);
1552 p += strlen (counter_info [i * 2 + 1]) + 1;
1559 for (i = 0; i < num_counters * 2; ++i) {
1560 g_free (counter_info [i]);
1562 g_free (counter_info);
1566 mono_error_cleanup (&error);
1571 mono_perfcounter_instance_exists (MonoString *instance, MonoString *category, MonoString *machine)
1574 const CategoryDesc *cdesc;
1575 SharedInstance *sinst;
1577 /* no support for counters on other machines */
1578 /*FIXME: machine appears to be wrong
1579 if (mono_string_compare_ascii (machine, "."))
1581 cdesc = find_category (category);
1583 SharedCategory *scat;
1584 scat = find_custom_category (category);
1587 name = mono_string_to_utf8_checked (instance, &error);
1588 mono_error_raise_exception (&error); /* FIXME don't raise here */
1589 sinst = find_custom_instance (scat, name);
1594 /* FIXME: search instance */
1600 mono_perfcounter_category_names (MonoString *machine)
1605 MonoDomain *domain = mono_domain_get ();
1606 GSList *custom_categories, *tmp;
1607 /* no support for counters on other machines */
1608 if (mono_string_compare_ascii (machine, ".")) {
1609 res = mono_array_new_checked (domain, mono_get_string_class (), 0, &error);
1610 mono_error_set_pending_exception (&error);
1614 custom_categories = get_custom_categories ();
1615 res = mono_array_new_checked (domain, mono_get_string_class (), NUM_CATEGORIES + g_slist_length (custom_categories), &error);
1616 if (mono_error_set_pending_exception (&error)) {
1621 for (i = 0; i < NUM_CATEGORIES; ++i) {
1622 const CategoryDesc *cdesc = &predef_categories [i];
1623 mono_array_setref (res, i, mono_string_new (domain, cdesc->name));
1625 for (tmp = custom_categories; tmp; tmp = tmp->next) {
1626 SharedCategory *scat = (SharedCategory *)tmp->data;
1627 mono_array_setref (res, i, mono_string_new (domain, scat->name));
1631 g_slist_free (custom_categories);
1636 mono_perfcounter_counter_names (MonoString *category, MonoString *machine)
1640 SharedCategory *scat;
1641 const CategoryDesc *cdesc;
1643 MonoDomain *domain = mono_domain_get ();
1644 /* no support for counters on other machines */
1645 if (mono_string_compare_ascii (machine, ".")) {
1646 res = mono_array_new_checked (domain, mono_get_string_class (), 0, &error);
1647 mono_error_set_pending_exception (&error);
1650 cdesc = find_category (category);
1652 res = mono_array_new_checked (domain, mono_get_string_class (), cdesc [1].first_counter - cdesc->first_counter, &error);
1653 if (mono_error_set_pending_exception (&error))
1655 for (i = cdesc->first_counter; i < cdesc [1].first_counter; ++i) {
1656 const CounterDesc *desc = &predef_counters [i];
1657 mono_array_setref (res, i - cdesc->first_counter, mono_string_new (domain, desc->name));
1662 scat = find_custom_category (category);
1664 char *p = custom_category_counters (scat);
1666 res = mono_array_new_checked (domain, mono_get_string_class (), scat->num_counters, &error);
1667 if (mono_error_set_pending_exception (&error)) {
1672 for (i = 0; i < scat->num_counters; ++i) {
1673 mono_array_setref (res, i, mono_string_new (domain, p + 1));
1674 p += 2; /* skip counter type */
1675 p += strlen (p) + 1; /* skip counter name */
1676 p += strlen (p) + 1; /* skip counter help */
1682 res = mono_array_new_checked (domain, mono_get_string_class (), 0, &error);
1683 mono_error_set_pending_exception (&error);
1688 get_string_array (void **array, int count, gboolean is_process, MonoError *error)
1691 MonoDomain *domain = mono_domain_get ();
1692 mono_error_init (error);
1693 MonoArray * res = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), count, error);
1694 return_val_if_nok (error, NULL);
1695 for (i = 0; i < count; ++i) {
1699 char *pname = mono_process_get_name (array [i], buf, sizeof (buf));
1700 p = g_strdup_printf ("%d/%s", GPOINTER_TO_INT (array [i]), pname);
1702 sprintf (buf, "%d", GPOINTER_TO_INT (array [i]));
1705 mono_array_setref (res, i, mono_string_new (domain, p));
1713 get_string_array_of_strings (void **array, int count, MonoError *error)
1716 MonoDomain *domain = mono_domain_get ();
1717 mono_error_init (error);
1718 MonoArray * res = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), count, error);
1719 return_val_if_nok (error, NULL);
1720 for (i = 0; i < count; ++i) {
1721 char* p = (char *)array[i];
1722 mono_array_setref (res, i, mono_string_new (domain, p));
1729 get_mono_instances (MonoError *error)
1735 mono_error_init (error);
1739 buf = g_new (void*, count);
1740 res = mono_shared_area_instances (buf, count);
1741 } while (res == count);
1742 array = get_string_array (buf, res, TRUE, error);
1748 get_cpu_instances (MonoError *error)
1753 mono_error_init (error);
1754 count = mono_cpu_count () + 1; /* +1 for "_Total" */
1755 buf = g_new (void*, count);
1756 for (i = 0; i < count; ++i)
1757 buf [i] = GINT_TO_POINTER (i - 1); /* -1 => _Total */
1758 array = get_string_array (buf, count, FALSE, error);
1760 mono_array_setref (array, 0, mono_string_new (mono_domain_get (), "_Total"));
1765 get_processes_instances (MonoError *error)
1769 void **buf = mono_process_list (&count);
1770 mono_error_init (error);
1772 return get_string_array (NULL, 0, FALSE, error);
1773 array = get_string_array (buf, count, TRUE, error);
1779 get_networkinterface_instances (MonoError *error)
1783 mono_error_init (error);
1784 void **buf = mono_networkinterface_list (&count);
1786 return get_string_array_of_strings (NULL, 0, error);
1787 array = get_string_array_of_strings (buf, count, error);
1788 g_strfreev ((char **) buf);
1793 get_custom_instances (MonoString *category, MonoError *error)
1795 SharedCategory *scat;
1796 mono_error_init (error);
1797 scat = find_custom_category (category);
1799 GSList *list = get_custom_instances_list (scat);
1802 MonoArray *array = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), g_slist_length (list), error);
1803 if (!is_ok (error)) {
1804 g_slist_free (list);
1807 for (tmp = list; tmp; tmp = tmp->next) {
1808 SharedInstance *inst = (SharedInstance *)tmp->data;
1809 mono_array_setref (array, i, mono_string_new (mono_domain_get (), inst->instance_name));
1812 g_slist_free (list);
1815 return mono_array_new_checked (mono_domain_get (), mono_get_string_class (), 0, error);
1819 mono_perfcounter_instance_names (MonoString *category, MonoString *machine)
1822 const CategoryDesc* cat;
1823 MonoArray *result = NULL;
1824 if (mono_string_compare_ascii (machine, ".")) {
1825 result = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), 0, &error);
1826 mono_error_set_pending_exception (&error);
1830 cat = find_category (category);
1832 MonoArray *result = get_custom_instances (category, &error);
1833 mono_error_set_pending_exception (&error);
1836 switch (cat->instance_type) {
1838 result = get_mono_instances (&error);
1841 result = get_cpu_instances (&error);
1843 case ProcessInstance:
1844 result = get_processes_instances (&error);
1846 case NetworkInterfaceInstance:
1847 result = get_networkinterface_instances (&error);
1849 case ThreadInstance:
1851 result = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), 0, &error);
1853 mono_error_set_pending_exception (&error);
1858 PerfCounterEnumCallback cb;
1860 } PerfCounterForeachData;
1863 mono_perfcounter_foreach_shared_item (SharedHeader *header, gpointer data)
1869 SharedCategory *cat;
1870 SharedCounter *counter;
1871 SharedInstance *inst;
1872 PerfCounterForeachData *foreach_data = (PerfCounterForeachData *)data;
1874 if (header->ftype == FTYPE_CATEGORY) {
1875 cat = (SharedCategory*)header;
1878 p += strlen (p) + 1; /* skip category name */
1879 p += strlen (p) + 1; /* skip category help */
1881 for (i = 0; i < cat->num_counters; ++i) {
1882 counter = (SharedCounter*) p;
1883 type = (unsigned char)*p++;
1884 /* seq_num = (int)* */ p++;
1886 p += strlen (p) + 1;
1888 p += strlen (p) + 1;
1890 inst = custom_get_instance (cat, counter, name);
1893 addr = custom_get_value_address (counter, inst);
1894 if (!foreach_data->cb (cat->name, name, type, addr ? *(gint64*)addr : 0, foreach_data->data))
1903 mono_perfcounter_foreach (PerfCounterEnumCallback cb, gpointer data)
1905 PerfCounterForeachData foreach_data = { cb, data };
1909 foreach_shared_item (mono_perfcounter_foreach_shared_item, &foreach_data);
1916 mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString* instance, MonoString* machine, int *type, MonoBoolean *custom)
1918 g_assert_not_reached ();
1922 mono_perfcounter_get_sample (void *impl, MonoBoolean only_value, MonoCounterSample *sample)
1924 g_assert_not_reached ();
1928 mono_perfcounter_update_value (void *impl, MonoBoolean do_incr, gint64 value)
1930 g_assert_not_reached ();
1934 mono_perfcounter_free_data (void *impl)
1936 g_assert_not_reached ();
1939 /* Category icalls */
1941 mono_perfcounter_category_del (MonoString *name)
1943 g_assert_not_reached ();
1947 mono_perfcounter_category_help (MonoString *category, MonoString *machine)
1949 g_assert_not_reached ();
1953 mono_perfcounter_category_exists (MonoString *counter, MonoString *category, MonoString *machine)
1955 g_assert_not_reached ();
1959 mono_perfcounter_create (MonoString *category, MonoString *help, int type, MonoArray *items)
1961 g_assert_not_reached ();
1965 mono_perfcounter_instance_exists (MonoString *instance, MonoString *category, MonoString *machine)
1967 g_assert_not_reached ();
1971 mono_perfcounter_category_names (MonoString *machine)
1973 g_assert_not_reached ();
1977 mono_perfcounter_counter_names (MonoString *category, MonoString *machine)
1979 g_assert_not_reached ();
1983 mono_perfcounter_instance_names (MonoString *category, MonoString *machine)
1985 g_assert_not_reached ();