2 * sgen-internal.c: Internal lock-free memory allocator.
4 * Copyright (C) 2012 Xamarin Inc
6 * 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/utils/lock-free-alloc.h"
17 #include "mono/sgen/sgen-memory-governor.h"
18 #include "mono/sgen/sgen-client.h"
20 /* keep each size a multiple of ALLOC_ALIGN */
21 #if SIZEOF_VOID_P == 4
22 static const int allocator_sizes [] = {
23 8, 16, 24, 32, 40, 48, 64, 80,
24 96, 128, 160, 192, 224, 248, 296, 320,
25 384, 448, 504, 528, 584, 680, 816, 1088,
26 1360, 2044, 2336, 2728, 3272, 4092, 5456, 8188 };
28 static const int allocator_sizes [] = {
29 8, 16, 24, 32, 40, 48, 64, 80,
30 96, 128, 160, 192, 224, 248, 320, 328,
31 384, 448, 528, 584, 680, 816, 1016, 1088,
32 1360, 2040, 2336, 2728, 3272, 4088, 5456, 8184 };
35 #define NUM_ALLOCATORS (sizeof (allocator_sizes) / sizeof (int))
37 static int allocator_block_sizes [NUM_ALLOCATORS];
39 static MonoLockFreeAllocSizeClass size_classes [NUM_ALLOCATORS];
40 static MonoLockFreeAllocator allocators [NUM_ALLOCATORS];
42 #ifdef HEAVY_STATISTICS
43 static int allocator_sizes_stats [NUM_ALLOCATORS];
47 block_size (size_t slot_size)
49 static int pagesize = -1;
54 pagesize = mono_pagesize ();
56 for (size = pagesize; size < LOCK_FREE_ALLOC_SB_MAX_SIZE; size <<= 1) {
57 if (slot_size * 2 <= LOCK_FREE_ALLOC_SB_USABLE_SIZE (size))
60 return LOCK_FREE_ALLOC_SB_MAX_SIZE;
64 * Find the allocator index for memory chunks that can contain @size
68 index_for_size (size_t size)
71 /* do a binary search or lookup table later. */
72 for (slot = 0; slot < NUM_ALLOCATORS; ++slot) {
73 if (allocator_sizes [slot] >= size)
76 g_assert_not_reached ();
81 * Allocator indexes for the fixed INTERNAL_MEM_XXX types. -1 if that
84 static int fixed_type_allocator_indexes [INTERNAL_MEM_MAX];
87 sgen_register_fixed_internal_mem_type (int type, size_t size)
91 g_assert (type >= 0 && type < INTERNAL_MEM_MAX);
92 g_assert (size <= allocator_sizes [NUM_ALLOCATORS - 1]);
94 slot = index_for_size (size);
97 if (fixed_type_allocator_indexes [type] == -1)
98 fixed_type_allocator_indexes [type] = slot;
100 g_assert (fixed_type_allocator_indexes [type] == slot);
104 description_for_type (int type)
107 case INTERNAL_MEM_PIN_QUEUE: return "pin-queue";
108 case INTERNAL_MEM_FRAGMENT: return "fragment";
109 case INTERNAL_MEM_SECTION: return "section";
110 case INTERNAL_MEM_SCAN_STARTS: return "scan-starts";
111 case INTERNAL_MEM_FIN_TABLE: return "fin-table";
112 case INTERNAL_MEM_FINALIZE_ENTRY: return "finalize-entry";
113 case INTERNAL_MEM_FINALIZE_READY: return "finalize-ready";
114 case INTERNAL_MEM_DISLINK_TABLE: return "dislink-table";
115 case INTERNAL_MEM_DISLINK: return "dislink";
116 case INTERNAL_MEM_ROOTS_TABLE: return "roots-table";
117 case INTERNAL_MEM_ROOT_RECORD: return "root-record";
118 case INTERNAL_MEM_STATISTICS: return "statistics";
119 case INTERNAL_MEM_STAT_PINNED_CLASS: return "pinned-class";
120 case INTERNAL_MEM_STAT_REMSET_CLASS: return "remset-class";
121 case INTERNAL_MEM_GRAY_QUEUE: return "gray-queue";
122 case INTERNAL_MEM_MS_TABLES: return "marksweep-tables";
123 case INTERNAL_MEM_MS_BLOCK_INFO: return "marksweep-block-info";
124 case INTERNAL_MEM_MS_BLOCK_INFO_SORT: return "marksweep-block-info-sort";
125 case INTERNAL_MEM_WORKER_DATA: return "worker-data";
126 case INTERNAL_MEM_THREAD_POOL_JOB: return "thread-pool-job";
127 case INTERNAL_MEM_BRIDGE_DATA: return "bridge-data";
128 case INTERNAL_MEM_OLD_BRIDGE_HASH_TABLE: return "old-bridge-hash-table";
129 case INTERNAL_MEM_OLD_BRIDGE_HASH_TABLE_ENTRY: return "old-bridge-hash-table-entry";
130 case INTERNAL_MEM_BRIDGE_HASH_TABLE: return "bridge-hash-table";
131 case INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY: return "bridge-hash-table-entry";
132 case INTERNAL_MEM_TARJAN_BRIDGE_HASH_TABLE: return "tarjan-bridge-hash-table";
133 case INTERNAL_MEM_TARJAN_BRIDGE_HASH_TABLE_ENTRY: return "tarjan-bridge-hash-table-entry";
134 case INTERNAL_MEM_TARJAN_OBJ_BUCKET: return "tarjan-bridge-object-buckets";
135 case INTERNAL_MEM_BRIDGE_ALIVE_HASH_TABLE: return "bridge-alive-hash-table";
136 case INTERNAL_MEM_BRIDGE_ALIVE_HASH_TABLE_ENTRY: return "bridge-alive-hash-table-entry";
137 case INTERNAL_MEM_BRIDGE_DEBUG: return "bridge-debug";
138 case INTERNAL_MEM_TOGGLEREF_DATA: return "toggleref-data";
139 case INTERNAL_MEM_CARDTABLE_MOD_UNION: return "cardtable-mod-union";
140 case INTERNAL_MEM_BINARY_PROTOCOL: return "binary-protocol";
141 case INTERNAL_MEM_TEMPORARY: return "temporary";
143 const char *description = sgen_client_description_for_internal_mem_type (type);
144 SGEN_ASSERT (0, description, "Unknown internal mem type");
151 sgen_alloc_internal_dynamic (size_t size, int type, gboolean assert_on_failure)
156 if (size > allocator_sizes [NUM_ALLOCATORS - 1]) {
157 p = sgen_alloc_os_memory (size, (SgenAllocFlags)(SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE), NULL);
159 sgen_assert_memory_alloc (NULL, size, description_for_type (type));
161 index = index_for_size (size);
163 #ifdef HEAVY_STATISTICS
164 ++ allocator_sizes_stats [index];
167 p = mono_lock_free_alloc (&allocators [index]);
169 sgen_assert_memory_alloc (NULL, size, description_for_type (type));
176 sgen_free_internal_dynamic (void *addr, size_t size, int type)
181 if (size > allocator_sizes [NUM_ALLOCATORS - 1])
182 sgen_free_os_memory (addr, size, SGEN_ALLOC_INTERNAL);
184 mono_lock_free_free (addr, block_size (size));
188 sgen_alloc_internal (int type)
193 index = fixed_type_allocator_indexes [type];
194 g_assert (index >= 0 && index < NUM_ALLOCATORS);
196 #ifdef HEAVY_STATISTICS
197 ++ allocator_sizes_stats [index];
200 size = allocator_sizes [index];
202 p = mono_lock_free_alloc (&allocators [index]);
209 sgen_free_internal (void *addr, int type)
216 index = fixed_type_allocator_indexes [type];
217 g_assert (index >= 0 && index < NUM_ALLOCATORS);
219 mono_lock_free_free (addr, allocator_block_sizes [index]);
223 sgen_dump_internal_mem_usage (FILE *heap_dump_file)
228 fprintf (heap_dump_file, "<other-mem-usage type=\"large-internal\" size=\"%lld\"/>\n", large_internal_bytes_alloced);
229 fprintf (heap_dump_file, "<other-mem-usage type=\"pinned-chunks\" size=\"%lld\"/>\n", pinned_chunk_bytes_alloced);
230 for (i = 0; i < INTERNAL_MEM_MAX; ++i) {
231 fprintf (heap_dump_file, "<other-mem-usage type=\"%s\" size=\"%ld\"/>\n",
232 description_for_type (i), unmanaged_allocator.small_internal_mem_bytes [i]);
238 sgen_report_internal_mem_usage (void)
241 #ifdef HEAVY_STATISTICS
242 printf ("size -> # allocations\n");
243 for (i = 0; i < NUM_ALLOCATORS; ++i)
244 printf ("%d -> %d\n", allocator_sizes [i], allocator_sizes_stats [i]);
249 sgen_init_internal_allocator (void)
253 for (i = 0; i < INTERNAL_MEM_MAX; ++i)
254 fixed_type_allocator_indexes [i] = -1;
256 for (i = 0; i < NUM_ALLOCATORS; ++i) {
257 allocator_block_sizes [i] = block_size (allocator_sizes [i]);
258 mono_lock_free_allocator_init_size_class (&size_classes [i], allocator_sizes [i], allocator_block_sizes [i]);
259 mono_lock_free_allocator_init_allocator (&allocators [i], &size_classes [i]);
262 for (size = mono_pagesize (); size <= LOCK_FREE_ALLOC_SB_MAX_SIZE; size <<= 1) {
263 int max_size = LOCK_FREE_ALLOC_SB_USABLE_SIZE (size) / 2;
265 * we assert that allocator_sizes contains the biggest possible object size
266 * per block (4K => 4080 / 2 = 2040, 8k => 8176 / 2 = 4088, 16k => 16368 / 2 = 8184 on 64bits),
267 * so that we do not get different block sizes for sizes that should go to the same one
269 g_assert (allocator_sizes [index_for_size (max_size)] == max_size);