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"
52 /* map of CounterSample.cs */
53 struct _MonoCounterSample {
56 gint64 counterFrequency;
57 gint64 systemFrequency;
59 gint64 timeStamp100nSec;
60 gint64 counterTimeStamp;
64 #ifndef DISABLE_PERFCOUNTERS
65 /* map of PerformanceCounterType.cs */
67 NumberOfItemsHEX32=0x00000000,
68 NumberOfItemsHEX64=0x00000100,
69 NumberOfItems32=0x00010000,
70 NumberOfItems64=0x00010100,
71 CounterDelta32=0x00400400,
72 CounterDelta64=0x00400500,
73 SampleCounter=0x00410400,
74 CountPerTimeInterval32=0x00450400,
75 CountPerTimeInterval64=0x00450500,
76 RateOfCountsPerSecond32=0x10410400,
77 RateOfCountsPerSecond64=0x10410500,
78 RawFraction=0x20020400,
79 CounterTimer=0x20410500,
80 Timer100Ns=0x20510500,
81 SampleFraction=0x20C20400,
82 CounterTimerInverse=0x21410500,
83 Timer100NsInverse=0x21510500,
84 CounterMultiTimer=0x22410500,
85 CounterMultiTimer100Ns=0x22510500,
86 CounterMultiTimerInverse=0x23410500,
87 CounterMultiTimer100NsInverse=0x23510500,
88 AverageTimer32=0x30020400,
89 ElapsedTime=0x30240500,
90 AverageCount64=0x40020500,
91 SampleBase=0x40030401,
92 AverageBase=0x40030402,
94 CounterMultiBase=0x42030500
97 /* maps a small integer type to the counter types above */
99 simple_type_to_type [] = {
100 NumberOfItemsHEX32, NumberOfItemsHEX64,
101 NumberOfItems32, NumberOfItems64,
102 CounterDelta32, CounterDelta64,
103 SampleCounter, CountPerTimeInterval32,
104 CountPerTimeInterval64, RateOfCountsPerSecond32,
105 RateOfCountsPerSecond64, RawFraction,
106 CounterTimer, Timer100Ns,
107 SampleFraction, CounterTimerInverse,
108 Timer100NsInverse, CounterMultiTimer,
109 CounterMultiTimer100Ns, CounterMultiTimerInverse,
110 CounterMultiTimer100NsInverse, AverageTimer32,
111 ElapsedTime, AverageCount64,
112 SampleBase, AverageBase,
113 RawBase, CounterMultiBase
127 NetworkInterfaceInstance,
131 #define PERFCTR_CAT(id,name,help,type,inst,first_counter) CATEGORY_ ## id,
132 #define PERFCTR_COUNTER(id,name,help,type,field)
134 #include "mono-perfcounters-def.h"
139 #undef PERFCTR_COUNTER
140 #define PERFCTR_CAT(id,name,help,type,inst,first_counter) CATEGORY_START_ ## id = -1,
141 #define PERFCTR_COUNTER(id,name,help,type,field) COUNTER_ ## id,
142 /* each counter is assigned an id starting from 0 inside the category */
144 #include "mono-perfcounters-def.h"
149 #undef PERFCTR_COUNTER
150 #define PERFCTR_CAT(id,name,help,type,inst,first_counter)
151 #define PERFCTR_COUNTER(id,name,help,type,field) CCOUNTER_ ## id,
152 /* this is used just to count the number of counters */
154 #include "mono-perfcounters-def.h"
158 static mono_mutex_t perfctr_mutex;
159 #define perfctr_lock() mono_os_mutex_lock (&perfctr_mutex)
160 #define perfctr_unlock() mono_os_mutex_unlock (&perfctr_mutex)
165 unsigned short counters_start;
166 unsigned short counters_size;
167 unsigned short data_start;
168 MonoPerfCounters counters;
173 binary format of custom counters in shared memory, starting from MonoSharedArea* + data_start;
175 struct stanza_header {
176 byte stanza_type; // FTYPE_*
178 ushort stanza_length; // includeas header
183 // perfcat and perfinstance are 4-bytes aligned
187 ushort length; // includes the counters
189 ushort counters_data_size;
191 char name[]; // null terminated
192 char help[]; // null terminated
193 // perfcounters follow
196 char name[]; // null terminated
197 char help[]; // null terminated
202 struct perfinstance {
204 byte data_offset; // offset of counters from beginning of struct
206 uint category_offset; // offset of category in the shared area
207 char name[]; // null terminated
208 // data follows: this is always 8-byte aligned
214 FTYPE_CATEGORY = 'C',
216 FTYPE_PREDEF_INSTANCE = 'P', // an instance of a predef counter
217 FTYPE_INSTANCE = 'I',
230 unsigned short num_counters;
231 unsigned short counters_data_size;
233 /* variable length data follows */
237 // SharedCounter counters_info [num_counters]
242 unsigned int category_offset;
243 /* variable length data follows */
244 char instance_name [1];
251 /* variable length data follows */
262 unsigned int instance_type : 6;
270 unsigned short offset; // offset inside MonoPerfCounters
275 #undef PERFCTR_COUNTER
276 #define PERFCTR_CAT(id,name,help,type,inst,first_counter) {name, help, CATEGORY_ ## id, type, inst ## Instance, CCOUNTER_ ## first_counter},
277 #define PERFCTR_COUNTER(id,name,help,type,field)
278 static const CategoryDesc
279 predef_categories [] = {
280 #include "mono-perfcounters-def.h"
281 {NULL, NULL, NUM_CATEGORIES, -1, 0, NUM_COUNTERS}
285 #undef PERFCTR_COUNTER
286 #define PERFCTR_CAT(id,name,help,type,inst,first_counter)
287 #define PERFCTR_COUNTER(id,name,help,type,field) {name, help, COUNTER_ ## id, G_STRUCT_OFFSET (MonoPerfCounters, field), type},
288 static const CounterDesc
289 predef_counters [] = {
290 #include "mono-perfcounters-def.h"
291 {NULL, NULL, -1, 0, 0}
295 * We have several different classes of counters:
297 * *) runtime counters
299 * *) user-defined counters
300 * *) windows counters (the implementation on windows will use this)
302 * To easily handle the differences we create a vtable for each class that contains the
303 * function pointers with the actual implementation to access the counters.
305 typedef struct _ImplVtable ImplVtable;
307 typedef MonoBoolean (*SampleFunc) (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample* sample);
308 typedef gint64 (*UpdateFunc) (ImplVtable *vtable, MonoBoolean do_incr, gint64 value);
309 typedef void (*CleanupFunc) (ImplVtable *vtable);
325 MonoPerfCounters *counters;
331 SharedInstance *instance_desc;
332 SharedCounter *counter_desc;
336 create_vtable (void *arg, SampleFunc sample, UpdateFunc update)
338 ImplVtable *vtable = g_new0 (ImplVtable, 1);
340 vtable->sample = sample;
341 vtable->update = update;
345 MonoPerfCounters *mono_perfcounters = NULL;
346 static MonoSharedArea *shared_area = NULL;
353 /* maps a pid to a ExternalSArea pointer */
354 static GHashTable *pid_to_shared_area = NULL;
356 static MonoSharedArea *
357 load_sarea_for_pid (int pid)
360 MonoSharedArea *area = NULL;
363 if (pid_to_shared_area == NULL)
364 pid_to_shared_area = g_hash_table_new (NULL, NULL);
365 data = (ExternalSArea *)g_hash_table_lookup (pid_to_shared_area, GINT_TO_POINTER (pid));
367 area = (MonoSharedArea *)mono_shared_area_for_pid (GINT_TO_POINTER (pid));
369 data = g_new (ExternalSArea, 1);
372 g_hash_table_insert (pid_to_shared_area, GINT_TO_POINTER (pid), data);
375 area = (MonoSharedArea *)data->sarea;
383 unref_pid_unlocked (int pid)
386 data = (ExternalSArea *)g_hash_table_lookup (pid_to_shared_area, GINT_TO_POINTER (pid));
389 if (!data->refcount) {
390 g_hash_table_remove (pid_to_shared_area, GINT_TO_POINTER (pid));
391 mono_shared_area_unload (data->sarea);
398 predef_cleanup (ImplVtable *vtable)
400 PredefVtable *vt = (PredefVtable*)vtable;
401 /* ExternalSArea *data; */
404 if (!pid_to_shared_area) {
408 unref_pid_unlocked (vt->pid);
413 mono_determine_physical_ram_size (void)
415 #if defined (TARGET_WIN32)
416 MEMORYSTATUSEX memstat;
418 memstat.dwLength = sizeof (memstat);
419 GlobalMemoryStatusEx (&memstat);
420 return (guint64)memstat.ullTotalPhys;
421 #elif defined (__NetBSD__) || defined (__APPLE__)
435 size_t size_sys = sizeof (value);
437 sysctl (mib, 2, &value, &size_sys, NULL, 0);
441 return (guint64)value;
442 #elif defined (HAVE_SYSCONF)
443 guint64 page_size = 0, num_pages = 0;
445 /* sysconf works on most *NIX operating systems, if your system doesn't have it or if it
446 * reports invalid values, please add your OS specific code below. */
448 page_size = (guint64)sysconf (_SC_PAGESIZE);
451 #ifdef _SC_PHYS_PAGES
452 num_pages = (guint64)sysconf (_SC_PHYS_PAGES);
455 if (!page_size || !num_pages) {
456 g_warning ("Your operating system's sysconf (3) function doesn't correctly report physical memory size!");
460 return page_size * num_pages;
467 mono_determine_physical_ram_available_size (void)
469 #if defined (TARGET_WIN32)
470 MEMORYSTATUSEX memstat;
472 memstat.dwLength = sizeof (memstat);
473 GlobalMemoryStatusEx (&memstat);
474 return (guint64)memstat.ullAvailPhys;
476 #elif defined (__NetBSD__)
477 struct vmtotal vm_total;
485 len = sizeof (vm_total);
486 sysctl (mib, 2, &vm_total, &len, NULL, 0);
489 mib[1] = HW_PAGESIZE;
491 len = sizeof (page_size);
492 sysctl (mib, 2, &page_size, &len, NULL, 0);
494 return ((guint64) vm_total.t_free * page_size) / 1024;
495 #elif defined (__APPLE__)
496 mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
497 mach_port_t host = mach_host_self();
499 vm_statistics_data_t vmstat;
502 ret = host_statistics(host, HOST_VM_INFO, (host_info_t)&vmstat, &count);
503 } while (ret == KERN_ABORTED);
505 if (ret != KERN_SUCCESS) {
506 g_warning ("Mono was unable to retrieve memory usage!");
510 host_page_size(host, &page_size);
511 return (guint64) vmstat.free_count * page_size;
513 #elif defined (HAVE_SYSCONF)
514 guint64 page_size = 0, num_pages = 0;
516 /* sysconf works on most *NIX operating systems, if your system doesn't have it or if it
517 * reports invalid values, please add your OS specific code below. */
519 page_size = (guint64)sysconf (_SC_PAGESIZE);
522 #ifdef _SC_AVPHYS_PAGES
523 num_pages = (guint64)sysconf (_SC_AVPHYS_PAGES);
526 if (!page_size || !num_pages) {
527 g_warning ("Your operating system's sysconf (3) function doesn't correctly report physical memory size!");
531 return page_size * num_pages;
538 mono_perfcounters_init (void)
540 int d_offset = G_STRUCT_OFFSET (MonoSharedArea, data);
544 mono_os_mutex_init_recursive (&perfctr_mutex);
546 shared_area = (MonoSharedArea *)mono_shared_area ();
547 shared_area->counters_start = G_STRUCT_OFFSET (MonoSharedArea, counters);
548 shared_area->counters_size = sizeof (MonoPerfCounters);
549 shared_area->data_start = d_offset;
550 shared_area->size = 4096;
551 mono_perfcounters = &shared_area->counters;
555 perfctr_type_compress (int type)
558 for (i = 0; i < G_N_ELEMENTS (simple_type_to_type); ++i) {
559 if (simple_type_to_type [i] == type)
562 /* NumberOfItems32 */
567 shared_data_reserve_room (int size, int ftype)
569 SharedHeader* header;
570 unsigned char *p = (unsigned char *)shared_area + shared_area->data_start;
571 unsigned char *end = (unsigned char *)shared_area + shared_area->size;
576 unsigned short *next;
577 if (*p == FTYPE_END) {
578 if (size < (end - p))
584 next = (unsigned short*)(p + 2);
585 if (*p == FTYPE_DELETED) {
586 /* we reuse only if it's the same size */
596 header = (SharedHeader*)p;
597 header->ftype = ftype;
598 header->extra = 0; /* data_offset could overflow here, so we leave this field unused */
604 typedef gboolean (*SharedFunc) (SharedHeader *header, void *data);
607 foreach_shared_item_in_area (unsigned char *p, unsigned char *end, SharedFunc func, void *data)
610 unsigned short *next;
613 next = (unsigned short*)(p + 2);
614 if (!func ((SharedHeader*)p, data))
623 foreach_shared_item (SharedFunc func, void *data)
625 unsigned char *p = (unsigned char *)shared_area + shared_area->data_start;
626 unsigned char *end = (unsigned char *)shared_area + shared_area->size;
628 foreach_shared_item_in_area (p, end, func, data);
632 mono_string_compare_ascii (MonoString *str, const char *ascii_str)
634 /* FIXME: make this case insensitive */
635 guint16 *strc = mono_string_chars (str);
636 while (*strc == *ascii_str++) {
641 return *strc - *(const unsigned char *)(ascii_str - 1);
650 category_search (SharedHeader *header, void *data)
652 CatSearch *search = (CatSearch *)data;
653 if (header->ftype == FTYPE_CATEGORY) {
654 SharedCategory *cat = (SharedCategory*)header;
655 if (mono_string_compare_ascii (search->name, cat->name) == 0) {
663 static SharedCategory*
664 find_custom_category (MonoString *name)
669 foreach_shared_item (category_search, &search);
674 category_collect (SharedHeader *header, void *data)
676 GSList **list = (GSList **)data;
677 if (header->ftype == FTYPE_CATEGORY) {
678 *list = g_slist_prepend (*list, header);
684 get_custom_categories (void) {
686 foreach_shared_item (category_collect, &list);
691 custom_category_counters (SharedCategory* cat)
693 char *p = cat->name + strlen (cat->name) + 1;
694 p += strlen (p) + 1; /* skip category help */
698 static SharedCounter*
699 find_custom_counter (SharedCategory* cat, MonoString *name)
702 char *p = custom_category_counters (cat);
703 for (i = 0; i < cat->num_counters; ++i) {
704 SharedCounter *counter = (SharedCounter*)p;
705 if (mono_string_compare_ascii (name, counter->name) == 0)
707 p += 2; /* skip counter type */
708 p += strlen (p) + 1; /* skip counter name */
709 p += strlen (p) + 1; /* skip counter help */
715 unsigned int cat_offset;
718 SharedInstance* result;
723 instance_search (SharedHeader *header, void *data)
725 InstanceSearch *search = (InstanceSearch *)data;
726 if (header->ftype == FTYPE_INSTANCE) {
727 SharedInstance *ins = (SharedInstance*)header;
728 if (search->cat_offset == ins->category_offset) {
730 if (strcmp (search->name, ins->instance_name) == 0) {
731 search->result = ins;
735 search->list = g_slist_prepend (search->list, ins);
742 static SharedInstance*
743 find_custom_instance (SharedCategory* cat, char *name)
745 InstanceSearch search;
746 search.cat_offset = (char*)cat - (char*)shared_area;
750 search.result = NULL;
751 foreach_shared_item (instance_search, &search);
752 return search.result;
756 get_custom_instances_list (SharedCategory* cat)
758 InstanceSearch search;
759 search.cat_offset = (char*)cat - (char*)shared_area;
763 search.result = NULL;
764 foreach_shared_item (instance_search, &search);
769 custom_category_help (SharedCategory* cat)
771 return cat->name + strlen (cat->name) + 1;
774 static const CounterDesc*
775 get_counter_in_category (const CategoryDesc *desc, MonoString *counter)
777 const CounterDesc *cdesc = &predef_counters [desc->first_counter];
778 const CounterDesc *end = &predef_counters [desc [1].first_counter];
779 for (; cdesc < end; ++cdesc) {
780 if (mono_string_compare_ascii (counter, cdesc->name) == 0)
786 /* fill the info in sample (except the raw value) */
788 fill_sample (MonoCounterSample *sample)
790 sample->timeStamp = mono_100ns_ticks ();
791 sample->timeStamp100nSec = sample->timeStamp;
792 sample->counterTimeStamp = sample->timeStamp;
793 sample->counterFrequency = 10000000;
794 sample->systemFrequency = 10000000;
795 // the real basevalue needs to be get from a different counter...
796 sample->baseValue = 0;
800 id_from_string (const gchar *id_str, gboolean is_process)
803 if (strcmp("", id_str) != 0) {
805 id = strtol (id_str, &end, 0);
806 if (end == id_str && !is_process)
813 get_cpu_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
815 MonoProcessError error;
816 int id = GPOINTER_TO_INT (vtable->arg);
820 fill_sample (sample);
821 sample->baseValue = 1;
823 sample->counterType = predef_counters [predef_categories [CATEGORY_CPU].first_counter + id].type;
825 case COUNTER_CPU_USER_TIME:
826 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_USER_TIME, &error);
828 case COUNTER_CPU_PRIV_TIME:
829 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_PRIV_TIME, &error);
831 case COUNTER_CPU_INTR_TIME:
832 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_INTR_TIME, &error);
834 case COUNTER_CPU_DCP_TIME:
835 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_DCP_TIME, &error);
837 case COUNTER_CPU_PROC_TIME:
838 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_IDLE_TIME, &error);
845 cpu_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
847 int id = id_from_string (instance, FALSE) << 5;
848 const CounterDesc *cdesc;
850 /* increase the shift above and the mask also in the implementation functions */
851 //g_assert (32 > desc [1].first_counter - desc->first_counter);
852 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_CPU], counter))) {
854 return create_vtable (GINT_TO_POINTER (id | cdesc->id), get_cpu_counter, NULL);
860 get_network_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
862 MonoNetworkError error = MONO_NETWORK_ERROR_OTHER;
863 NetworkVtableArg *narg = (NetworkVtableArg*) vtable->arg;
865 fill_sample (sample);
868 sample->counterType = predef_counters [predef_categories [CATEGORY_NETWORK].first_counter + narg->id].type;
870 case COUNTER_NETWORK_BYTESRECSEC:
871 sample->rawValue = mono_network_get_data (narg->name, MONO_NETWORK_BYTESREC, &error);
873 case COUNTER_NETWORK_BYTESSENTSEC:
874 sample->rawValue = mono_network_get_data (narg->name, MONO_NETWORK_BYTESSENT, &error);
876 case COUNTER_NETWORK_BYTESTOTALSEC:
877 sample->rawValue = mono_network_get_data (narg->name, MONO_NETWORK_BYTESTOTAL, &error);
881 if (error == MONO_NETWORK_ERROR_NONE)
888 network_cleanup (ImplVtable *vtable)
890 NetworkVtableArg *narg;
895 narg = (NetworkVtableArg *)vtable->arg;
906 network_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
908 const CounterDesc *cdesc;
909 NetworkVtableArg *narg;
914 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_NETWORK], counter))) {
915 instance_name = g_strdup (instance);
916 narg = g_new0 (NetworkVtableArg, 1);
917 narg->id = cdesc->id;
918 narg->name = instance_name;
920 vtable = create_vtable (narg, get_network_counter, NULL);
921 vtable->cleanup = network_cleanup;
928 get_process_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
930 int id = GPOINTER_TO_INT (vtable->arg);
936 fill_sample (sample);
937 sample->baseValue = 1;
939 sample->counterType = predef_counters [predef_categories [CATEGORY_PROC].first_counter + id].type;
941 case COUNTER_PROC_USER_TIME:
942 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_USER_TIME);
944 case COUNTER_PROC_PRIV_TIME:
945 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_SYSTEM_TIME);
947 case COUNTER_PROC_PROC_TIME:
948 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_TOTAL_TIME);
950 case COUNTER_PROC_THREADS:
951 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_NUM_THREADS);
953 case COUNTER_PROC_VBYTES:
954 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_VIRTUAL_BYTES);
956 case COUNTER_PROC_WSET:
957 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_WORKING_SET);
959 case COUNTER_PROC_PBYTES:
960 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_PRIVATE_BYTES);
967 process_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
969 int id = id_from_string (instance, TRUE) << 5;
970 const CounterDesc *cdesc;
972 /* increase the shift above and the mask also in the implementation functions */
973 //g_assert (32 > desc [1].first_counter - desc->first_counter);
974 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_PROC], counter))) {
976 return create_vtable (GINT_TO_POINTER (id | cdesc->id), get_process_counter, NULL);
982 mono_mem_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
984 int id = GPOINTER_TO_INT (vtable->arg);
986 fill_sample (sample);
987 sample->baseValue = 1;
989 sample->counterType = predef_counters [predef_categories [CATEGORY_MONO_MEM].first_counter + id].type;
991 case COUNTER_MEM_NUM_OBJECTS:
992 sample->rawValue = 0;
994 case COUNTER_MEM_PHYS_TOTAL:
995 sample->rawValue = mono_determine_physical_ram_size ();;
997 case COUNTER_MEM_PHYS_AVAILABLE:
998 sample->rawValue = mono_determine_physical_ram_available_size ();;
1005 mono_mem_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
1007 const CounterDesc *cdesc;
1009 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_MONO_MEM], counter))) {
1010 *type = cdesc->type;
1011 return create_vtable (GINT_TO_POINTER ((gint) cdesc->id), mono_mem_counter, NULL);
1017 predef_readonly_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
1019 PredefVtable *vt = (PredefVtable *)vtable;
1020 const CounterDesc *desc;
1021 int cat_id = GPOINTER_TO_INT (vtable->arg);
1022 int id = cat_id >> 16;
1025 fill_sample (sample);
1026 sample->baseValue = 1;
1028 desc = &predef_counters [predef_categories [cat_id].first_counter + id];
1029 sample->counterType = desc->type;
1030 /* FIXME: check that the offset fits inside imported counters */
1031 /*g_print ("loading %s at %d\n", desc->name, desc->offset);*/
1032 sample->rawValue = *(guint32*)((char*)vt->counters + desc->offset);
1037 predef_vtable (void *arg, const gchar *pids)
1039 MonoSharedArea *area;
1040 PredefVtable *vtable;
1044 area = load_sarea_for_pid (pid);
1048 vtable = g_new (PredefVtable, 1);
1049 vtable->vtable.arg = arg;
1050 vtable->vtable.sample = predef_readonly_counter;
1051 vtable->vtable.cleanup = predef_cleanup;
1052 vtable->counters = (MonoPerfCounters*)((char*)area + area->counters_start);
1055 return (ImplVtable*)vtable;
1058 /* consider storing the pointer directly in vtable->arg, so the runtime overhead is lower:
1059 * this needs some way to set sample->counterType as well, though.
1062 predef_writable_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
1064 int cat_id = GPOINTER_TO_INT (vtable->arg);
1065 int id = cat_id >> 16;
1068 fill_sample (sample);
1069 sample->baseValue = 1;
1071 sample->counterType = predef_counters [predef_categories [cat_id].first_counter + id].type;
1075 case COUNTER_EXC_THROWN:
1076 sample->rawValue = mono_perfcounters->exceptions_thrown;
1080 case CATEGORY_ASPNET:
1082 case COUNTER_ASPNET_REQ_Q:
1083 sample->rawValue = mono_perfcounters->aspnet_requests_queued;
1085 case COUNTER_ASPNET_REQ_TOTAL:
1086 sample->rawValue = mono_perfcounters->aspnet_requests;
1090 case CATEGORY_THREADPOOL:
1092 case COUNTER_THREADPOOL_WORKITEMS:
1093 sample->rawValue = mono_perfcounters->threadpool_workitems;
1095 case COUNTER_THREADPOOL_IOWORKITEMS:
1096 sample->rawValue = mono_perfcounters->threadpool_ioworkitems;
1098 case COUNTER_THREADPOOL_THREADS:
1099 sample->rawValue = mono_perfcounters->threadpool_threads;
1101 case COUNTER_THREADPOOL_IOTHREADS:
1102 sample->rawValue = mono_perfcounters->threadpool_iothreads;
1108 case COUNTER_JIT_BYTES:
1109 sample->rawValue = mono_perfcounters->jit_bytes;
1111 case COUNTER_JIT_METHODS:
1112 sample->rawValue = mono_perfcounters->jit_methods;
1114 case COUNTER_JIT_TIME:
1115 sample->rawValue = mono_perfcounters->jit_time;
1117 case COUNTER_JIT_BYTES_PSEC:
1118 sample->rawValue = mono_perfcounters->jit_bytes;
1120 case COUNTER_JIT_FAILURES:
1121 sample->rawValue = mono_perfcounters->jit_failures;
1130 predef_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
1132 guint32 *volatile ptr = NULL;
1133 gint64 *volatile ptr64 = NULL;
1134 int cat_id = GPOINTER_TO_INT (vtable->arg);
1135 int id = cat_id >> 16;
1138 case CATEGORY_ASPNET:
1140 case COUNTER_ASPNET_REQ_Q: ptr = &mono_perfcounters->aspnet_requests_queued; break;
1141 case COUNTER_ASPNET_REQ_TOTAL: ptr = &mono_perfcounters->aspnet_requests; break;
1144 case CATEGORY_THREADPOOL:
1146 case COUNTER_THREADPOOL_WORKITEMS: ptr64 = (gint64 *) &mono_perfcounters->threadpool_workitems; break;
1147 case COUNTER_THREADPOOL_IOWORKITEMS: ptr64 = (gint64 *) &mono_perfcounters->threadpool_ioworkitems; break;
1148 case COUNTER_THREADPOOL_THREADS: ptr = &mono_perfcounters->threadpool_threads; break;
1149 case COUNTER_THREADPOOL_IOTHREADS: ptr = &mono_perfcounters->threadpool_iothreads; break;
1156 return InterlockedIncrement ((gint32 *) ptr); /* FIXME: sign */
1158 return InterlockedDecrement ((gint32 *) ptr); /* FIXME: sign */
1163 /* this can be non-atomic */
1168 /* FIXME: we need to do this atomically */
1169 /* No InterlockedIncrement64() yet */
1172 return InterlockedIncrement64 (ptr);
1174 return InterlockedDecrement64 (ptr);
1180 /* this can be non-atomic */
1188 predef_writable_get_impl (int cat, MonoString* counter, const gchar *instance, int *type, MonoBoolean *custom)
1190 const CounterDesc *cdesc;
1192 if ((cdesc = get_counter_in_category (&predef_categories [cat], counter))) {
1193 *type = cdesc->type;
1194 if (instance == NULL || strcmp (instance, "") == 0)
1195 return create_vtable (GINT_TO_POINTER ((cdesc->id << 16) | cat), predef_writable_counter, predef_writable_update);
1197 return predef_vtable (GINT_TO_POINTER ((cdesc->id << 16) | cat), instance);
1203 custom_writable_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
1205 CustomVTable *counter_data = (CustomVTable *)vtable;
1207 fill_sample (sample);
1208 sample->baseValue = 1;
1210 sample->counterType = simple_type_to_type [counter_data->counter_desc->type];
1212 sample->rawValue = 0;
1214 sample->rawValue = *(guint64*)vtable->arg;
1219 custom_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
1221 /* FIXME: check writability */
1222 guint64 *ptr = (guint64 *)vtable->arg;
1225 /* FIXME: we need to do this atomically */
1229 /* this can be non-atomic */
1236 static SharedInstance*
1237 custom_get_instance (SharedCategory *cat, SharedCounter *scounter, char* name)
1239 SharedInstance* inst;
1242 inst = find_custom_instance (cat, name);
1245 size = sizeof (SharedInstance) + strlen (name);
1248 size += (sizeof (guint64) * cat->num_counters);
1250 inst = (SharedInstance*) shared_data_reserve_room (size, FTYPE_INSTANCE);
1256 inst->category_offset = (char*)cat - (char*)shared_area;
1257 cat->num_instances++;
1258 /* now copy the variable data */
1259 p = inst->instance_name;
1261 p += strlen (name) + 1;
1268 custom_vtable (SharedCounter *scounter, SharedInstance* inst, char *data)
1270 CustomVTable* vtable;
1271 vtable = g_new0 (CustomVTable, 1);
1272 vtable->vtable.arg = data;
1273 vtable->vtable.sample = custom_writable_counter;
1274 vtable->vtable.update = custom_writable_update;
1275 vtable->instance_desc = inst;
1276 vtable->counter_desc = scounter;
1278 return (ImplVtable*)vtable;
1282 custom_get_value_address (SharedCounter *scounter, SharedInstance* sinst)
1284 int offset = sizeof (SharedInstance) + strlen (sinst->instance_name);
1287 offset += scounter->seq_num * sizeof (guint64);
1288 return (char*)sinst + offset;
1292 custom_get_impl (SharedCategory *cat, MonoString *counter, MonoString* instance, int *type, MonoError *error)
1294 SharedCounter *scounter;
1295 SharedInstance* inst;
1298 mono_error_init (error);
1299 scounter = find_custom_counter (cat, counter);
1302 name = mono_string_to_utf8_checked (counter, error);
1303 return_val_if_nok (error, NULL);
1304 *type = simple_type_to_type [scounter->type];
1305 inst = custom_get_instance (cat, scounter, name);
1309 return custom_vtable (scounter, inst, (char *)custom_get_value_address (scounter, inst));
1312 static const CategoryDesc*
1313 find_category (MonoString *category)
1316 for (i = 0; i < NUM_CATEGORIES; ++i) {
1317 if (mono_string_compare_ascii (category, predef_categories [i].name) == 0)
1318 return &predef_categories [i];
1324 mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString* instance,
1325 MonoString* machine, int *type, MonoBoolean *custom)
1328 const CategoryDesc *cdesc;
1329 void *result = NULL;
1330 /* no support for counters on other machines */
1331 if (mono_string_compare_ascii (machine, "."))
1333 cdesc = find_category (category);
1335 SharedCategory *scat = find_custom_category (category);
1339 result = custom_get_impl (scat, counter, instance, type, &error);
1340 if (mono_error_set_pending_exception (&error))
1344 gchar *c_instance = mono_string_to_utf8_checked (instance, &error);
1345 if (mono_error_set_pending_exception (&error))
1347 switch (cdesc->id) {
1349 result = cpu_get_impl (counter, c_instance, type, custom);
1352 result = process_get_impl (counter, c_instance, type, custom);
1354 case CATEGORY_MONO_MEM:
1355 result = mono_mem_get_impl (counter, c_instance, type, custom);
1357 case CATEGORY_NETWORK:
1358 result = network_get_impl (counter, c_instance, type, custom);
1363 case CATEGORY_REMOTING:
1364 case CATEGORY_LOADING:
1365 case CATEGORY_THREAD:
1366 case CATEGORY_INTEROP:
1367 case CATEGORY_SECURITY:
1368 case CATEGORY_ASPNET:
1369 case CATEGORY_THREADPOOL:
1370 result = predef_writable_get_impl (cdesc->id, counter, c_instance, type, custom);
1373 g_free (c_instance);
1378 mono_perfcounter_get_sample (void *impl, MonoBoolean only_value, MonoCounterSample *sample)
1380 ImplVtable *vtable = (ImplVtable *)impl;
1381 if (vtable && vtable->sample)
1382 return vtable->sample (vtable, only_value, sample);
1387 mono_perfcounter_update_value (void *impl, MonoBoolean do_incr, gint64 value)
1389 ImplVtable *vtable = (ImplVtable *)impl;
1390 if (vtable && vtable->update)
1391 return vtable->update (vtable, do_incr, value);
1396 mono_perfcounter_free_data (void *impl)
1398 ImplVtable *vtable = (ImplVtable *)impl;
1399 if (vtable && vtable->cleanup)
1400 vtable->cleanup (vtable);
1404 /* Category icalls */
1406 mono_perfcounter_category_del (MonoString *name)
1408 const CategoryDesc *cdesc;
1409 SharedCategory *cat;
1410 cdesc = find_category (name);
1411 /* can't delete a predefined category */
1415 cat = find_custom_category (name);
1416 /* FIXME: check the semantics, if deleting a category means also deleting the instances */
1417 if (!cat || cat->num_instances) {
1421 cat->header.ftype = FTYPE_DELETED;
1427 mono_perfcounter_category_help (MonoString *category, MonoString *machine)
1429 const CategoryDesc *cdesc;
1430 /* no support for counters on other machines */
1431 if (mono_string_compare_ascii (machine, "."))
1433 cdesc = find_category (category);
1435 SharedCategory *scat = find_custom_category (category);
1438 return mono_string_new (mono_domain_get (), custom_category_help (scat));
1440 return mono_string_new (mono_domain_get (), cdesc->help);
1444 * Check if the category named @category exists on @machine. If @counter is not NULL, return
1445 * TRUE only if a counter with that name exists in the category.
1448 mono_perfcounter_category_exists (MonoString *counter, MonoString *category, MonoString *machine)
1450 const CategoryDesc *cdesc;
1451 /* no support for counters on other machines */
1452 if (mono_string_compare_ascii (machine, "."))
1454 cdesc = find_category (category);
1456 SharedCategory *scat = find_custom_category (category);
1459 /* counter is allowed to be null */
1462 /* search through the custom category */
1463 return find_custom_counter (scat, counter) != NULL;
1465 /* counter is allowed to be null */
1468 if (get_counter_in_category (cdesc, counter))
1473 /* C map of the type with the same name */
1479 } CounterCreationData;
1482 * Since we'll keep a copy of the category per-process, we should also make sure
1483 * categories with the same name are compatible.
1486 mono_perfcounter_create (MonoString *category, MonoString *help, int type, MonoArray *items)
1491 int num_counters = mono_array_length (items);
1492 int counters_data_size;
1495 char **counter_info = NULL;
1497 SharedCategory *cat;
1499 /* FIXME: ensure there isn't a category created already */
1500 name = mono_string_to_utf8_checked (category, &error);
1501 if (!mono_error_ok (&error))
1503 chelp = mono_string_to_utf8_checked (help, &error);
1504 if (!mono_error_ok (&error))
1506 counter_info = g_new0 (char*, num_counters * 2);
1507 /* calculate the size we need structure size + name/help + 2 0 string terminators */
1508 size = G_STRUCT_OFFSET (SharedCategory, name) + strlen (name) + strlen (chelp) + 2;
1509 for (i = 0; i < num_counters; ++i) {
1510 CounterCreationData *data = mono_array_get (items, CounterCreationData*, i);
1511 counter_info [i * 2] = mono_string_to_utf8_checked (data->name, &error);
1512 if (!mono_error_ok (&error))
1514 counter_info [i * 2 + 1] = mono_string_to_utf8_checked (data->help, &error);
1515 if (!mono_error_ok (&error))
1517 size += sizeof (SharedCounter) + 1; /* 1 is for the help 0 terminator */
1519 for (i = 0; i < num_counters * 2; ++i) {
1520 if (!counter_info [i])
1522 size += strlen (counter_info [i]) + 1;
1526 counters_data_size = num_counters * 8; /* optimize for size later */
1530 cat = (SharedCategory*) shared_data_reserve_room (size, FTYPE_CATEGORY);
1535 cat->num_counters = num_counters;
1536 cat->counters_data_size = counters_data_size;
1537 /* now copy the vaiable data */
1540 p += strlen (name) + 1;
1542 p += strlen (chelp) + 1;
1543 for (i = 0; i < num_counters; ++i) {
1544 CounterCreationData *data = mono_array_get (items, CounterCreationData*, i);
1545 /* emit the SharedCounter structures */
1546 *p++ = perfctr_type_compress (data->type);
1548 strcpy (p, counter_info [i * 2]);
1549 p += strlen (counter_info [i * 2]) + 1;
1550 strcpy (p, counter_info [i * 2 + 1]);
1551 p += strlen (counter_info [i * 2 + 1]) + 1;
1558 for (i = 0; i < num_counters * 2; ++i) {
1559 g_free (counter_info [i]);
1561 g_free (counter_info);
1565 mono_error_cleanup (&error);
1570 mono_perfcounter_instance_exists (MonoString *instance, MonoString *category, MonoString *machine)
1573 const CategoryDesc *cdesc;
1574 SharedInstance *sinst;
1576 /* no support for counters on other machines */
1577 /*FIXME: machine appears to be wrong
1578 if (mono_string_compare_ascii (machine, "."))
1580 cdesc = find_category (category);
1582 SharedCategory *scat;
1583 scat = find_custom_category (category);
1586 name = mono_string_to_utf8_checked (instance, &error);
1587 if (mono_error_set_pending_exception (&error))
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 ();