3 * Copyright 2001-2003 Ximian, Inc
4 * Copyright 2003-2010 Novell, Inc.
5 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
7 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #include "mono/sgen/sgen-gc.h"
16 #include "mono/sgen/sgen-pinning.h"
17 #include "mono/sgen/sgen-hash-table.h"
18 #include "mono/sgen/sgen-client.h"
20 typedef struct _PinStatAddress PinStatAddress
;
21 struct _PinStatAddress
{
25 PinStatAddress
*right
;
29 size_t num_pins
[PIN_TYPE_MAX
];
34 } GlobalRemsetClassEntry
;
36 static gboolean do_pin_stats
= FALSE
;
38 static PinStatAddress
*pin_stat_addresses
= NULL
;
39 static size_t pinned_byte_counts
[PIN_TYPE_MAX
];
41 static size_t pinned_bytes_in_generation
[GENERATION_MAX
];
42 static int pinned_objects_in_generation
[GENERATION_MAX
];
44 static SgenPointerQueue pinned_objects
= SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_STATISTICS
);
46 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
);
47 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
);
50 sgen_pin_stats_enable (void)
56 pin_stats_tree_free (PinStatAddress
*node
)
60 pin_stats_tree_free (node
->left
);
61 pin_stats_tree_free (node
->right
);
62 sgen_free_internal_dynamic (node
, sizeof (PinStatAddress
), INTERNAL_MEM_STATISTICS
);
66 sgen_pin_stats_reset (void)
69 pin_stats_tree_free (pin_stat_addresses
);
70 pin_stat_addresses
= NULL
;
71 for (i
= 0; i
< PIN_TYPE_MAX
; ++i
)
72 pinned_byte_counts
[i
] = 0;
73 for (i
= 0; i
< GENERATION_MAX
; ++i
) {
74 pinned_bytes_in_generation
[i
] = 0;
75 pinned_objects_in_generation
[i
] = 0;
77 sgen_pointer_queue_clear (&pinned_objects
);
78 sgen_hash_table_clean (&pinned_class_hash_table
);
79 sgen_hash_table_clean (&global_remset_class_hash_table
);
83 sgen_pin_stats_register_address (char *addr
, int pin_type
)
85 PinStatAddress
**node_ptr
= &pin_stat_addresses
;
87 int pin_type_bit
= 1 << pin_type
;
93 if (addr
== node
->addr
) {
94 node
->pin_types
|= pin_type_bit
;
97 if (addr
< node
->addr
)
98 node_ptr
= &node
->left
;
100 node_ptr
= &node
->right
;
103 node
= (PinStatAddress
*)sgen_alloc_internal_dynamic (sizeof (PinStatAddress
), INTERNAL_MEM_STATISTICS
, TRUE
);
105 node
->pin_types
= pin_type_bit
;
106 node
->left
= node
->right
= NULL
;
112 pin_stats_count_object_from_tree (GCObject
*object
, size_t size
, PinStatAddress
*node
, int *pin_types
)
114 char *obj
= (char*)object
;
117 if (node
->addr
>= obj
&& node
->addr
< obj
+ size
) {
119 for (i
= 0; i
< PIN_TYPE_MAX
; ++i
) {
120 int pin_bit
= 1 << i
;
121 if (!(*pin_types
& pin_bit
) && (node
->pin_types
& pin_bit
)) {
122 pinned_byte_counts
[i
] += size
;
123 *pin_types
|= pin_bit
;
127 if (obj
< node
->addr
)
128 pin_stats_count_object_from_tree (object
, size
, node
->left
, pin_types
);
129 if (obj
+ size
- 1 > node
->addr
)
130 pin_stats_count_object_from_tree (object
, size
, node
->right
, pin_types
);
134 lookup_vtable_entry (SgenHashTable
*hash_table
, GCVTable vtable
, gpointer empty_entry
)
136 char *name
= g_strdup_printf ("%s.%s", sgen_client_vtable_get_namespace (vtable
), sgen_client_vtable_get_name (vtable
));
137 gpointer entry
= sgen_hash_table_lookup (hash_table
, name
);
142 sgen_hash_table_replace (hash_table
, name
, empty_entry
, NULL
);
143 entry
= sgen_hash_table_lookup (hash_table
, name
);
150 register_vtable (GCVTable vtable
, int pin_types
)
152 PinnedClassEntry empty_entry
;
153 PinnedClassEntry
*entry
;
156 memset (&empty_entry
, 0, sizeof (PinnedClassEntry
));
157 entry
= (PinnedClassEntry
*)lookup_vtable_entry (&pinned_class_hash_table
, vtable
, &empty_entry
);
159 for (i
= 0; i
< PIN_TYPE_MAX
; ++i
) {
160 if (pin_types
& (1 << i
))
161 ++entry
->num_pins
[i
];
166 sgen_pin_stats_register_object (GCObject
*obj
, int generation
)
171 if (sgen_binary_protocol_is_enabled ()) {
172 size
= sgen_safe_object_get_size (obj
);
173 pinned_bytes_in_generation
[generation
] += size
;
174 ++pinned_objects_in_generation
[generation
];
181 size
= sgen_safe_object_get_size (obj
);
183 pin_stats_count_object_from_tree (obj
, size
, pin_stat_addresses
, &pin_types
);
184 sgen_pointer_queue_add (&pinned_objects
, obj
);
187 register_vtable (SGEN_LOAD_VTABLE (obj
), pin_types
);
191 sgen_pin_stats_register_global_remset (GCObject
*obj
)
193 GlobalRemsetClassEntry empty_entry
;
194 GlobalRemsetClassEntry
*entry
;
199 memset (&empty_entry
, 0, sizeof (GlobalRemsetClassEntry
));
200 entry
= (GlobalRemsetClassEntry
*)lookup_vtable_entry (&global_remset_class_hash_table
, SGEN_LOAD_VTABLE (obj
), &empty_entry
);
202 ++entry
->num_remsets
;
206 sgen_pin_stats_report (void)
209 PinnedClassEntry
*pinned_entry
;
210 GlobalRemsetClassEntry
*remset_entry
;
212 sgen_binary_protocol_pin_stats (pinned_objects_in_generation
[GENERATION_NURSERY
], pinned_bytes_in_generation
[GENERATION_NURSERY
],
213 pinned_objects_in_generation
[GENERATION_OLD
], pinned_bytes_in_generation
[GENERATION_OLD
]);
218 mono_gc_printf (sgen_gc_debug_file
, "\n%-50s %10s %10s %10s\n", "Class", "Stack", "Static", "Other");
219 SGEN_HASH_TABLE_FOREACH (&pinned_class_hash_table
, char *, name
, PinnedClassEntry
*, pinned_entry
) {
221 mono_gc_printf (sgen_gc_debug_file
, "%-50s", name
);
222 for (i
= 0; i
< PIN_TYPE_MAX
; ++i
)
223 mono_gc_printf (sgen_gc_debug_file
, " %10zd", pinned_entry
->num_pins
[i
]);
224 mono_gc_printf (sgen_gc_debug_file
, "\n");
225 } SGEN_HASH_TABLE_FOREACH_END
;
227 mono_gc_printf (sgen_gc_debug_file
, "\n%-50s %10s\n", "Class", "#Remsets");
228 SGEN_HASH_TABLE_FOREACH (&global_remset_class_hash_table
, char *, name
, GlobalRemsetClassEntry
*, remset_entry
) {
229 mono_gc_printf (sgen_gc_debug_file
, "%-50s %10ld\n", name
, remset_entry
->num_remsets
);
230 } SGEN_HASH_TABLE_FOREACH_END
;
232 mono_gc_printf (sgen_gc_debug_file
, "\nTotal bytes pinned from stack: %zd static: %zd other: %zd\n",
233 pinned_byte_counts
[PIN_TYPE_STACK
],
234 pinned_byte_counts
[PIN_TYPE_STATIC_DATA
],
235 pinned_byte_counts
[PIN_TYPE_OTHER
]);
239 sgen_pin_stats_get_pinned_byte_count (int pin_type
)
241 return pinned_byte_counts
[pin_type
];
245 sgen_pin_stats_get_object_list (void)
247 return &pinned_objects
;
250 #endif /* HAVE_SGEN_GC */