2 * Copyright 2001-2003 Ximian, Inc
3 * Copyright 2003-2010 Novell, Inc.
4 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
6 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
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"
19 typedef struct _PinStatAddress PinStatAddress
;
20 struct _PinStatAddress
{
24 PinStatAddress
*right
;
28 size_t num_pins
[PIN_TYPE_MAX
];
33 } GlobalRemsetClassEntry
;
35 static gboolean do_pin_stats
= FALSE
;
37 static PinStatAddress
*pin_stat_addresses
= NULL
;
38 static size_t pinned_byte_counts
[PIN_TYPE_MAX
];
40 static size_t pinned_bytes_in_generation
[GENERATION_MAX
];
41 static int pinned_objects_in_generation
[GENERATION_MAX
];
43 static SgenPointerQueue pinned_objects
= SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_STATISTICS
);
45 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
);
46 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
);
49 sgen_pin_stats_enable (void)
55 pin_stats_tree_free (PinStatAddress
*node
)
59 pin_stats_tree_free (node
->left
);
60 pin_stats_tree_free (node
->right
);
61 sgen_free_internal_dynamic (node
, sizeof (PinStatAddress
), INTERNAL_MEM_STATISTICS
);
65 sgen_pin_stats_reset (void)
68 pin_stats_tree_free (pin_stat_addresses
);
69 pin_stat_addresses
= NULL
;
70 for (i
= 0; i
< PIN_TYPE_MAX
; ++i
)
71 pinned_byte_counts
[i
] = 0;
72 for (i
= 0; i
< GENERATION_MAX
; ++i
) {
73 pinned_bytes_in_generation
[i
] = 0;
74 pinned_objects_in_generation
[i
] = 0;
76 sgen_pointer_queue_clear (&pinned_objects
);
77 sgen_hash_table_clean (&pinned_class_hash_table
);
78 sgen_hash_table_clean (&global_remset_class_hash_table
);
82 sgen_pin_stats_register_address (char *addr
, int pin_type
)
84 PinStatAddress
**node_ptr
= &pin_stat_addresses
;
86 int pin_type_bit
= 1 << pin_type
;
92 if (addr
== node
->addr
) {
93 node
->pin_types
|= pin_type_bit
;
96 if (addr
< node
->addr
)
97 node_ptr
= &node
->left
;
99 node_ptr
= &node
->right
;
102 node
= (PinStatAddress
*)sgen_alloc_internal_dynamic (sizeof (PinStatAddress
), INTERNAL_MEM_STATISTICS
, TRUE
);
104 node
->pin_types
= pin_type_bit
;
105 node
->left
= node
->right
= NULL
;
111 pin_stats_count_object_from_tree (GCObject
*object
, size_t size
, PinStatAddress
*node
, int *pin_types
)
113 char *obj
= (char*)object
;
116 if (node
->addr
>= obj
&& node
->addr
< obj
+ size
) {
118 for (i
= 0; i
< PIN_TYPE_MAX
; ++i
) {
119 int pin_bit
= 1 << i
;
120 if (!(*pin_types
& pin_bit
) && (node
->pin_types
& pin_bit
)) {
121 pinned_byte_counts
[i
] += size
;
122 *pin_types
|= pin_bit
;
126 if (obj
< node
->addr
)
127 pin_stats_count_object_from_tree (object
, size
, node
->left
, pin_types
);
128 if (obj
+ size
- 1 > node
->addr
)
129 pin_stats_count_object_from_tree (object
, size
, node
->right
, pin_types
);
133 lookup_vtable_entry (SgenHashTable
*hash_table
, GCVTable vtable
, gpointer empty_entry
)
135 char *name
= g_strdup_printf ("%s.%s", sgen_client_vtable_get_namespace (vtable
), sgen_client_vtable_get_name (vtable
));
136 gpointer entry
= sgen_hash_table_lookup (hash_table
, name
);
141 sgen_hash_table_replace (hash_table
, name
, empty_entry
, NULL
);
142 entry
= sgen_hash_table_lookup (hash_table
, name
);
149 register_vtable (GCVTable vtable
, int pin_types
)
151 PinnedClassEntry empty_entry
;
152 PinnedClassEntry
*entry
;
155 memset (&empty_entry
, 0, sizeof (PinnedClassEntry
));
156 entry
= (PinnedClassEntry
*)lookup_vtable_entry (&pinned_class_hash_table
, vtable
, &empty_entry
);
158 for (i
= 0; i
< PIN_TYPE_MAX
; ++i
) {
159 if (pin_types
& (1 << i
))
160 ++entry
->num_pins
[i
];
165 sgen_pin_stats_register_object (GCObject
*obj
, int generation
)
170 if (binary_protocol_is_enabled ()) {
171 size
= sgen_safe_object_get_size (obj
);
172 pinned_bytes_in_generation
[generation
] += size
;
173 ++pinned_objects_in_generation
[generation
];
180 size
= sgen_safe_object_get_size (obj
);
182 pin_stats_count_object_from_tree (obj
, size
, pin_stat_addresses
, &pin_types
);
183 sgen_pointer_queue_add (&pinned_objects
, obj
);
186 register_vtable (SGEN_LOAD_VTABLE (obj
), pin_types
);
190 sgen_pin_stats_register_global_remset (GCObject
*obj
)
192 GlobalRemsetClassEntry empty_entry
;
193 GlobalRemsetClassEntry
*entry
;
198 memset (&empty_entry
, 0, sizeof (GlobalRemsetClassEntry
));
199 entry
= (GlobalRemsetClassEntry
*)lookup_vtable_entry (&global_remset_class_hash_table
, SGEN_LOAD_VTABLE (obj
), &empty_entry
);
201 ++entry
->num_remsets
;
205 sgen_pin_stats_report (void)
208 PinnedClassEntry
*pinned_entry
;
209 GlobalRemsetClassEntry
*remset_entry
;
211 binary_protocol_pin_stats (pinned_objects_in_generation
[GENERATION_NURSERY
], pinned_bytes_in_generation
[GENERATION_NURSERY
],
212 pinned_objects_in_generation
[GENERATION_OLD
], pinned_bytes_in_generation
[GENERATION_OLD
]);
217 mono_gc_printf (gc_debug_file
, "\n%-50s %10s %10s %10s\n", "Class", "Stack", "Static", "Other");
218 SGEN_HASH_TABLE_FOREACH (&pinned_class_hash_table
, char *, name
, PinnedClassEntry
*, pinned_entry
) {
220 mono_gc_printf (gc_debug_file
, "%-50s", name
);
221 for (i
= 0; i
< PIN_TYPE_MAX
; ++i
)
222 mono_gc_printf (gc_debug_file
, " %10ld", pinned_entry
->num_pins
[i
]);
223 mono_gc_printf (gc_debug_file
, "\n");
224 } SGEN_HASH_TABLE_FOREACH_END
;
226 mono_gc_printf (gc_debug_file
, "\n%-50s %10s\n", "Class", "#Remsets");
227 SGEN_HASH_TABLE_FOREACH (&global_remset_class_hash_table
, char *, name
, GlobalRemsetClassEntry
*, remset_entry
) {
228 mono_gc_printf (gc_debug_file
, "%-50s %10ld\n", name
, remset_entry
->num_remsets
);
229 } SGEN_HASH_TABLE_FOREACH_END
;
231 mono_gc_printf (gc_debug_file
, "\nTotal bytes pinned from stack: %ld static: %ld other: %ld\n",
232 pinned_byte_counts
[PIN_TYPE_STACK
],
233 pinned_byte_counts
[PIN_TYPE_STATIC_DATA
],
234 pinned_byte_counts
[PIN_TYPE_OTHER
]);
238 sgen_pin_stats_get_pinned_byte_count (int pin_type
)
240 return pinned_byte_counts
[pin_type
];
244 sgen_pin_stats_get_object_list (void)
246 return &pinned_objects
;
249 #endif /* HAVE_SGEN_GC */