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 (const gchar *id_str, gboolean is_process)
808 if (strcmp("", id_str) != 0) {
810 id = strtol (id_str, &end, 0);
811 if (end == id_str && !is_process)
818 get_cpu_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
820 MonoProcessError error;
821 int id = GPOINTER_TO_INT (vtable->arg);
825 fill_sample (sample);
826 sample->baseValue = 1;
828 sample->counterType = predef_counters [predef_categories [CATEGORY_CPU].first_counter + id].type;
830 case COUNTER_CPU_USER_TIME:
831 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_USER_TIME, &error);
833 case COUNTER_CPU_PRIV_TIME:
834 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_PRIV_TIME, &error);
836 case COUNTER_CPU_INTR_TIME:
837 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_INTR_TIME, &error);
839 case COUNTER_CPU_DCP_TIME:
840 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_DCP_TIME, &error);
842 case COUNTER_CPU_PROC_TIME:
843 sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_IDLE_TIME, &error);
850 cpu_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
852 int id = id_from_string (instance, FALSE) << 5;
853 const CounterDesc *cdesc;
855 /* increase the shift above and the mask also in the implementation functions */
856 //g_assert (32 > desc [1].first_counter - desc->first_counter);
857 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_CPU], counter))) {
859 return create_vtable (GINT_TO_POINTER (id | cdesc->id), get_cpu_counter, NULL);
865 get_network_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
867 MonoNetworkError error = MONO_NETWORK_ERROR_OTHER;
868 NetworkVtableArg *narg = (NetworkVtableArg*) vtable->arg;
870 fill_sample (sample);
873 sample->counterType = predef_counters [predef_categories [CATEGORY_NETWORK].first_counter + narg->id].type;
875 case COUNTER_NETWORK_BYTESRECSEC:
876 sample->rawValue = mono_network_get_data (narg->name, MONO_NETWORK_BYTESREC, &error);
878 case COUNTER_NETWORK_BYTESSENTSEC:
879 sample->rawValue = mono_network_get_data (narg->name, MONO_NETWORK_BYTESSENT, &error);
881 case COUNTER_NETWORK_BYTESTOTALSEC:
882 sample->rawValue = mono_network_get_data (narg->name, MONO_NETWORK_BYTESTOTAL, &error);
886 if (error == MONO_NETWORK_ERROR_NONE)
893 network_cleanup (ImplVtable *vtable)
895 NetworkVtableArg *narg;
900 narg = (NetworkVtableArg *)vtable->arg;
911 network_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
913 const CounterDesc *cdesc;
914 NetworkVtableArg *narg;
919 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_NETWORK], counter))) {
920 instance_name = g_strdup (instance);
921 narg = g_new0 (NetworkVtableArg, 1);
922 narg->id = cdesc->id;
923 narg->name = instance_name;
925 vtable = create_vtable (narg, get_network_counter, NULL);
926 vtable->cleanup = network_cleanup;
933 get_process_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
935 int id = GPOINTER_TO_INT (vtable->arg);
941 fill_sample (sample);
942 sample->baseValue = 1;
944 sample->counterType = predef_counters [predef_categories [CATEGORY_PROC].first_counter + id].type;
946 case COUNTER_PROC_USER_TIME:
947 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_USER_TIME);
949 case COUNTER_PROC_PRIV_TIME:
950 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_SYSTEM_TIME);
952 case COUNTER_PROC_PROC_TIME:
953 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_TOTAL_TIME);
955 case COUNTER_PROC_THREADS:
956 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_NUM_THREADS);
958 case COUNTER_PROC_VBYTES:
959 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_VIRTUAL_BYTES);
961 case COUNTER_PROC_WSET:
962 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_WORKING_SET);
964 case COUNTER_PROC_PBYTES:
965 sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_PRIVATE_BYTES);
972 process_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
974 int id = id_from_string (instance, TRUE) << 5;
975 const CounterDesc *cdesc;
977 /* increase the shift above and the mask also in the implementation functions */
978 //g_assert (32 > desc [1].first_counter - desc->first_counter);
979 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_PROC], counter))) {
981 return create_vtable (GINT_TO_POINTER (id | cdesc->id), get_process_counter, NULL);
987 mono_mem_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
989 int id = GPOINTER_TO_INT (vtable->arg);
991 fill_sample (sample);
992 sample->baseValue = 1;
994 sample->counterType = predef_counters [predef_categories [CATEGORY_MONO_MEM].first_counter + id].type;
996 case COUNTER_MEM_NUM_OBJECTS:
997 sample->rawValue = 0;
999 case COUNTER_MEM_PHYS_TOTAL:
1000 sample->rawValue = mono_determine_physical_ram_size ();;
1002 case COUNTER_MEM_PHYS_AVAILABLE:
1003 sample->rawValue = mono_determine_physical_ram_available_size ();;
1010 mono_mem_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
1012 const CounterDesc *cdesc;
1014 if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_MONO_MEM], counter))) {
1015 *type = cdesc->type;
1016 return create_vtable (GINT_TO_POINTER ((gint) cdesc->id), mono_mem_counter, NULL);
1022 predef_readonly_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
1024 PredefVtable *vt = (PredefVtable *)vtable;
1025 const CounterDesc *desc;
1026 int cat_id = GPOINTER_TO_INT (vtable->arg);
1027 int id = cat_id >> 16;
1030 fill_sample (sample);
1031 sample->baseValue = 1;
1033 desc = &predef_counters [predef_categories [cat_id].first_counter + id];
1034 sample->counterType = desc->type;
1035 /* FIXME: check that the offset fits inside imported counters */
1036 /*g_print ("loading %s at %d\n", desc->name, desc->offset);*/
1037 sample->rawValue = *(guint32*)((char*)vt->counters + desc->offset);
1042 predef_vtable (void *arg, const gchar *pids)
1044 MonoSharedArea *area;
1045 PredefVtable *vtable;
1049 area = load_sarea_for_pid (pid);
1053 vtable = g_new (PredefVtable, 1);
1054 vtable->vtable.arg = arg;
1055 vtable->vtable.sample = predef_readonly_counter;
1056 vtable->vtable.cleanup = predef_cleanup;
1057 vtable->counters = (MonoPerfCounters*)((char*)area + area->counters_start);
1060 return (ImplVtable*)vtable;
1063 /* consider storing the pointer directly in vtable->arg, so the runtime overhead is lower:
1064 * this needs some way to set sample->counterType as well, though.
1067 predef_writable_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
1069 int cat_id = GPOINTER_TO_INT (vtable->arg);
1070 int id = cat_id >> 16;
1073 fill_sample (sample);
1074 sample->baseValue = 1;
1076 sample->counterType = predef_counters [predef_categories [cat_id].first_counter + id].type;
1080 case COUNTER_EXC_THROWN:
1081 sample->rawValue = mono_perfcounters->exceptions_thrown;
1085 case CATEGORY_ASPNET:
1087 case COUNTER_ASPNET_REQ_Q:
1088 sample->rawValue = mono_perfcounters->aspnet_requests_queued;
1090 case COUNTER_ASPNET_REQ_TOTAL:
1091 sample->rawValue = mono_perfcounters->aspnet_requests;
1095 case CATEGORY_THREADPOOL:
1097 case COUNTER_THREADPOOL_WORKITEMS:
1098 sample->rawValue = mono_perfcounters->threadpool_workitems;
1100 case COUNTER_THREADPOOL_IOWORKITEMS:
1101 sample->rawValue = mono_perfcounters->threadpool_ioworkitems;
1103 case COUNTER_THREADPOOL_THREADS:
1104 sample->rawValue = mono_perfcounters->threadpool_threads;
1106 case COUNTER_THREADPOOL_IOTHREADS:
1107 sample->rawValue = mono_perfcounters->threadpool_iothreads;
1113 case COUNTER_JIT_BYTES:
1114 sample->rawValue = mono_perfcounters->jit_bytes;
1116 case COUNTER_JIT_METHODS:
1117 sample->rawValue = mono_perfcounters->jit_methods;
1119 case COUNTER_JIT_TIME:
1120 sample->rawValue = mono_perfcounters->jit_time;
1122 case COUNTER_JIT_BYTES_PSEC:
1123 sample->rawValue = mono_perfcounters->jit_bytes;
1125 case COUNTER_JIT_FAILURES:
1126 sample->rawValue = mono_perfcounters->jit_failures;
1135 predef_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
1137 guint32 *volatile ptr = NULL;
1138 gint64 *volatile ptr64 = NULL;
1139 int cat_id = GPOINTER_TO_INT (vtable->arg);
1140 int id = cat_id >> 16;
1143 case CATEGORY_ASPNET:
1145 case COUNTER_ASPNET_REQ_Q: ptr = &mono_perfcounters->aspnet_requests_queued; break;
1146 case COUNTER_ASPNET_REQ_TOTAL: ptr = &mono_perfcounters->aspnet_requests; break;
1149 case CATEGORY_THREADPOOL:
1151 case COUNTER_THREADPOOL_WORKITEMS: ptr64 = (gint64 *) &mono_perfcounters->threadpool_workitems; break;
1152 case COUNTER_THREADPOOL_IOWORKITEMS: ptr64 = (gint64 *) &mono_perfcounters->threadpool_ioworkitems; break;
1153 case COUNTER_THREADPOOL_THREADS: ptr = &mono_perfcounters->threadpool_threads; break;
1154 case COUNTER_THREADPOOL_IOTHREADS: ptr = &mono_perfcounters->threadpool_iothreads; break;
1161 return InterlockedIncrement ((gint32 *) ptr); /* FIXME: sign */
1163 return InterlockedDecrement ((gint32 *) ptr); /* FIXME: sign */
1168 /* this can be non-atomic */
1173 /* FIXME: we need to do this atomically */
1174 /* No InterlockedIncrement64() yet */
1177 return InterlockedIncrement64 (ptr);
1179 return InterlockedDecrement64 (ptr);
1185 /* this can be non-atomic */
1193 predef_writable_get_impl (int cat, MonoString* counter, const gchar *instance, int *type, MonoBoolean *custom)
1195 const CounterDesc *cdesc;
1197 if ((cdesc = get_counter_in_category (&predef_categories [cat], counter))) {
1198 *type = cdesc->type;
1199 if (instance == NULL || strcmp (instance, "") == 0)
1200 return create_vtable (GINT_TO_POINTER ((cdesc->id << 16) | cat), predef_writable_counter, predef_writable_update);
1202 return predef_vtable (GINT_TO_POINTER ((cdesc->id << 16) | cat), instance);
1208 custom_writable_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
1210 CustomVTable *counter_data = (CustomVTable *)vtable;
1212 fill_sample (sample);
1213 sample->baseValue = 1;
1215 sample->counterType = simple_type_to_type [counter_data->counter_desc->type];
1217 sample->rawValue = 0;
1219 sample->rawValue = *(guint64*)vtable->arg;
1224 custom_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
1226 /* FIXME: check writability */
1227 guint64 *ptr = (guint64 *)vtable->arg;
1230 /* FIXME: we need to do this atomically */
1234 /* this can be non-atomic */
1241 static SharedInstance*
1242 custom_get_instance (SharedCategory *cat, SharedCounter *scounter, char* name)
1244 SharedInstance* inst;
1247 inst = find_custom_instance (cat, name);
1250 size = sizeof (SharedInstance) + strlen (name);
1253 size += (sizeof (guint64) * cat->num_counters);
1255 inst = (SharedInstance*) shared_data_reserve_room (size, FTYPE_INSTANCE);
1261 inst->category_offset = (char*)cat - (char*)shared_area;
1262 cat->num_instances++;
1263 /* now copy the variable data */
1264 p = inst->instance_name;
1266 p += strlen (name) + 1;
1273 custom_vtable (SharedCounter *scounter, SharedInstance* inst, char *data)
1275 CustomVTable* vtable;
1276 vtable = g_new0 (CustomVTable, 1);
1277 vtable->vtable.arg = data;
1278 vtable->vtable.sample = custom_writable_counter;
1279 vtable->vtable.update = custom_writable_update;
1280 vtable->instance_desc = inst;
1281 vtable->counter_desc = scounter;
1283 return (ImplVtable*)vtable;
1287 custom_get_value_address (SharedCounter *scounter, SharedInstance* sinst)
1289 int offset = sizeof (SharedInstance) + strlen (sinst->instance_name);
1292 offset += scounter->seq_num * sizeof (guint64);
1293 return (char*)sinst + offset;
1297 custom_get_impl (SharedCategory *cat, MonoString *counter, MonoString* instance, int *type, MonoError *error)
1299 SharedCounter *scounter;
1300 SharedInstance* inst;
1303 mono_error_init (error);
1304 scounter = find_custom_counter (cat, counter);
1307 name = mono_string_to_utf8_checked (counter, error);
1308 return_val_if_nok (error, NULL);
1309 *type = simple_type_to_type [scounter->type];
1310 inst = custom_get_instance (cat, scounter, name);
1314 return custom_vtable (scounter, inst, (char *)custom_get_value_address (scounter, inst));
1317 static const CategoryDesc*
1318 find_category (MonoString *category)
1321 for (i = 0; i < NUM_CATEGORIES; ++i) {
1322 if (mono_string_compare_ascii (category, predef_categories [i].name) == 0)
1323 return &predef_categories [i];
1329 mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString* instance,
1330 MonoString* machine, int *type, MonoBoolean *custom)
1333 const CategoryDesc *cdesc;
1334 void *result = NULL;
1335 /* no support for counters on other machines */
1336 if (mono_string_compare_ascii (machine, "."))
1338 cdesc = find_category (category);
1340 SharedCategory *scat = find_custom_category (category);
1344 result = custom_get_impl (scat, counter, instance, type, &error);
1345 if (mono_error_set_pending_exception (&error))
1349 gchar *c_instance = mono_string_to_utf8_checked (instance, &error);
1350 if (mono_error_set_pending_exception (&error))
1352 switch (cdesc->id) {
1354 result = cpu_get_impl (counter, c_instance, type, custom);
1357 result = process_get_impl (counter, c_instance, type, custom);
1359 case CATEGORY_MONO_MEM:
1360 result = mono_mem_get_impl (counter, c_instance, type, custom);
1362 case CATEGORY_NETWORK:
1363 result = network_get_impl (counter, c_instance, type, custom);
1368 case CATEGORY_REMOTING:
1369 case CATEGORY_LOADING:
1370 case CATEGORY_THREAD:
1371 case CATEGORY_INTEROP:
1372 case CATEGORY_SECURITY:
1373 case CATEGORY_ASPNET:
1374 case CATEGORY_THREADPOOL:
1375 result = predef_writable_get_impl (cdesc->id, counter, c_instance, type, custom);
1378 g_free (c_instance);
1383 mono_perfcounter_get_sample (void *impl, MonoBoolean only_value, MonoCounterSample *sample)
1385 ImplVtable *vtable = (ImplVtable *)impl;
1386 if (vtable && vtable->sample)
1387 return vtable->sample (vtable, only_value, sample);
1392 mono_perfcounter_update_value (void *impl, MonoBoolean do_incr, gint64 value)
1394 ImplVtable *vtable = (ImplVtable *)impl;
1395 if (vtable && vtable->update)
1396 return vtable->update (vtable, do_incr, value);
1401 mono_perfcounter_free_data (void *impl)
1403 ImplVtable *vtable = (ImplVtable *)impl;
1404 if (vtable && vtable->cleanup)
1405 vtable->cleanup (vtable);
1409 /* Category icalls */
1411 mono_perfcounter_category_del (MonoString *name)
1413 const CategoryDesc *cdesc;
1414 SharedCategory *cat;
1415 cdesc = find_category (name);
1416 /* can't delete a predefined category */
1420 cat = find_custom_category (name);
1421 /* FIXME: check the semantics, if deleting a category means also deleting the instances */
1422 if (!cat || cat->num_instances) {
1426 cat->header.ftype = FTYPE_DELETED;
1432 mono_perfcounter_category_help (MonoString *category, MonoString *machine)
1434 const CategoryDesc *cdesc;
1435 /* no support for counters on other machines */
1436 if (mono_string_compare_ascii (machine, "."))
1438 cdesc = find_category (category);
1440 SharedCategory *scat = find_custom_category (category);
1443 return mono_string_new (mono_domain_get (), custom_category_help (scat));
1445 return mono_string_new (mono_domain_get (), cdesc->help);
1449 * Check if the category named @category exists on @machine. If @counter is not NULL, return
1450 * TRUE only if a counter with that name exists in the category.
1453 mono_perfcounter_category_exists (MonoString *counter, MonoString *category, MonoString *machine)
1455 const CategoryDesc *cdesc;
1456 /* no support for counters on other machines */
1457 if (mono_string_compare_ascii (machine, "."))
1459 cdesc = find_category (category);
1461 SharedCategory *scat = find_custom_category (category);
1464 /* counter is allowed to be null */
1467 /* search through the custom category */
1468 return find_custom_counter (scat, counter) != NULL;
1470 /* counter is allowed to be null */
1473 if (get_counter_in_category (cdesc, counter))
1478 /* C map of the type with the same name */
1484 } CounterCreationData;
1487 * Since we'll keep a copy of the category per-process, we should also make sure
1488 * categories with the same name are compatible.
1491 mono_perfcounter_create (MonoString *category, MonoString *help, int type, MonoArray *items)
1496 int num_counters = mono_array_length (items);
1497 int counters_data_size;
1500 char **counter_info = NULL;
1502 SharedCategory *cat;
1504 /* FIXME: ensure there isn't a category created already */
1505 name = mono_string_to_utf8_checked (category, &error);
1506 if (!mono_error_ok (&error))
1508 chelp = mono_string_to_utf8_checked (help, &error);
1509 if (!mono_error_ok (&error))
1511 counter_info = g_new0 (char*, num_counters * 2);
1512 /* calculate the size we need structure size + name/help + 2 0 string terminators */
1513 size = G_STRUCT_OFFSET (SharedCategory, name) + strlen (name) + strlen (chelp) + 2;
1514 for (i = 0; i < num_counters; ++i) {
1515 CounterCreationData *data = mono_array_get (items, CounterCreationData*, i);
1516 counter_info [i * 2] = mono_string_to_utf8_checked (data->name, &error);
1517 if (!mono_error_ok (&error))
1519 counter_info [i * 2 + 1] = mono_string_to_utf8_checked (data->help, &error);
1520 if (!mono_error_ok (&error))
1522 size += sizeof (SharedCounter) + 1; /* 1 is for the help 0 terminator */
1524 for (i = 0; i < num_counters * 2; ++i) {
1525 if (!counter_info [i])
1527 size += strlen (counter_info [i]) + 1;
1531 counters_data_size = num_counters * 8; /* optimize for size later */
1535 cat = (SharedCategory*) shared_data_reserve_room (size, FTYPE_CATEGORY);
1540 cat->num_counters = num_counters;
1541 cat->counters_data_size = counters_data_size;
1542 /* now copy the vaiable data */
1545 p += strlen (name) + 1;
1547 p += strlen (chelp) + 1;
1548 for (i = 0; i < num_counters; ++i) {
1549 CounterCreationData *data = mono_array_get (items, CounterCreationData*, i);
1550 /* emit the SharedCounter structures */
1551 *p++ = perfctr_type_compress (data->type);
1553 strcpy (p, counter_info [i * 2]);
1554 p += strlen (counter_info [i * 2]) + 1;
1555 strcpy (p, counter_info [i * 2 + 1]);
1556 p += strlen (counter_info [i * 2 + 1]) + 1;
1563 for (i = 0; i < num_counters * 2; ++i) {
1564 g_free (counter_info [i]);
1566 g_free (counter_info);
1570 mono_error_cleanup (&error);
1575 mono_perfcounter_instance_exists (MonoString *instance, MonoString *category, MonoString *machine)
1578 const CategoryDesc *cdesc;
1579 SharedInstance *sinst;
1581 /* no support for counters on other machines */
1582 /*FIXME: machine appears to be wrong
1583 if (mono_string_compare_ascii (machine, "."))
1585 cdesc = find_category (category);
1587 SharedCategory *scat;
1588 scat = find_custom_category (category);
1591 name = mono_string_to_utf8_checked (instance, &error);
1592 if (mono_error_set_pending_exception (&error))
1594 sinst = find_custom_instance (scat, name);
1599 /* FIXME: search instance */
1605 mono_perfcounter_category_names (MonoString *machine)
1610 MonoDomain *domain = mono_domain_get ();
1611 GSList *custom_categories, *tmp;
1612 /* no support for counters on other machines */
1613 if (mono_string_compare_ascii (machine, ".")) {
1614 res = mono_array_new_checked (domain, mono_get_string_class (), 0, &error);
1615 mono_error_set_pending_exception (&error);
1619 custom_categories = get_custom_categories ();
1620 res = mono_array_new_checked (domain, mono_get_string_class (), NUM_CATEGORIES + g_slist_length (custom_categories), &error);
1621 if (mono_error_set_pending_exception (&error)) {
1626 for (i = 0; i < NUM_CATEGORIES; ++i) {
1627 const CategoryDesc *cdesc = &predef_categories [i];
1628 mono_array_setref (res, i, mono_string_new (domain, cdesc->name));
1630 for (tmp = custom_categories; tmp; tmp = tmp->next) {
1631 SharedCategory *scat = (SharedCategory *)tmp->data;
1632 mono_array_setref (res, i, mono_string_new (domain, scat->name));
1636 g_slist_free (custom_categories);
1641 mono_perfcounter_counter_names (MonoString *category, MonoString *machine)
1645 SharedCategory *scat;
1646 const CategoryDesc *cdesc;
1648 MonoDomain *domain = mono_domain_get ();
1649 /* no support for counters on other machines */
1650 if (mono_string_compare_ascii (machine, ".")) {
1651 res = mono_array_new_checked (domain, mono_get_string_class (), 0, &error);
1652 mono_error_set_pending_exception (&error);
1655 cdesc = find_category (category);
1657 res = mono_array_new_checked (domain, mono_get_string_class (), cdesc [1].first_counter - cdesc->first_counter, &error);
1658 if (mono_error_set_pending_exception (&error))
1660 for (i = cdesc->first_counter; i < cdesc [1].first_counter; ++i) {
1661 const CounterDesc *desc = &predef_counters [i];
1662 mono_array_setref (res, i - cdesc->first_counter, mono_string_new (domain, desc->name));
1667 scat = find_custom_category (category);
1669 char *p = custom_category_counters (scat);
1671 res = mono_array_new_checked (domain, mono_get_string_class (), scat->num_counters, &error);
1672 if (mono_error_set_pending_exception (&error)) {
1677 for (i = 0; i < scat->num_counters; ++i) {
1678 mono_array_setref (res, i, mono_string_new (domain, p + 1));
1679 p += 2; /* skip counter type */
1680 p += strlen (p) + 1; /* skip counter name */
1681 p += strlen (p) + 1; /* skip counter help */
1687 res = mono_array_new_checked (domain, mono_get_string_class (), 0, &error);
1688 mono_error_set_pending_exception (&error);
1693 get_string_array (void **array, int count, gboolean is_process, MonoError *error)
1696 MonoDomain *domain = mono_domain_get ();
1697 mono_error_init (error);
1698 MonoArray * res = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), count, error);
1699 return_val_if_nok (error, NULL);
1700 for (i = 0; i < count; ++i) {
1704 char *pname = mono_process_get_name (array [i], buf, sizeof (buf));
1705 p = g_strdup_printf ("%d/%s", GPOINTER_TO_INT (array [i]), pname);
1707 sprintf (buf, "%d", GPOINTER_TO_INT (array [i]));
1710 mono_array_setref (res, i, mono_string_new (domain, p));
1718 get_string_array_of_strings (void **array, int count, MonoError *error)
1721 MonoDomain *domain = mono_domain_get ();
1722 mono_error_init (error);
1723 MonoArray * res = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), count, error);
1724 return_val_if_nok (error, NULL);
1725 for (i = 0; i < count; ++i) {
1726 char* p = (char *)array[i];
1727 mono_array_setref (res, i, mono_string_new (domain, p));
1734 get_mono_instances (MonoError *error)
1740 mono_error_init (error);
1744 buf = g_new (void*, count);
1745 res = mono_shared_area_instances (buf, count);
1746 } while (res == count);
1747 array = get_string_array (buf, res, TRUE, error);
1753 get_cpu_instances (MonoError *error)
1758 mono_error_init (error);
1759 count = mono_cpu_count () + 1; /* +1 for "_Total" */
1760 buf = g_new (void*, count);
1761 for (i = 0; i < count; ++i)
1762 buf [i] = GINT_TO_POINTER (i - 1); /* -1 => _Total */
1763 array = get_string_array (buf, count, FALSE, error);
1765 mono_array_setref (array, 0, mono_string_new (mono_domain_get (), "_Total"));
1770 get_processes_instances (MonoError *error)
1774 void **buf = mono_process_list (&count);
1775 mono_error_init (error);
1777 return get_string_array (NULL, 0, FALSE, error);
1778 array = get_string_array (buf, count, TRUE, error);
1784 get_networkinterface_instances (MonoError *error)
1788 mono_error_init (error);
1789 void **buf = mono_networkinterface_list (&count);
1791 return get_string_array_of_strings (NULL, 0, error);
1792 array = get_string_array_of_strings (buf, count, error);
1793 g_strfreev ((char **) buf);
1798 get_custom_instances (MonoString *category, MonoError *error)
1800 SharedCategory *scat;
1801 mono_error_init (error);
1802 scat = find_custom_category (category);
1804 GSList *list = get_custom_instances_list (scat);
1807 MonoArray *array = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), g_slist_length (list), error);
1808 if (!is_ok (error)) {
1809 g_slist_free (list);
1812 for (tmp = list; tmp; tmp = tmp->next) {
1813 SharedInstance *inst = (SharedInstance *)tmp->data;
1814 mono_array_setref (array, i, mono_string_new (mono_domain_get (), inst->instance_name));
1817 g_slist_free (list);
1820 return mono_array_new_checked (mono_domain_get (), mono_get_string_class (), 0, error);
1824 mono_perfcounter_instance_names (MonoString *category, MonoString *machine)
1827 const CategoryDesc* cat;
1828 MonoArray *result = NULL;
1829 if (mono_string_compare_ascii (machine, ".")) {
1830 result = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), 0, &error);
1831 mono_error_set_pending_exception (&error);
1835 cat = find_category (category);
1837 MonoArray *result = get_custom_instances (category, &error);
1838 mono_error_set_pending_exception (&error);
1841 switch (cat->instance_type) {
1843 result = get_mono_instances (&error);
1846 result = get_cpu_instances (&error);
1848 case ProcessInstance:
1849 result = get_processes_instances (&error);
1851 case NetworkInterfaceInstance:
1852 result = get_networkinterface_instances (&error);
1854 case ThreadInstance:
1856 result = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), 0, &error);
1858 mono_error_set_pending_exception (&error);
1863 PerfCounterEnumCallback cb;
1865 } PerfCounterForeachData;
1868 mono_perfcounter_foreach_shared_item (SharedHeader *header, gpointer data)
1874 SharedCategory *cat;
1875 SharedCounter *counter;
1876 SharedInstance *inst;
1877 PerfCounterForeachData *foreach_data = (PerfCounterForeachData *)data;
1879 if (header->ftype == FTYPE_CATEGORY) {
1880 cat = (SharedCategory*)header;
1883 p += strlen (p) + 1; /* skip category name */
1884 p += strlen (p) + 1; /* skip category help */
1886 for (i = 0; i < cat->num_counters; ++i) {
1887 counter = (SharedCounter*) p;
1888 type = (unsigned char)*p++;
1889 /* seq_num = (int)* */ p++;
1891 p += strlen (p) + 1;
1893 p += strlen (p) + 1;
1895 inst = custom_get_instance (cat, counter, name);
1898 addr = custom_get_value_address (counter, inst);
1899 if (!foreach_data->cb (cat->name, name, type, addr ? *(gint64*)addr : 0, foreach_data->data))
1908 mono_perfcounter_foreach (PerfCounterEnumCallback cb, gpointer data)
1910 PerfCounterForeachData foreach_data = { cb, data };
1914 foreach_shared_item (mono_perfcounter_foreach_shared_item, &foreach_data);
1921 mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString* instance, MonoString* machine, int *type, MonoBoolean *custom)
1923 g_assert_not_reached ();
1927 mono_perfcounter_get_sample (void *impl, MonoBoolean only_value, MonoCounterSample *sample)
1929 g_assert_not_reached ();
1933 mono_perfcounter_update_value (void *impl, MonoBoolean do_incr, gint64 value)
1935 g_assert_not_reached ();
1939 mono_perfcounter_free_data (void *impl)
1941 g_assert_not_reached ();
1944 /* Category icalls */
1946 mono_perfcounter_category_del (MonoString *name)
1948 g_assert_not_reached ();
1952 mono_perfcounter_category_help (MonoString *category, MonoString *machine)
1954 g_assert_not_reached ();
1958 mono_perfcounter_category_exists (MonoString *counter, MonoString *category, MonoString *machine)
1960 g_assert_not_reached ();
1964 mono_perfcounter_create (MonoString *category, MonoString *help, int type, MonoArray *items)
1966 g_assert_not_reached ();
1970 mono_perfcounter_instance_exists (MonoString *instance, MonoString *category, MonoString *machine)
1972 g_assert_not_reached ();
1976 mono_perfcounter_category_names (MonoString *machine)
1978 g_assert_not_reached ();
1982 mono_perfcounter_counter_names (MonoString *category, MonoString *machine)
1984 g_assert_not_reached ();
1988 mono_perfcounter_instance_names (MonoString *category, MonoString *machine)
1990 g_assert_not_reached ();