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 "utils/unlocked.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 = InterlockedRead (&mono_perfcounters->exceptions_thrown);
1081 case CATEGORY_ASPNET:
1083 case COUNTER_ASPNET_REQ_Q:
1084 sample->rawValue = InterlockedRead (&mono_perfcounters->aspnet_requests_queued);
1086 case COUNTER_ASPNET_REQ_TOTAL:
1087 sample->rawValue = InterlockedRead (&mono_perfcounters->aspnet_requests);
1091 case CATEGORY_THREADPOOL:
1093 case COUNTER_THREADPOOL_WORKITEMS:
1094 sample->rawValue = InterlockedRead64 (&mono_perfcounters->threadpool_workitems);
1096 case COUNTER_THREADPOOL_IOWORKITEMS:
1097 sample->rawValue = InterlockedRead64 (&mono_perfcounters->threadpool_ioworkitems);
1099 case COUNTER_THREADPOOL_THREADS:
1100 sample->rawValue = InterlockedRead (&mono_perfcounters->threadpool_threads);
1102 case COUNTER_THREADPOOL_IOTHREADS:
1103 sample->rawValue = InterlockedRead (&mono_perfcounters->threadpool_iothreads);
1109 case COUNTER_JIT_BYTES:
1110 sample->rawValue = InterlockedRead (&mono_perfcounters->jit_bytes);
1112 case COUNTER_JIT_METHODS:
1113 sample->rawValue = InterlockedRead (&mono_perfcounters->jit_methods);
1115 case COUNTER_JIT_TIME:
1116 sample->rawValue = InterlockedRead (&mono_perfcounters->jit_time);
1118 case COUNTER_JIT_BYTES_PSEC:
1119 sample->rawValue = InterlockedRead (&mono_perfcounters->jit_bytes);
1121 case COUNTER_JIT_FAILURES:
1122 sample->rawValue = InterlockedRead (&mono_perfcounters->jit_failures);
1131 predef_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
1133 gint32 *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 = &mono_perfcounters->threadpool_workitems; break;
1148 case COUNTER_THREADPOOL_IOWORKITEMS: ptr64 = &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 (ptr);
1159 return InterlockedDecrement (ptr);
1161 return InterlockedAdd(ptr, value);
1163 /* this can be non-atomic */
1169 return UnlockedIncrement64 (ptr64); /* FIXME: use InterlockedIncrement64 () */
1171 return UnlockedDecrement64 (ptr64); /* FIXME: use InterlockedDecrement64 () */
1173 return UnlockedAdd64 (ptr64, value); /* FIXME: use InterlockedAdd64 () */
1175 /* this can be non-atomic */
1183 predef_writable_get_impl (int cat, MonoString* counter, const gchar *instance, int *type, MonoBoolean *custom)
1185 const CounterDesc *cdesc;
1187 if ((cdesc = get_counter_in_category (&predef_categories [cat], counter))) {
1188 *type = cdesc->type;
1189 if (instance == NULL || strcmp (instance, "") == 0)
1190 return create_vtable (GINT_TO_POINTER ((cdesc->id << 16) | cat), predef_writable_counter, predef_writable_update);
1192 return predef_vtable (GINT_TO_POINTER ((cdesc->id << 16) | cat), instance);
1198 custom_writable_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
1200 CustomVTable *counter_data = (CustomVTable *)vtable;
1202 fill_sample (sample);
1203 sample->baseValue = 1;
1205 sample->counterType = simple_type_to_type [counter_data->counter_desc->type];
1207 sample->rawValue = 0;
1209 sample->rawValue = *(guint64*)vtable->arg;
1214 custom_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
1216 /* FIXME: check writability */
1217 guint64 *ptr = (guint64 *)vtable->arg;
1220 /* FIXME: we need to do this atomically */
1224 /* this can be non-atomic */
1231 static SharedInstance*
1232 custom_get_instance (SharedCategory *cat, SharedCounter *scounter, char* name)
1234 SharedInstance* inst;
1237 inst = find_custom_instance (cat, name);
1240 size = sizeof (SharedInstance) + strlen (name);
1243 size += (sizeof (guint64) * cat->num_counters);
1245 inst = (SharedInstance*) shared_data_reserve_room (size, FTYPE_INSTANCE);
1251 inst->category_offset = (char*)cat - (char*)shared_area;
1252 cat->num_instances++;
1253 /* now copy the variable data */
1254 p = inst->instance_name;
1256 p += strlen (name) + 1;
1263 custom_vtable (SharedCounter *scounter, SharedInstance* inst, char *data)
1265 CustomVTable* vtable;
1266 vtable = g_new0 (CustomVTable, 1);
1267 vtable->vtable.arg = data;
1268 vtable->vtable.sample = custom_writable_counter;
1269 vtable->vtable.update = custom_writable_update;
1270 vtable->instance_desc = inst;
1271 vtable->counter_desc = scounter;
1273 return (ImplVtable*)vtable;
1277 custom_get_value_address (SharedCounter *scounter, SharedInstance* sinst)
1279 int offset = sizeof (SharedInstance) + strlen (sinst->instance_name);
1282 offset += scounter->seq_num * sizeof (guint64);
1283 return (char*)sinst + offset;
1287 custom_get_impl (SharedCategory *cat, MonoString *counter, MonoString* instance, int *type, MonoError *error)
1289 SharedCounter *scounter;
1290 SharedInstance* inst;
1294 scounter = find_custom_counter (cat, counter);
1297 name = mono_string_to_utf8_checked (counter, error);
1298 return_val_if_nok (error, NULL);
1299 *type = simple_type_to_type [scounter->type];
1300 inst = custom_get_instance (cat, scounter, name);
1304 return custom_vtable (scounter, inst, (char *)custom_get_value_address (scounter, inst));
1307 static const CategoryDesc*
1308 find_category (MonoString *category)
1311 for (i = 0; i < NUM_CATEGORIES; ++i) {
1312 if (mono_string_compare_ascii (category, predef_categories [i].name) == 0)
1313 return &predef_categories [i];
1319 mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString* instance,
1320 MonoString* machine, int *type, MonoBoolean *custom)
1323 const CategoryDesc *cdesc;
1324 void *result = NULL;
1325 /* no support for counters on other machines */
1326 if (mono_string_compare_ascii (machine, "."))
1328 cdesc = find_category (category);
1330 SharedCategory *scat = find_custom_category (category);
1334 result = custom_get_impl (scat, counter, instance, type, &error);
1335 if (mono_error_set_pending_exception (&error))
1339 gchar *c_instance = mono_string_to_utf8_checked (instance, &error);
1340 if (mono_error_set_pending_exception (&error))
1342 switch (cdesc->id) {
1344 result = cpu_get_impl (counter, c_instance, type, custom);
1347 result = process_get_impl (counter, c_instance, type, custom);
1349 case CATEGORY_MONO_MEM:
1350 result = mono_mem_get_impl (counter, c_instance, type, custom);
1352 case CATEGORY_NETWORK:
1353 result = network_get_impl (counter, c_instance, type, custom);
1358 case CATEGORY_REMOTING:
1359 case CATEGORY_LOADING:
1360 case CATEGORY_THREAD:
1361 case CATEGORY_INTEROP:
1362 case CATEGORY_SECURITY:
1363 case CATEGORY_ASPNET:
1364 case CATEGORY_THREADPOOL:
1365 result = predef_writable_get_impl (cdesc->id, counter, c_instance, type, custom);
1368 g_free (c_instance);
1373 mono_perfcounter_get_sample (void *impl, MonoBoolean only_value, MonoCounterSample *sample)
1375 ImplVtable *vtable = (ImplVtable *)impl;
1376 if (vtable && vtable->sample)
1377 return vtable->sample (vtable, only_value, sample);
1382 mono_perfcounter_update_value (void *impl, MonoBoolean do_incr, gint64 value)
1384 ImplVtable *vtable = (ImplVtable *)impl;
1385 if (vtable && vtable->update)
1386 return vtable->update (vtable, do_incr, value);
1391 mono_perfcounter_free_data (void *impl)
1393 ImplVtable *vtable = (ImplVtable *)impl;
1394 if (vtable && vtable->cleanup)
1395 vtable->cleanup (vtable);
1399 /* Category icalls */
1401 mono_perfcounter_category_del (MonoString *name)
1403 const CategoryDesc *cdesc;
1404 SharedCategory *cat;
1405 cdesc = find_category (name);
1406 /* can't delete a predefined category */
1410 cat = find_custom_category (name);
1411 /* FIXME: check the semantics, if deleting a category means also deleting the instances */
1412 if (!cat || cat->num_instances) {
1416 cat->header.ftype = FTYPE_DELETED;
1421 /* this is an icall */
1423 mono_perfcounter_category_help (MonoString *category, MonoString *machine)
1426 MonoString *result = NULL;
1427 const CategoryDesc *cdesc;
1428 error_init (&error);
1429 /* no support for counters on other machines */
1430 if (mono_string_compare_ascii (machine, "."))
1432 cdesc = find_category (category);
1434 SharedCategory *scat = find_custom_category (category);
1437 result = mono_string_new_checked (mono_domain_get (), custom_category_help (scat), &error);
1438 if (mono_error_set_pending_exception (&error))
1442 result = mono_string_new_checked (mono_domain_get (), cdesc->help, &error);
1443 if (mono_error_set_pending_exception (&error))
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 */
1604 /* this is an icall */
1606 mono_perfcounter_category_names (MonoString *machine)
1611 MonoDomain *domain = mono_domain_get ();
1612 GSList *custom_categories, *tmp;
1613 /* no support for counters on other machines */
1614 if (mono_string_compare_ascii (machine, ".")) {
1615 res = mono_array_new_checked (domain, mono_get_string_class (), 0, &error);
1616 mono_error_set_pending_exception (&error);
1620 custom_categories = get_custom_categories ();
1621 res = mono_array_new_checked (domain, mono_get_string_class (), NUM_CATEGORIES + g_slist_length (custom_categories), &error);
1622 if (mono_error_set_pending_exception (&error)) {
1627 for (i = 0; i < NUM_CATEGORIES; ++i) {
1628 const CategoryDesc *cdesc = &predef_categories [i];
1629 MonoString *name = mono_string_new_checked (domain, cdesc->name, &error);
1630 if (!is_ok (&error))
1632 mono_array_setref (res, i, name);
1634 for (tmp = custom_categories; tmp; tmp = tmp->next) {
1635 SharedCategory *scat = (SharedCategory *)tmp->data;
1636 MonoString *name = mono_string_new_checked (domain, scat->name, &error);
1637 if (!is_ok (&error))
1639 mono_array_setref (res, i, name);
1644 g_slist_free (custom_categories);
1645 mono_error_set_pending_exception (&error);
1650 mono_perfcounter_counter_names (MonoString *category, MonoString *machine)
1654 SharedCategory *scat;
1655 const CategoryDesc *cdesc;
1657 MonoDomain *domain = mono_domain_get ();
1658 /* no support for counters on other machines */
1659 if (mono_string_compare_ascii (machine, ".")) {
1660 res = mono_array_new_checked (domain, mono_get_string_class (), 0, &error);
1661 mono_error_set_pending_exception (&error);
1664 cdesc = find_category (category);
1666 res = mono_array_new_checked (domain, mono_get_string_class (), cdesc [1].first_counter - cdesc->first_counter, &error);
1667 if (mono_error_set_pending_exception (&error))
1669 for (i = cdesc->first_counter; i < cdesc [1].first_counter; ++i) {
1670 const CounterDesc *desc = &predef_counters [i];
1671 MonoString *name = mono_string_new_checked (domain, desc->name, &error);
1672 if (mono_error_set_pending_exception (&error))
1674 mono_array_setref (res, i - cdesc->first_counter, name);
1679 scat = find_custom_category (category);
1681 char *p = custom_category_counters (scat);
1683 res = mono_array_new_checked (domain, mono_get_string_class (), scat->num_counters, &error);
1684 if (mono_error_set_pending_exception (&error)) {
1689 for (i = 0; i < scat->num_counters; ++i) {
1690 MonoString *str = mono_string_new_checked (domain, p + 1, &error);
1691 if (!is_ok (&error))
1693 mono_array_setref (res, i, str);
1694 p += 2; /* skip counter type */
1695 p += strlen (p) + 1; /* skip counter name */
1696 p += strlen (p) + 1; /* skip counter help */
1699 res = mono_array_new_checked (domain, mono_get_string_class (), 0, &error);
1702 mono_error_set_pending_exception (&error);
1707 get_string_array (void **array, int count, gboolean is_process, MonoError *error)
1710 MonoDomain *domain = mono_domain_get ();
1712 MonoArray * res = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), count, error);
1713 return_val_if_nok (error, NULL);
1714 for (i = 0; i < count; ++i) {
1718 char *pname = mono_process_get_name (array [i], buf, sizeof (buf));
1719 p = g_strdup_printf ("%d/%s", GPOINTER_TO_INT (array [i]), pname);
1721 sprintf (buf, "%d", GPOINTER_TO_INT (array [i]));
1724 MonoString *str = mono_string_new_checked (domain, p, error);
1727 return_val_if_nok (error, NULL);
1728 mono_array_setref (res, i, str);
1734 get_string_array_of_strings (void **array, int count, MonoError *error)
1737 MonoDomain *domain = mono_domain_get ();
1739 MonoArray * res = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), count, error);
1740 return_val_if_nok (error, NULL);
1741 for (i = 0; i < count; ++i) {
1742 char* p = (char *)array[i];
1743 MonoString *str = mono_string_new_checked (domain, p, error);
1744 return_val_if_nok (error, NULL);
1745 mono_array_setref (res, i, str);
1752 get_mono_instances (MonoError *error)
1762 buf = g_new (void*, count);
1763 res = mono_shared_area_instances (buf, count);
1764 } while (res == count);
1765 array = get_string_array (buf, res, TRUE, error);
1771 get_cpu_instances (MonoError *error)
1777 count = mono_cpu_count () + 1; /* +1 for "_Total" */
1778 buf = g_new (void*, count);
1779 for (i = 0; i < count; ++i)
1780 buf [i] = GINT_TO_POINTER (i - 1); /* -1 => _Total */
1781 array = get_string_array (buf, count, FALSE, error);
1783 MonoString *total = mono_string_new_checked (mono_domain_get (), "_Total", error);
1784 return_val_if_nok (error, NULL);
1785 mono_array_setref (array, 0, total);
1790 get_processes_instances (MonoError *error)
1794 void **buf = mono_process_list (&count);
1797 return get_string_array (NULL, 0, FALSE, error);
1798 array = get_string_array (buf, count, TRUE, error);
1804 get_networkinterface_instances (MonoError *error)
1809 void **buf = mono_networkinterface_list (&count);
1811 return get_string_array_of_strings (NULL, 0, error);
1812 array = get_string_array_of_strings (buf, count, error);
1813 g_strfreev ((char **) buf);
1818 get_custom_instances (MonoString *category, MonoError *error)
1820 SharedCategory *scat;
1822 scat = find_custom_category (category);
1824 GSList *list = get_custom_instances_list (scat);
1827 MonoArray *array = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), g_slist_length (list), error);
1828 if (!is_ok (error)) {
1829 g_slist_free (list);
1832 for (tmp = list; tmp; tmp = tmp->next) {
1833 SharedInstance *inst = (SharedInstance *)tmp->data;
1834 MonoString *str = mono_string_new_checked (mono_domain_get (), inst->instance_name, error);
1835 if (!is_ok (error)) {
1836 g_slist_free (list);
1839 mono_array_setref (array, i, str);
1842 g_slist_free (list);
1845 return mono_array_new_checked (mono_domain_get (), mono_get_string_class (), 0, error);
1849 mono_perfcounter_instance_names (MonoString *category, MonoString *machine)
1852 const CategoryDesc* cat;
1853 MonoArray *result = NULL;
1854 if (mono_string_compare_ascii (machine, ".")) {
1855 result = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), 0, &error);
1856 mono_error_set_pending_exception (&error);
1860 cat = find_category (category);
1862 MonoArray *result = get_custom_instances (category, &error);
1863 mono_error_set_pending_exception (&error);
1866 switch (cat->instance_type) {
1868 result = get_mono_instances (&error);
1871 result = get_cpu_instances (&error);
1873 case ProcessInstance:
1874 result = get_processes_instances (&error);
1876 case NetworkInterfaceInstance:
1877 result = get_networkinterface_instances (&error);
1879 case ThreadInstance:
1881 result = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), 0, &error);
1883 mono_error_set_pending_exception (&error);
1888 PerfCounterEnumCallback cb;
1890 } PerfCounterForeachData;
1893 mono_perfcounter_foreach_shared_item (SharedHeader *header, gpointer data)
1899 SharedCategory *cat;
1900 SharedCounter *counter;
1901 SharedInstance *inst;
1902 PerfCounterForeachData *foreach_data = (PerfCounterForeachData *)data;
1904 if (header->ftype == FTYPE_CATEGORY) {
1905 cat = (SharedCategory*)header;
1908 p += strlen (p) + 1; /* skip category name */
1909 p += strlen (p) + 1; /* skip category help */
1911 for (i = 0; i < cat->num_counters; ++i) {
1912 counter = (SharedCounter*) p;
1913 type = (unsigned char)*p++;
1914 /* seq_num = (int)* */ p++;
1916 p += strlen (p) + 1;
1918 p += strlen (p) + 1;
1920 inst = custom_get_instance (cat, counter, name);
1923 addr = custom_get_value_address (counter, inst);
1924 if (!foreach_data->cb (cat->name, name, type, addr ? *(gint64*)addr : 0, foreach_data->data))
1933 mono_perfcounter_foreach (PerfCounterEnumCallback cb, gpointer data)
1935 PerfCounterForeachData foreach_data = { cb, data };
1939 foreach_shared_item (mono_perfcounter_foreach_shared_item, &foreach_data);
1946 mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString* instance, MonoString* machine, int *type, MonoBoolean *custom)
1948 g_assert_not_reached ();
1952 mono_perfcounter_get_sample (void *impl, MonoBoolean only_value, MonoCounterSample *sample)
1954 g_assert_not_reached ();
1958 mono_perfcounter_update_value (void *impl, MonoBoolean do_incr, gint64 value)
1960 g_assert_not_reached ();
1964 mono_perfcounter_free_data (void *impl)
1966 g_assert_not_reached ();
1969 /* Category icalls */
1971 mono_perfcounter_category_del (MonoString *name)
1973 g_assert_not_reached ();
1977 mono_perfcounter_category_help (MonoString *category, MonoString *machine)
1979 g_assert_not_reached ();
1983 mono_perfcounter_category_exists (MonoString *counter, MonoString *category, MonoString *machine)
1985 g_assert_not_reached ();
1989 mono_perfcounter_create (MonoString *category, MonoString *help, int type, MonoArray *items)
1991 g_assert_not_reached ();
1995 mono_perfcounter_instance_exists (MonoString *instance, MonoString *category, MonoString *machine)
1997 g_assert_not_reached ();
2001 mono_perfcounter_category_names (MonoString *machine)
2003 g_assert_not_reached ();
2007 mono_perfcounter_counter_names (MonoString *category, MonoString *machine)
2009 g_assert_not_reached ();
2013 mono_perfcounter_instance_names (MonoString *category, MonoString *machine)
2015 g_assert_not_reached ();