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>
33 #include <sys/sysctl.h>
35 #if defined (__NetBSD__)
36 #include <sys/param.h>
37 #include <sys/sysctl.h>
38 #include <sys/vmmeter.h>
40 #include "metadata/mono-perfcounters.h"
41 #include "metadata/appdomain.h"
42 #include "metadata/object-internals.h"
44 #include "metadata/class-internals.h"
45 #include "utils/mono-time.h"
46 #include "utils/mono-mmap.h"
47 #include "utils/mono-proclib.h"
48 #include "utils/mono-networkinterfaces.h"
49 #include "utils/mono-error-internals.h"
50 #include "utils/atomic.h"
51 #include <mono/io-layer/io-layer.h>
53 /* map of CounterSample.cs */
54 struct _MonoCounterSample {
57 gint64 counterFrequency;
58 gint64 systemFrequency;
60 gint64 timeStamp100nSec;
61 gint64 counterTimeStamp;
65 #ifndef DISABLE_PERFCOUNTERS
66 /* map of PerformanceCounterType.cs */
68 NumberOfItemsHEX32=0x00000000,
69 NumberOfItemsHEX64=0x00000100,
70 NumberOfItems32=0x00010000,
71 NumberOfItems64=0x00010100,
72 CounterDelta32=0x00400400,
73 CounterDelta64=0x00400500,
74 SampleCounter=0x00410400,
75 CountPerTimeInterval32=0x00450400,
76 CountPerTimeInterval64=0x00450500,
77 RateOfCountsPerSecond32=0x10410400,
78 RateOfCountsPerSecond64=0x10410500,
79 RawFraction=0x20020400,
80 CounterTimer=0x20410500,
81 Timer100Ns=0x20510500,
82 SampleFraction=0x20C20400,
83 CounterTimerInverse=0x21410500,
84 Timer100NsInverse=0x21510500,
85 CounterMultiTimer=0x22410500,
86 CounterMultiTimer100Ns=0x22510500,
87 CounterMultiTimerInverse=0x23410500,
88 CounterMultiTimer100NsInverse=0x23510500,
89 AverageTimer32=0x30020400,
90 ElapsedTime=0x30240500,
91 AverageCount64=0x40020500,
92 SampleBase=0x40030401,
93 AverageBase=0x40030402,
95 CounterMultiBase=0x42030500
98 /* maps a small integer type to the counter types above */
100 simple_type_to_type [] = {
101 NumberOfItemsHEX32, NumberOfItemsHEX64,
102 NumberOfItems32, NumberOfItems64,
103 CounterDelta32, CounterDelta64,
104 SampleCounter, CountPerTimeInterval32,
105 CountPerTimeInterval64, RateOfCountsPerSecond32,
106 RateOfCountsPerSecond64, RawFraction,
107 CounterTimer, Timer100Ns,
108 SampleFraction, CounterTimerInverse,
109 Timer100NsInverse, CounterMultiTimer,
110 CounterMultiTimer100Ns, CounterMultiTimerInverse,
111 CounterMultiTimer100NsInverse, AverageTimer32,
112 ElapsedTime, AverageCount64,
113 SampleBase, AverageBase,
114 RawBase, CounterMultiBase
128 NetworkInterfaceInstance,
132 #define PERFCTR_CAT(id,name,help,type,inst,first_counter) CATEGORY_ ## id,
133 #define PERFCTR_COUNTER(id,name,help,type,field)
135 #include "mono-perfcounters-def.h"
140 #undef PERFCTR_COUNTER
141 #define PERFCTR_CAT(id,name,help,type,inst,first_counter) CATEGORY_START_ ## id = -1,
142 #define PERFCTR_COUNTER(id,name,help,type,field) COUNTER_ ## id,
143 /* each counter is assigned an id starting from 0 inside the category */
145 #include "mono-perfcounters-def.h"
150 #undef PERFCTR_COUNTER
151 #define PERFCTR_CAT(id,name,help,type,inst,first_counter)
152 #define PERFCTR_COUNTER(id,name,help,type,field) CCOUNTER_ ## id,
153 /* this is used just to count the number of counters */
155 #include "mono-perfcounters-def.h"
159 static mono_mutex_t perfctr_mutex;
160 #define perfctr_lock() mono_os_mutex_lock (&perfctr_mutex)
161 #define perfctr_unlock() mono_os_mutex_unlock (&perfctr_mutex)
166 unsigned short counters_start;
167 unsigned short counters_size;
168 unsigned short data_start;
169 MonoPerfCounters counters;
174 binary format of custom counters in shared memory, starting from MonoSharedArea* + data_start;
176 struct stanza_header {
177 byte stanza_type; // FTYPE_*
179 ushort stanza_length; // includeas header
184 // perfcat and perfinstance are 4-bytes aligned
188 ushort length; // includes the counters
190 ushort counters_data_size;
192 char name[]; // null terminated
193 char help[]; // null terminated
194 // perfcounters follow
197 char name[]; // null terminated
198 char help[]; // null terminated
203 struct perfinstance {
205 byte data_offset; // offset of counters from beginning of struct
207 uint category_offset; // offset of category in the shared area
208 char name[]; // null terminated
209 // data follows: this is always 8-byte aligned
215 FTYPE_CATEGORY = 'C',
217 FTYPE_PREDEF_INSTANCE = 'P', // an instance of a predef counter
218 FTYPE_INSTANCE = 'I',
231 unsigned short num_counters;
232 unsigned short counters_data_size;
234 /* variable length data follows */
238 // SharedCounter counters_info [num_counters]
243 unsigned int category_offset;
244 /* variable length data follows */
245 char instance_name [1];
252 /* variable length data follows */
263 unsigned int instance_type : 6;
271 unsigned short offset; // offset inside MonoPerfCounters
276 #undef PERFCTR_COUNTER
277 #define PERFCTR_CAT(id,name,help,type,inst,first_counter) {name, help, CATEGORY_ ## id, type, inst ## Instance, CCOUNTER_ ## first_counter},
278 #define PERFCTR_COUNTER(id,name,help,type,field)
279 static const CategoryDesc
280 predef_categories [] = {
281 #include "mono-perfcounters-def.h"
282 {NULL, NULL, NUM_CATEGORIES, -1, 0, NUM_COUNTERS}
286 #undef PERFCTR_COUNTER
287 #define PERFCTR_CAT(id,name,help,type,inst,first_counter)
288 #define PERFCTR_COUNTER(id,name,help,type,field) {name, help, COUNTER_ ## id, G_STRUCT_OFFSET (MonoPerfCounters, field), type},
289 static const CounterDesc
290 predef_counters [] = {
291 #include "mono-perfcounters-def.h"
292 {NULL, NULL, -1, 0, 0}
296 * We have several different classes of counters:
298 * *) runtime counters
300 * *) user-defined counters
301 * *) windows counters (the implementation on windows will use this)
303 * To easily handle the differences we create a vtable for each class that contains the
304 * function pointers with the actual implementation to access the counters.
306 typedef struct _ImplVtable ImplVtable;
308 typedef MonoBoolean (*SampleFunc) (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample* sample);
309 typedef gint64 (*UpdateFunc) (ImplVtable *vtable, MonoBoolean do_incr, gint64 value);
310 typedef void (*CleanupFunc) (ImplVtable *vtable);
326 MonoPerfCounters *counters;
332 SharedInstance *instance_desc;
333 SharedCounter *counter_desc;
337 create_vtable (void *arg, SampleFunc sample, UpdateFunc update)
339 ImplVtable *vtable = g_new0 (ImplVtable, 1);
341 vtable->sample = sample;
342 vtable->update = update;
346 MonoPerfCounters *mono_perfcounters = NULL;
347 static MonoSharedArea *shared_area = NULL;
354 /* maps a pid to a ExternalSArea pointer */
355 static GHashTable *pid_to_shared_area = NULL;
357 static MonoSharedArea *
358 load_sarea_for_pid (int pid)
361 MonoSharedArea *area = NULL;
364 if (pid_to_shared_area == NULL)
365 pid_to_shared_area = g_hash_table_new (NULL, NULL);
366 data = (ExternalSArea *)g_hash_table_lookup (pid_to_shared_area, GINT_TO_POINTER (pid));
368 area = (MonoSharedArea *)mono_shared_area_for_pid (GINT_TO_POINTER (pid));
370 data = g_new (ExternalSArea, 1);
373 g_hash_table_insert (pid_to_shared_area, GINT_TO_POINTER (pid), data);
376 area = (MonoSharedArea *)data->sarea;
384 unref_pid_unlocked (int pid)
387 data = (ExternalSArea *)g_hash_table_lookup (pid_to_shared_area, GINT_TO_POINTER (pid));
390 if (!data->refcount) {
391 g_hash_table_remove (pid_to_shared_area, GINT_TO_POINTER (pid));
392 mono_shared_area_unload (data->sarea);
399 predef_cleanup (ImplVtable *vtable)
401 PredefVtable *vt = (PredefVtable*)vtable;
402 /* ExternalSArea *data; */
405 if (!pid_to_shared_area) {
409 unref_pid_unlocked (vt->pid);
414 mono_determine_physical_ram_size (void)
416 #if defined (TARGET_WIN32)
417 MEMORYSTATUSEX memstat;
419 memstat.dwLength = sizeof (memstat);
420 GlobalMemoryStatusEx (&memstat);
421 return (guint64)memstat.ullTotalPhys;
422 #elif defined (__NetBSD__) || defined (__APPLE__)
436 size_t size_sys = sizeof (value);
438 sysctl (mib, 2, &value, &size_sys, NULL, 0);
442 return (guint64)value;
443 #elif defined (HAVE_SYSCONF)
444 guint64 page_size = 0, num_pages = 0;
446 /* sysconf works on most *NIX operating systems, if your system doesn't have it or if it
447 * reports invalid values, please add your OS specific code below. */
449 page_size = (guint64)sysconf (_SC_PAGESIZE);
452 #ifdef _SC_PHYS_PAGES
453 num_pages = (guint64)sysconf (_SC_PHYS_PAGES);
456 if (!page_size || !num_pages) {
457 g_warning ("Your operating system's sysconf (3) function doesn't correctly report physical memory size!");
461 return page_size * num_pages;
468 mono_determine_physical_ram_available_size (void)
470 #if defined (TARGET_WIN32)
471 MEMORYSTATUSEX memstat;
473 memstat.dwLength = sizeof (memstat);
474 GlobalMemoryStatusEx (&memstat);
475 return (guint64)memstat.ullAvailPhys;
477 #elif defined (__NetBSD__)
478 struct vmtotal vm_total;
486 len = sizeof (vm_total);
487 sysctl (mib, 2, &vm_total, &len, NULL, 0);
490 mib[1] = HW_PAGESIZE;
492 len = sizeof (page_size);
493 sysctl (mib, 2, &page_size, &len, NULL, 0);
495 return ((guint64) vm_total.t_free * page_size) / 1024;
496 #elif defined (__APPLE__)
497 mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
498 mach_port_t host = mach_host_self();
500 vm_statistics_data_t vmstat;
503 ret = host_statistics(host, HOST_VM_INFO, (host_info_t)&vmstat, &count);
504 } while (ret == KERN_ABORTED);
506 if (ret != KERN_SUCCESS) {
507 g_warning ("Mono was unable to retrieve memory usage!");
511 host_page_size(host, &page_size);
512 return (guint64) vmstat.free_count * page_size;
514 #elif defined (HAVE_SYSCONF)
515 guint64 page_size = 0, num_pages = 0;
517 /* sysconf works on most *NIX operating systems, if your system doesn't have it or if it
518 * reports invalid values, please add your OS specific code below. */
520 page_size = (guint64)sysconf (_SC_PAGESIZE);
523 #ifdef _SC_AVPHYS_PAGES
524 num_pages = (guint64)sysconf (_SC_AVPHYS_PAGES);
527 if (!page_size || !num_pages) {
528 g_warning ("Your operating system's sysconf (3) function doesn't correctly report physical memory size!");
532 return page_size * num_pages;
539 mono_perfcounters_init (void)
541 int d_offset = G_STRUCT_OFFSET (MonoSharedArea, data);
545 mono_os_mutex_init_recursive (&perfctr_mutex);
547 shared_area = (MonoSharedArea *)mono_shared_area ();
548 shared_area->counters_start = G_STRUCT_OFFSET (MonoSharedArea, counters);
549 shared_area->counters_size = sizeof (MonoPerfCounters);
550 shared_area->data_start = d_offset;
551 shared_area->size = 4096;
552 mono_perfcounters = &shared_area->counters;
556 perfctr_type_compress (int type)
559 for (i = 0; i < G_N_ELEMENTS (simple_type_to_type); ++i) {
560 if (simple_type_to_type [i] == type)
563 /* NumberOfItems32 */
568 shared_data_reserve_room (int size, int ftype)
570 SharedHeader* header;
571 unsigned char *p = (unsigned char *)shared_area + shared_area->data_start;
572 unsigned char *end = (unsigned char *)shared_area + shared_area->size;
577 unsigned short *next;
578 if (*p == FTYPE_END) {
579 if (size < (end - p))
585 next = (unsigned short*)(p + 2);
586 if (*p == FTYPE_DELETED) {
587 /* we reuse only if it's the same size */
597 header = (SharedHeader*)p;
598 header->ftype = ftype;
599 header->extra = 0; /* data_offset could overflow here, so we leave this field unused */
605 typedef gboolean (*SharedFunc) (SharedHeader *header, void *data);
608 foreach_shared_item_in_area (unsigned char *p, unsigned char *end, SharedFunc func, void *data)
611 unsigned short *next;
614 next = (unsigned short*)(p + 2);
615 if (!func ((SharedHeader*)p, data))
624 foreach_shared_item (SharedFunc func, void *data)
626 unsigned char *p = (unsigned char *)shared_area + shared_area->data_start;
627 unsigned char *end = (unsigned char *)shared_area + shared_area->size;
629 foreach_shared_item_in_area (p, end, func, data);
633 mono_string_compare_ascii (MonoString *str, const char *ascii_str)
635 /* FIXME: make this case insensitive */
636 guint16 *strc = mono_string_chars (str);
637 while (*strc == *ascii_str++) {
642 return *strc - *(const unsigned char *)(ascii_str - 1);
651 category_search (SharedHeader *header, void *data)
653 CatSearch *search = (CatSearch *)data;
654 if (header->ftype == FTYPE_CATEGORY) {
655 SharedCategory *cat = (SharedCategory*)header;
656 if (mono_string_compare_ascii (search->name, cat->name) == 0) {
664 static SharedCategory*
665 find_custom_category (MonoString *name)
670 foreach_shared_item (category_search, &search);
675 category_collect (SharedHeader *header, void *data)
677 GSList **list = (GSList **)data;
678 if (header->ftype == FTYPE_CATEGORY) {
679 *list = g_slist_prepend (*list, header);
685 get_custom_categories (void) {
687 foreach_shared_item (category_collect, &list);
692 custom_category_counters (SharedCategory* cat)
694 char *p = cat->name + strlen (cat->name) + 1;
695 p += strlen (p) + 1; /* skip category help */
699 static SharedCounter*
700 find_custom_counter (SharedCategory* cat, MonoString *name)
703 char *p = custom_category_counters (cat);
704 for (i = 0; i < cat->num_counters; ++i) {
705 SharedCounter *counter = (SharedCounter*)p;
706 if (mono_string_compare_ascii (name, counter->name) == 0)
708 p += 2; /* skip counter type */
709 p += strlen (p) + 1; /* skip counter name */
710 p += strlen (p) + 1; /* skip counter help */
716 unsigned int cat_offset;
719 SharedInstance* result;
724 instance_search (SharedHeader *header, void *data)
726 InstanceSearch *search = (InstanceSearch *)data;
727 if (header->ftype == FTYPE_INSTANCE) {
728 SharedInstance *ins = (SharedInstance*)header;
729 if (search->cat_offset == ins->category_offset) {
731 if (strcmp (search->name, ins->instance_name) == 0) {
732 search->result = ins;
736 search->list = g_slist_prepend (search->list, ins);
743 static SharedInstance*
744 find_custom_instance (SharedCategory* cat, char *name)
746 InstanceSearch search;
747 search.cat_offset = (char*)cat - (char*)shared_area;
751 search.result = NULL;
752 foreach_shared_item (instance_search, &search);
753 return search.result;
757 get_custom_instances_list (SharedCategory* cat)
759 InstanceSearch search;
760 search.cat_offset = (char*)cat - (char*)shared_area;
764 search.result = NULL;
765 foreach_shared_item (instance_search, &search);
770 custom_category_help (SharedCategory* cat)
772 return cat->name + strlen (cat->name) + 1;
775 static const CounterDesc*
776 get_counter_in_category (const CategoryDesc *desc, MonoString *counter)
778 const CounterDesc *cdesc = &predef_counters [desc->first_counter];
779 const CounterDesc *end = &predef_counters [desc [1].first_counter];
780 for (; cdesc < end; ++cdesc) {
781 if (mono_string_compare_ascii (counter, cdesc->name) == 0)
787 /* fill the info in sample (except the raw value) */
789 fill_sample (MonoCounterSample *sample)
791 sample->timeStamp = mono_100ns_ticks ();
792 sample->timeStamp100nSec = sample->timeStamp;
793 sample->counterTimeStamp = sample->timeStamp;
794 sample->counterFrequency = 10000000;
795 sample->systemFrequency = 10000000;
796 // the real basevalue needs to be get from a different counter...
797 sample->baseValue = 0;
801 id_from_string (const gchar *id_str, gboolean is_process)
804 if (strcmp("", id_str) != 0) {
806 id = strtol (id_str, &end, 0);
807 if (end == id_str && !is_process)
814 get_cpu_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
816 MonoProcessError error;
817 int id = GPOINTER_TO_INT (vtable->arg);
821 fill_sample (sample);
822 sample->baseValue = 1;
824 sample->counterType = predef_counters [predef_categories [CATEGORY_CPU].first_counter + id].type;
826 case COUNTER_CPU_USER_TIME:
827 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_USER_TIME, &error);
829 case COUNTER_CPU_PRIV_TIME:
830 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_PRIV_TIME, &error);
832 case COUNTER_CPU_INTR_TIME:
833 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_INTR_TIME, &error);
835 case COUNTER_CPU_DCP_TIME:
836 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_DCP_TIME, &error);
838 case COUNTER_CPU_PROC_TIME:
839 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_IDLE_TIME, &error);
846 cpu_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
848 int id = id_from_string (instance, FALSE) << 5;
849 const CounterDesc *cdesc;
851 /* increase the shift above and the mask also in the implementation functions */
852 //g_assert (32 > desc [1].first_counter - desc->first_counter);
853 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_CPU], counter))) {
855 return create_vtable (GINT_TO_POINTER (id | cdesc->id), get_cpu_counter, NULL);
861 get_network_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
863 MonoNetworkError error = MONO_NETWORK_ERROR_OTHER;
864 NetworkVtableArg *narg = (NetworkVtableArg*) vtable->arg;
866 fill_sample (sample);
869 sample->counterType = predef_counters [predef_categories [CATEGORY_NETWORK].first_counter + narg->id].type;
871 case COUNTER_NETWORK_BYTESRECSEC:
872 sample->rawValue = mono_network_get_data (narg->name, MONO_NETWORK_BYTESREC, &error);
874 case COUNTER_NETWORK_BYTESSENTSEC:
875 sample->rawValue = mono_network_get_data (narg->name, MONO_NETWORK_BYTESSENT, &error);
877 case COUNTER_NETWORK_BYTESTOTALSEC:
878 sample->rawValue = mono_network_get_data (narg->name, MONO_NETWORK_BYTESTOTAL, &error);
882 if (error == MONO_NETWORK_ERROR_NONE)
889 network_cleanup (ImplVtable *vtable)
891 NetworkVtableArg *narg;
896 narg = (NetworkVtableArg *)vtable->arg;
907 network_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
909 const CounterDesc *cdesc;
910 NetworkVtableArg *narg;
915 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_NETWORK], counter))) {
916 instance_name = g_strdup (instance);
917 narg = g_new0 (NetworkVtableArg, 1);
918 narg->id = cdesc->id;
919 narg->name = instance_name;
921 vtable = create_vtable (narg, get_network_counter, NULL);
922 vtable->cleanup = network_cleanup;
929 get_process_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
931 int id = GPOINTER_TO_INT (vtable->arg);
937 fill_sample (sample);
938 sample->baseValue = 1;
940 sample->counterType = predef_counters [predef_categories [CATEGORY_PROC].first_counter + id].type;
942 case COUNTER_PROC_USER_TIME:
943 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_USER_TIME);
945 case COUNTER_PROC_PRIV_TIME:
946 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_SYSTEM_TIME);
948 case COUNTER_PROC_PROC_TIME:
949 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_TOTAL_TIME);
951 case COUNTER_PROC_THREADS:
952 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_NUM_THREADS);
954 case COUNTER_PROC_VBYTES:
955 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_VIRTUAL_BYTES);
957 case COUNTER_PROC_WSET:
958 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_WORKING_SET);
960 case COUNTER_PROC_PBYTES:
961 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_PRIVATE_BYTES);
968 process_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
970 int id = id_from_string (instance, TRUE) << 5;
971 const CounterDesc *cdesc;
973 /* increase the shift above and the mask also in the implementation functions */
974 //g_assert (32 > desc [1].first_counter - desc->first_counter);
975 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_PROC], counter))) {
977 return create_vtable (GINT_TO_POINTER (id | cdesc->id), get_process_counter, NULL);
983 mono_mem_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
985 int id = GPOINTER_TO_INT (vtable->arg);
987 fill_sample (sample);
988 sample->baseValue = 1;
990 sample->counterType = predef_counters [predef_categories [CATEGORY_MONO_MEM].first_counter + id].type;
992 case COUNTER_MEM_NUM_OBJECTS:
993 sample->rawValue = 0;
995 case COUNTER_MEM_PHYS_TOTAL:
996 sample->rawValue = mono_determine_physical_ram_size ();;
998 case COUNTER_MEM_PHYS_AVAILABLE:
999 sample->rawValue = mono_determine_physical_ram_available_size ();;
1006 mono_mem_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
1008 const CounterDesc *cdesc;
1010 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_MONO_MEM], counter))) {
1011 *type = cdesc->type;
1012 return create_vtable (GINT_TO_POINTER ((gint) cdesc->id), mono_mem_counter, NULL);
1018 predef_readonly_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
1020 PredefVtable *vt = (PredefVtable *)vtable;
1021 const CounterDesc *desc;
1022 int cat_id = GPOINTER_TO_INT (vtable->arg);
1023 int id = cat_id >> 16;
1026 fill_sample (sample);
1027 sample->baseValue = 1;
1029 desc = &predef_counters [predef_categories [cat_id].first_counter + id];
1030 sample->counterType = desc->type;
1031 /* FIXME: check that the offset fits inside imported counters */
1032 /*g_print ("loading %s at %d\n", desc->name, desc->offset);*/
1033 sample->rawValue = *(guint32*)((char*)vt->counters + desc->offset);
1038 predef_vtable (void *arg, const gchar *pids)
1040 MonoSharedArea *area;
1041 PredefVtable *vtable;
1045 area = load_sarea_for_pid (pid);
1049 vtable = g_new (PredefVtable, 1);
1050 vtable->vtable.arg = arg;
1051 vtable->vtable.sample = predef_readonly_counter;
1052 vtable->vtable.cleanup = predef_cleanup;
1053 vtable->counters = (MonoPerfCounters*)((char*)area + area->counters_start);
1056 return (ImplVtable*)vtable;
1059 /* consider storing the pointer directly in vtable->arg, so the runtime overhead is lower:
1060 * this needs some way to set sample->counterType as well, though.
1063 predef_writable_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
1065 int cat_id = GPOINTER_TO_INT (vtable->arg);
1066 int id = cat_id >> 16;
1069 fill_sample (sample);
1070 sample->baseValue = 1;
1072 sample->counterType = predef_counters [predef_categories [cat_id].first_counter + id].type;
1076 case COUNTER_EXC_THROWN:
1077 sample->rawValue = mono_perfcounters->exceptions_thrown;
1081 case CATEGORY_ASPNET:
1083 case COUNTER_ASPNET_REQ_Q:
1084 sample->rawValue = mono_perfcounters->aspnet_requests_queued;
1086 case COUNTER_ASPNET_REQ_TOTAL:
1087 sample->rawValue = mono_perfcounters->aspnet_requests;
1091 case CATEGORY_THREADPOOL:
1093 case COUNTER_THREADPOOL_WORKITEMS:
1094 sample->rawValue = mono_perfcounters->threadpool_workitems;
1096 case COUNTER_THREADPOOL_IOWORKITEMS:
1097 sample->rawValue = mono_perfcounters->threadpool_ioworkitems;
1099 case COUNTER_THREADPOOL_THREADS:
1100 sample->rawValue = mono_perfcounters->threadpool_threads;
1102 case COUNTER_THREADPOOL_IOTHREADS:
1103 sample->rawValue = mono_perfcounters->threadpool_iothreads;
1109 case COUNTER_JIT_BYTES:
1110 sample->rawValue = mono_perfcounters->jit_bytes;
1112 case COUNTER_JIT_METHODS:
1113 sample->rawValue = mono_perfcounters->jit_methods;
1115 case COUNTER_JIT_TIME:
1116 sample->rawValue = mono_perfcounters->jit_time;
1118 case COUNTER_JIT_BYTES_PSEC:
1119 sample->rawValue = mono_perfcounters->jit_bytes;
1121 case COUNTER_JIT_FAILURES:
1122 sample->rawValue = mono_perfcounters->jit_failures;
1131 predef_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
1133 guint32 *volatile ptr = NULL;
1134 gint64 *volatile ptr64 = NULL;
1135 int cat_id = GPOINTER_TO_INT (vtable->arg);
1136 int id = cat_id >> 16;
1139 case CATEGORY_ASPNET:
1141 case COUNTER_ASPNET_REQ_Q: ptr = &mono_perfcounters->aspnet_requests_queued; break;
1142 case COUNTER_ASPNET_REQ_TOTAL: ptr = &mono_perfcounters->aspnet_requests; break;
1145 case CATEGORY_THREADPOOL:
1147 case COUNTER_THREADPOOL_WORKITEMS: ptr64 = (gint64 *) &mono_perfcounters->threadpool_workitems; break;
1148 case COUNTER_THREADPOOL_IOWORKITEMS: ptr64 = (gint64 *) &mono_perfcounters->threadpool_ioworkitems; break;
1149 case COUNTER_THREADPOOL_THREADS: ptr = &mono_perfcounters->threadpool_threads; break;
1150 case COUNTER_THREADPOOL_IOTHREADS: ptr = &mono_perfcounters->threadpool_iothreads; break;
1157 return InterlockedIncrement ((gint32 *) ptr); /* FIXME: sign */
1159 return InterlockedDecrement ((gint32 *) ptr); /* FIXME: sign */
1164 /* this can be non-atomic */
1169 /* FIXME: we need to do this atomically */
1170 /* No InterlockedIncrement64() yet */
1173 return InterlockedIncrement64 (ptr);
1175 return InterlockedDecrement64 (ptr);
1181 /* this can be non-atomic */
1189 predef_writable_get_impl (int cat, MonoString* counter, const gchar *instance, int *type, MonoBoolean *custom)
1191 const CounterDesc *cdesc;
1193 if ((cdesc = get_counter_in_category (&predef_categories [cat], counter))) {
1194 *type = cdesc->type;
1195 if (instance == NULL || strcmp (instance, "") == 0)
1196 return create_vtable (GINT_TO_POINTER ((cdesc->id << 16) | cat), predef_writable_counter, predef_writable_update);
1198 return predef_vtable (GINT_TO_POINTER ((cdesc->id << 16) | cat), instance);
1204 custom_writable_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
1206 CustomVTable *counter_data = (CustomVTable *)vtable;
1208 fill_sample (sample);
1209 sample->baseValue = 1;
1211 sample->counterType = simple_type_to_type [counter_data->counter_desc->type];
1213 sample->rawValue = 0;
1215 sample->rawValue = *(guint64*)vtable->arg;
1220 custom_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
1222 /* FIXME: check writability */
1223 guint64 *ptr = (guint64 *)vtable->arg;
1226 /* FIXME: we need to do this atomically */
1230 /* this can be non-atomic */
1237 static SharedInstance*
1238 custom_get_instance (SharedCategory *cat, SharedCounter *scounter, char* name)
1240 SharedInstance* inst;
1243 inst = find_custom_instance (cat, name);
1246 size = sizeof (SharedInstance) + strlen (name);
1249 size += (sizeof (guint64) * cat->num_counters);
1251 inst = (SharedInstance*) shared_data_reserve_room (size, FTYPE_INSTANCE);
1257 inst->category_offset = (char*)cat - (char*)shared_area;
1258 cat->num_instances++;
1259 /* now copy the variable data */
1260 p = inst->instance_name;
1262 p += strlen (name) + 1;
1269 custom_vtable (SharedCounter *scounter, SharedInstance* inst, char *data)
1271 CustomVTable* vtable;
1272 vtable = g_new0 (CustomVTable, 1);
1273 vtable->vtable.arg = data;
1274 vtable->vtable.sample = custom_writable_counter;
1275 vtable->vtable.update = custom_writable_update;
1276 vtable->instance_desc = inst;
1277 vtable->counter_desc = scounter;
1279 return (ImplVtable*)vtable;
1283 custom_get_value_address (SharedCounter *scounter, SharedInstance* sinst)
1285 int offset = sizeof (SharedInstance) + strlen (sinst->instance_name);
1288 offset += scounter->seq_num * sizeof (guint64);
1289 return (char*)sinst + offset;
1293 custom_get_impl (SharedCategory *cat, MonoString *counter, MonoString* instance, int *type, MonoError *error)
1295 SharedCounter *scounter;
1296 SharedInstance* inst;
1299 mono_error_init (error);
1300 scounter = find_custom_counter (cat, counter);
1303 name = mono_string_to_utf8_checked (counter, error);
1304 return_val_if_nok (error, NULL);
1305 *type = simple_type_to_type [scounter->type];
1306 inst = custom_get_instance (cat, scounter, name);
1310 return custom_vtable (scounter, inst, (char *)custom_get_value_address (scounter, inst));
1313 static const CategoryDesc*
1314 find_category (MonoString *category)
1317 for (i = 0; i < NUM_CATEGORIES; ++i) {
1318 if (mono_string_compare_ascii (category, predef_categories [i].name) == 0)
1319 return &predef_categories [i];
1325 mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString* instance,
1326 MonoString* machine, int *type, MonoBoolean *custom)
1329 const CategoryDesc *cdesc;
1330 void *result = NULL;
1331 /* no support for counters on other machines */
1332 if (mono_string_compare_ascii (machine, "."))
1334 cdesc = find_category (category);
1336 SharedCategory *scat = find_custom_category (category);
1340 result = custom_get_impl (scat, counter, instance, type, &error);
1341 if (mono_error_set_pending_exception (&error))
1345 gchar *c_instance = mono_string_to_utf8_checked (instance, &error);
1346 if (mono_error_set_pending_exception (&error))
1348 switch (cdesc->id) {
1350 result = cpu_get_impl (counter, c_instance, type, custom);
1353 result = process_get_impl (counter, c_instance, type, custom);
1355 case CATEGORY_MONO_MEM:
1356 result = mono_mem_get_impl (counter, c_instance, type, custom);
1358 case CATEGORY_NETWORK:
1359 result = network_get_impl (counter, c_instance, type, custom);
1364 case CATEGORY_REMOTING:
1365 case CATEGORY_LOADING:
1366 case CATEGORY_THREAD:
1367 case CATEGORY_INTEROP:
1368 case CATEGORY_SECURITY:
1369 case CATEGORY_ASPNET:
1370 case CATEGORY_THREADPOOL:
1371 result = predef_writable_get_impl (cdesc->id, counter, c_instance, type, custom);
1374 g_free (c_instance);
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 if (mono_error_set_pending_exception (&error))
1590 sinst = find_custom_instance (scat, name);
1595 /* FIXME: search instance */
1601 mono_perfcounter_category_names (MonoString *machine)
1606 MonoDomain *domain = mono_domain_get ();
1607 GSList *custom_categories, *tmp;
1608 /* no support for counters on other machines */
1609 if (mono_string_compare_ascii (machine, ".")) {
1610 res = mono_array_new_checked (domain, mono_get_string_class (), 0, &error);
1611 mono_error_set_pending_exception (&error);
1615 custom_categories = get_custom_categories ();
1616 res = mono_array_new_checked (domain, mono_get_string_class (), NUM_CATEGORIES + g_slist_length (custom_categories), &error);
1617 if (mono_error_set_pending_exception (&error)) {
1622 for (i = 0; i < NUM_CATEGORIES; ++i) {
1623 const CategoryDesc *cdesc = &predef_categories [i];
1624 mono_array_setref (res, i, mono_string_new (domain, cdesc->name));
1626 for (tmp = custom_categories; tmp; tmp = tmp->next) {
1627 SharedCategory *scat = (SharedCategory *)tmp->data;
1628 mono_array_setref (res, i, mono_string_new (domain, scat->name));
1632 g_slist_free (custom_categories);
1637 mono_perfcounter_counter_names (MonoString *category, MonoString *machine)
1641 SharedCategory *scat;
1642 const CategoryDesc *cdesc;
1644 MonoDomain *domain = mono_domain_get ();
1645 /* no support for counters on other machines */
1646 if (mono_string_compare_ascii (machine, ".")) {
1647 res = mono_array_new_checked (domain, mono_get_string_class (), 0, &error);
1648 mono_error_set_pending_exception (&error);
1651 cdesc = find_category (category);
1653 res = mono_array_new_checked (domain, mono_get_string_class (), cdesc [1].first_counter - cdesc->first_counter, &error);
1654 if (mono_error_set_pending_exception (&error))
1656 for (i = cdesc->first_counter; i < cdesc [1].first_counter; ++i) {
1657 const CounterDesc *desc = &predef_counters [i];
1658 mono_array_setref (res, i - cdesc->first_counter, mono_string_new (domain, desc->name));
1663 scat = find_custom_category (category);
1665 char *p = custom_category_counters (scat);
1667 res = mono_array_new_checked (domain, mono_get_string_class (), scat->num_counters, &error);
1668 if (mono_error_set_pending_exception (&error)) {
1673 for (i = 0; i < scat->num_counters; ++i) {
1674 mono_array_setref (res, i, mono_string_new (domain, p + 1));
1675 p += 2; /* skip counter type */
1676 p += strlen (p) + 1; /* skip counter name */
1677 p += strlen (p) + 1; /* skip counter help */
1683 res = mono_array_new_checked (domain, mono_get_string_class (), 0, &error);
1684 mono_error_set_pending_exception (&error);
1689 get_string_array (void **array, int count, gboolean is_process, MonoError *error)
1692 MonoDomain *domain = mono_domain_get ();
1693 mono_error_init (error);
1694 MonoArray * res = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), count, error);
1695 return_val_if_nok (error, NULL);
1696 for (i = 0; i < count; ++i) {
1700 char *pname = mono_process_get_name (array [i], buf, sizeof (buf));
1701 p = g_strdup_printf ("%d/%s", GPOINTER_TO_INT (array [i]), pname);
1703 sprintf (buf, "%d", GPOINTER_TO_INT (array [i]));
1706 mono_array_setref (res, i, mono_string_new (domain, p));
1714 get_string_array_of_strings (void **array, int count, MonoError *error)
1717 MonoDomain *domain = mono_domain_get ();
1718 mono_error_init (error);
1719 MonoArray * res = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), count, error);
1720 return_val_if_nok (error, NULL);
1721 for (i = 0; i < count; ++i) {
1722 char* p = (char *)array[i];
1723 mono_array_setref (res, i, mono_string_new (domain, p));
1730 get_mono_instances (MonoError *error)
1736 mono_error_init (error);
1740 buf = g_new (void*, count);
1741 res = mono_shared_area_instances (buf, count);
1742 } while (res == count);
1743 array = get_string_array (buf, res, TRUE, error);
1749 get_cpu_instances (MonoError *error)
1754 mono_error_init (error);
1755 count = mono_cpu_count () + 1; /* +1 for "_Total" */
1756 buf = g_new (void*, count);
1757 for (i = 0; i < count; ++i)
1758 buf [i] = GINT_TO_POINTER (i - 1); /* -1 => _Total */
1759 array = get_string_array (buf, count, FALSE, error);
1761 mono_array_setref (array, 0, mono_string_new (mono_domain_get (), "_Total"));
1766 get_processes_instances (MonoError *error)
1770 void **buf = mono_process_list (&count);
1771 mono_error_init (error);
1773 return get_string_array (NULL, 0, FALSE, error);
1774 array = get_string_array (buf, count, TRUE, error);
1780 get_networkinterface_instances (MonoError *error)
1784 mono_error_init (error);
1785 void **buf = mono_networkinterface_list (&count);
1787 return get_string_array_of_strings (NULL, 0, error);
1788 array = get_string_array_of_strings (buf, count, error);
1789 g_strfreev ((char **) buf);
1794 get_custom_instances (MonoString *category, MonoError *error)
1796 SharedCategory *scat;
1797 mono_error_init (error);
1798 scat = find_custom_category (category);
1800 GSList *list = get_custom_instances_list (scat);
1803 MonoArray *array = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), g_slist_length (list), error);
1804 if (!is_ok (error)) {
1805 g_slist_free (list);
1808 for (tmp = list; tmp; tmp = tmp->next) {
1809 SharedInstance *inst = (SharedInstance *)tmp->data;
1810 mono_array_setref (array, i, mono_string_new (mono_domain_get (), inst->instance_name));
1813 g_slist_free (list);
1816 return mono_array_new_checked (mono_domain_get (), mono_get_string_class (), 0, error);
1820 mono_perfcounter_instance_names (MonoString *category, MonoString *machine)
1823 const CategoryDesc* cat;
1824 MonoArray *result = NULL;
1825 if (mono_string_compare_ascii (machine, ".")) {
1826 result = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), 0, &error);
1827 mono_error_set_pending_exception (&error);
1831 cat = find_category (category);
1833 MonoArray *result = get_custom_instances (category, &error);
1834 mono_error_set_pending_exception (&error);
1837 switch (cat->instance_type) {
1839 result = get_mono_instances (&error);
1842 result = get_cpu_instances (&error);
1844 case ProcessInstance:
1845 result = get_processes_instances (&error);
1847 case NetworkInterfaceInstance:
1848 result = get_networkinterface_instances (&error);
1850 case ThreadInstance:
1852 result = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), 0, &error);
1854 mono_error_set_pending_exception (&error);
1859 PerfCounterEnumCallback cb;
1861 } PerfCounterForeachData;
1864 mono_perfcounter_foreach_shared_item (SharedHeader *header, gpointer data)
1870 SharedCategory *cat;
1871 SharedCounter *counter;
1872 SharedInstance *inst;
1873 PerfCounterForeachData *foreach_data = (PerfCounterForeachData *)data;
1875 if (header->ftype == FTYPE_CATEGORY) {
1876 cat = (SharedCategory*)header;
1879 p += strlen (p) + 1; /* skip category name */
1880 p += strlen (p) + 1; /* skip category help */
1882 for (i = 0; i < cat->num_counters; ++i) {
1883 counter = (SharedCounter*) p;
1884 type = (unsigned char)*p++;
1885 /* seq_num = (int)* */ p++;
1887 p += strlen (p) + 1;
1889 p += strlen (p) + 1;
1891 inst = custom_get_instance (cat, counter, name);
1894 addr = custom_get_value_address (counter, inst);
1895 if (!foreach_data->cb (cat->name, name, type, addr ? *(gint64*)addr : 0, foreach_data->data))
1904 mono_perfcounter_foreach (PerfCounterEnumCallback cb, gpointer data)
1906 PerfCounterForeachData foreach_data = { cb, data };
1910 foreach_shared_item (mono_perfcounter_foreach_shared_item, &foreach_data);
1917 mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString* instance, MonoString* machine, int *type, MonoBoolean *custom)
1919 g_assert_not_reached ();
1923 mono_perfcounter_get_sample (void *impl, MonoBoolean only_value, MonoCounterSample *sample)
1925 g_assert_not_reached ();
1929 mono_perfcounter_update_value (void *impl, MonoBoolean do_incr, gint64 value)
1931 g_assert_not_reached ();
1935 mono_perfcounter_free_data (void *impl)
1937 g_assert_not_reached ();
1940 /* Category icalls */
1942 mono_perfcounter_category_del (MonoString *name)
1944 g_assert_not_reached ();
1948 mono_perfcounter_category_help (MonoString *category, MonoString *machine)
1950 g_assert_not_reached ();
1954 mono_perfcounter_category_exists (MonoString *counter, MonoString *category, MonoString *machine)
1956 g_assert_not_reached ();
1960 mono_perfcounter_create (MonoString *category, MonoString *help, int type, MonoArray *items)
1962 g_assert_not_reached ();
1966 mono_perfcounter_instance_exists (MonoString *instance, MonoString *category, MonoString *machine)
1968 g_assert_not_reached ();
1972 mono_perfcounter_category_names (MonoString *machine)
1974 g_assert_not_reached ();
1978 mono_perfcounter_counter_names (MonoString *category, MonoString *machine)
1980 g_assert_not_reached ();
1984 mono_perfcounter_instance_names (MonoString *category, MonoString *machine)
1986 g_assert_not_reached ();