[sgen] Don't register pinned objects if pin stats are disabled
[mono.git] / mono / sgen / sgen-pinning-stats.c
1 /*
2  * Copyright 2001-2003 Ximian, Inc
3  * Copyright 2003-2010 Novell, Inc.
4  * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
5  * 
6  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
7  */
8
9 #include "config.h"
10 #ifdef HAVE_SGEN_GC
11
12 #include <string.h>
13
14 #include "mono/sgen/sgen-gc.h"
15 #include "mono/sgen/sgen-pinning.h"
16 #include "mono/sgen/sgen-hash-table.h"
17 #include "mono/sgen/sgen-client.h"
18
19 typedef struct _PinStatAddress PinStatAddress;
20 struct _PinStatAddress {
21         char *addr;
22         int pin_types;
23         PinStatAddress *left;
24         PinStatAddress *right;
25 };
26
27 typedef struct {
28         size_t num_pins [PIN_TYPE_MAX];
29 } PinnedClassEntry;
30
31 typedef struct {
32         gulong num_remsets;
33 } GlobalRemsetClassEntry;
34
35 static gboolean do_pin_stats = FALSE;
36
37 static PinStatAddress *pin_stat_addresses = NULL;
38 static size_t pinned_byte_counts [PIN_TYPE_MAX];
39
40 static SgenPointerQueue pinned_objects = SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_STATISTICS);
41
42 static SgenHashTable pinned_class_hash_table = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_STATISTICS, INTERNAL_MEM_STAT_PINNED_CLASS, sizeof (PinnedClassEntry), g_str_hash, g_str_equal);
43 static SgenHashTable global_remset_class_hash_table = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_STATISTICS, INTERNAL_MEM_STAT_REMSET_CLASS, sizeof (GlobalRemsetClassEntry), g_str_hash, g_str_equal);
44
45 void
46 sgen_pin_stats_enable (void)
47 {
48         do_pin_stats = TRUE;
49 }
50
51 static void
52 pin_stats_tree_free (PinStatAddress *node)
53 {
54         if (!node)
55                 return;
56         pin_stats_tree_free (node->left);
57         pin_stats_tree_free (node->right);
58         sgen_free_internal_dynamic (node, sizeof (PinStatAddress), INTERNAL_MEM_STATISTICS);
59 }
60
61 void
62 sgen_pin_stats_reset (void)
63 {
64         int i;
65         pin_stats_tree_free (pin_stat_addresses);
66         pin_stat_addresses = NULL;
67         for (i = 0; i < PIN_TYPE_MAX; ++i)
68                 pinned_byte_counts [i] = 0;
69         sgen_pointer_queue_clear (&pinned_objects);
70         sgen_hash_table_clean (&pinned_class_hash_table);
71         sgen_hash_table_clean (&global_remset_class_hash_table);
72 }
73
74 void
75 sgen_pin_stats_register_address (char *addr, int pin_type)
76 {
77         PinStatAddress **node_ptr = &pin_stat_addresses;
78         PinStatAddress *node;
79         int pin_type_bit = 1 << pin_type;
80
81         if (!do_pin_stats)
82                 return;
83         while (*node_ptr) {
84                 node = *node_ptr;
85                 if (addr == node->addr) {
86                         node->pin_types |= pin_type_bit;
87                         return;
88                 }
89                 if (addr < node->addr)
90                         node_ptr = &node->left;
91                 else
92                         node_ptr = &node->right;
93         }
94
95         node = (PinStatAddress *)sgen_alloc_internal_dynamic (sizeof (PinStatAddress), INTERNAL_MEM_STATISTICS, TRUE);
96         node->addr = addr;
97         node->pin_types = pin_type_bit;
98         node->left = node->right = NULL;
99
100         *node_ptr = node;
101 }
102
103 static void
104 pin_stats_count_object_from_tree (GCObject *object, size_t size, PinStatAddress *node, int *pin_types)
105 {
106         char *obj = (char*)object;
107         if (!node)
108                 return;
109         if (node->addr >= obj && node->addr < obj + size) {
110                 int i;
111                 for (i = 0; i < PIN_TYPE_MAX; ++i) {
112                         int pin_bit = 1 << i;
113                         if (!(*pin_types & pin_bit) && (node->pin_types & pin_bit)) {
114                                 pinned_byte_counts [i] += size;
115                                 *pin_types |= pin_bit;
116                         }
117                 }
118         }
119         if (obj < node->addr)
120                 pin_stats_count_object_from_tree (object, size, node->left, pin_types);
121         if (obj + size - 1 > node->addr)
122                 pin_stats_count_object_from_tree (object, size, node->right, pin_types);
123 }
124
125 static gpointer
126 lookup_vtable_entry (SgenHashTable *hash_table, GCVTable vtable, gpointer empty_entry)
127 {
128         char *name = g_strdup_printf ("%s.%s", sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable));
129         gpointer entry = sgen_hash_table_lookup (hash_table, name);
130
131         if (entry) {
132                 g_free (name);
133         } else {
134                 sgen_hash_table_replace (hash_table, name, empty_entry, NULL);
135                 entry = sgen_hash_table_lookup (hash_table, name);
136         }
137
138         return entry;
139 }
140
141 static void
142 register_vtable (GCVTable vtable, int pin_types)
143 {
144         PinnedClassEntry empty_entry;
145         PinnedClassEntry *entry;
146         int i;
147
148         memset (&empty_entry, 0, sizeof (PinnedClassEntry));
149         entry = (PinnedClassEntry *)lookup_vtable_entry (&pinned_class_hash_table, vtable, &empty_entry);
150
151         for (i = 0; i < PIN_TYPE_MAX; ++i) {
152                 if (pin_types & (1 << i))
153                         ++entry->num_pins [i];
154         }
155 }
156
157 void
158 sgen_pin_stats_register_object (GCObject *obj, size_t size)
159 {
160         int pin_types = 0;
161
162         if (!do_pin_stats)
163                 return;
164
165         pin_stats_count_object_from_tree (obj, size, pin_stat_addresses, &pin_types);
166         sgen_pointer_queue_add (&pinned_objects, obj);
167
168         if (pin_types)
169                 register_vtable (SGEN_LOAD_VTABLE (obj), pin_types);
170 }
171
172 void
173 sgen_pin_stats_register_global_remset (GCObject *obj)
174 {
175         GlobalRemsetClassEntry empty_entry;
176         GlobalRemsetClassEntry *entry;
177
178         if (!do_pin_stats)
179                 return;
180
181         memset (&empty_entry, 0, sizeof (GlobalRemsetClassEntry));
182         entry = (GlobalRemsetClassEntry *)lookup_vtable_entry (&global_remset_class_hash_table, SGEN_LOAD_VTABLE (obj), &empty_entry);
183
184         ++entry->num_remsets;
185 }
186
187 void
188 sgen_pin_stats_print_class_stats (void)
189 {
190         char *name;
191         PinnedClassEntry *pinned_entry;
192         GlobalRemsetClassEntry *remset_entry;
193
194         if (!do_pin_stats)
195                 return;
196
197         mono_gc_printf (gc_debug_file, "\n%-50s  %10s  %10s  %10s\n", "Class", "Stack", "Static", "Other");
198         SGEN_HASH_TABLE_FOREACH (&pinned_class_hash_table, char *, name, PinnedClassEntry *, pinned_entry) {
199                 int i;
200                 mono_gc_printf (gc_debug_file, "%-50s", name);
201                 for (i = 0; i < PIN_TYPE_MAX; ++i)
202                         mono_gc_printf (gc_debug_file, "  %10ld", pinned_entry->num_pins [i]);
203                 mono_gc_printf (gc_debug_file, "\n");
204         } SGEN_HASH_TABLE_FOREACH_END;
205
206         mono_gc_printf (gc_debug_file, "\n%-50s  %10s\n", "Class", "#Remsets");
207         SGEN_HASH_TABLE_FOREACH (&global_remset_class_hash_table, char *, name, GlobalRemsetClassEntry *, remset_entry) {
208                 mono_gc_printf (gc_debug_file, "%-50s  %10ld\n", name, remset_entry->num_remsets);
209         } SGEN_HASH_TABLE_FOREACH_END;
210
211         mono_gc_printf (gc_debug_file, "\nTotal bytes pinned from stack: %ld  static: %ld  other: %ld\n",
212                         pinned_byte_counts [PIN_TYPE_STACK],
213                         pinned_byte_counts [PIN_TYPE_STATIC_DATA],
214                         pinned_byte_counts [PIN_TYPE_OTHER]);
215 }
216
217 size_t
218 sgen_pin_stats_get_pinned_byte_count (int pin_type)
219 {
220         return pinned_byte_counts [pin_type];
221 }
222
223 SgenPointerQueue*
224 sgen_pin_stats_get_object_list (void)
225 {
226         return &pinned_objects;
227 }
228
229 #endif /* HAVE_SGEN_GC */