2 * sgen-internal.c: Internal lock-free memory allocator.
4 * Copyright (C) 2012 Xamarin Inc
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License 2.0 as published by the Free Software Foundation;
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License 2.0 along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "utils/mono-counters.h"
25 #include "metadata/sgen-gc.h"
26 #include "utils/lock-free-alloc.h"
27 #include "metadata/sgen-memory-governor.h"
29 /* keep each size a multiple of ALLOC_ALIGN */
30 #if SIZEOF_VOID_P == 4
31 static const int allocator_sizes [] = {
32 8, 16, 24, 32, 40, 48, 64, 80,
33 96, 128, 160, 192, 224, 248, 296, 320,
34 384, 448, 504, 528, 584, 680, 816, 1088,
35 1360, 2040, 2336, 2728, 3272, 4088, 5456, 8184 };
37 static const int allocator_sizes [] = {
38 8, 16, 24, 32, 40, 48, 64, 80,
39 96, 128, 160, 192, 224, 248, 320, 328,
40 384, 448, 528, 584, 680, 816, 1016, 1088,
41 1360, 2040, 2336, 2728, 3272, 4088, 5456, 8184 };
44 #define NUM_ALLOCATORS (sizeof (allocator_sizes) / sizeof (int))
46 static MonoLockFreeAllocSizeClass size_classes [NUM_ALLOCATORS];
47 static MonoLockFreeAllocator allocators [NUM_ALLOCATORS];
50 * Find the allocator index for memory chunks that can contain @size
54 index_for_size (size_t size)
57 /* do a binary search or lookup table later. */
58 for (slot = 0; slot < NUM_ALLOCATORS; ++slot) {
59 if (allocator_sizes [slot] >= size)
62 g_assert_not_reached ();
67 * Allocator indexes for the fixed INTERNAL_MEM_XXX types. -1 if that
70 static int fixed_type_allocator_indexes [INTERNAL_MEM_MAX];
73 sgen_register_fixed_internal_mem_type (int type, size_t size)
77 g_assert (type >= 0 && type < INTERNAL_MEM_MAX);
79 slot = index_for_size (size);
82 if (fixed_type_allocator_indexes [type] == -1)
83 fixed_type_allocator_indexes [type] = slot;
85 g_assert (fixed_type_allocator_indexes [type] == slot);
89 description_for_type (int type)
92 case INTERNAL_MEM_PIN_QUEUE: return "pin-queue";
93 case INTERNAL_MEM_FRAGMENT: return "fragment";
94 case INTERNAL_MEM_SECTION: return "section";
95 case INTERNAL_MEM_SCAN_STARTS: return "scan-starts";
96 case INTERNAL_MEM_FIN_TABLE: return "fin-table";
97 case INTERNAL_MEM_FINALIZE_ENTRY: return "finalize-entry";
98 case INTERNAL_MEM_FINALIZE_READY_ENTRY: return "finalize-ready-entry";
99 case INTERNAL_MEM_DISLINK_TABLE: return "dislink-table";
100 case INTERNAL_MEM_DISLINK: return "dislink";
101 case INTERNAL_MEM_ROOTS_TABLE: return "roots-table";
102 case INTERNAL_MEM_ROOT_RECORD: return "root-record";
103 case INTERNAL_MEM_STATISTICS: return "statistics";
104 case INTERNAL_MEM_STAT_PINNED_CLASS: return "pinned-class";
105 case INTERNAL_MEM_STAT_REMSET_CLASS: return "remset-class";
106 case INTERNAL_MEM_GRAY_QUEUE: return "gray-queue";
107 case INTERNAL_MEM_MS_TABLES: return "marksweep-tables";
108 case INTERNAL_MEM_MS_BLOCK_INFO: return "marksweep-block-info";
109 case INTERNAL_MEM_MS_BLOCK_INFO_SORT: return "marksweep-block-info-sort";
110 case INTERNAL_MEM_EPHEMERON_LINK: return "ephemeron-link";
111 case INTERNAL_MEM_WORKER_DATA: return "worker-data";
112 case INTERNAL_MEM_WORKER_JOB_DATA: return "worker-job-data";
113 case INTERNAL_MEM_BRIDGE_DATA: return "bridge-data";
114 case INTERNAL_MEM_OLD_BRIDGE_HASH_TABLE: return "old-bridge-hash-table";
115 case INTERNAL_MEM_OLD_BRIDGE_HASH_TABLE_ENTRY: return "old-bridge-hash-table-entry";
116 case INTERNAL_MEM_BRIDGE_HASH_TABLE: return "bridge-hash-table";
117 case INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY: return "bridge-hash-table-entry";
118 case INTERNAL_MEM_TARJAN_BRIDGE_HASH_TABLE: return "tarjan-bridge-hash-table";
119 case INTERNAL_MEM_TARJAN_BRIDGE_HASH_TABLE_ENTRY: return "tarjan-bridge-hash-table-entry";
120 case INTERNAL_MEM_TARJAN_OBJ_BUCKET: return "tarjan-bridge-object-buckets";
121 case INTERNAL_MEM_BRIDGE_ALIVE_HASH_TABLE: return "bridge-alive-hash-table";
122 case INTERNAL_MEM_BRIDGE_ALIVE_HASH_TABLE_ENTRY: return "bridge-alive-hash-table-entry";
123 case INTERNAL_MEM_BRIDGE_DEBUG: return "bridge-debug";
124 case INTERNAL_MEM_JOB_QUEUE_ENTRY: return "job-queue-entry";
125 case INTERNAL_MEM_TOGGLEREF_DATA: return "toggleref-data";
126 case INTERNAL_MEM_CARDTABLE_MOD_UNION: return "cardtable-mod-union";
127 case INTERNAL_MEM_BINARY_PROTOCOL: return "binary-protocol";
129 g_assert_not_reached ();
134 sgen_alloc_internal_dynamic (size_t size, int type, gboolean assert_on_failure)
139 if (size > allocator_sizes [NUM_ALLOCATORS - 1]) {
140 p = sgen_alloc_os_memory (size, SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE, NULL);
142 sgen_assert_memory_alloc (NULL, size, description_for_type (type));
144 index = index_for_size (size);
146 p = mono_lock_free_alloc (&allocators [index]);
148 sgen_assert_memory_alloc (NULL, size, description_for_type (type));
152 MONO_GC_INTERNAL_ALLOC ((mword)p, size, type);
157 sgen_free_internal_dynamic (void *addr, size_t size, int type)
162 if (size > allocator_sizes [NUM_ALLOCATORS - 1])
163 sgen_free_os_memory (addr, size, SGEN_ALLOC_INTERNAL);
165 mono_lock_free_free (addr);
167 MONO_GC_INTERNAL_DEALLOC ((mword)addr, size, type);
171 sgen_alloc_internal (int type)
173 int index = fixed_type_allocator_indexes [type];
174 int size = allocator_sizes [index];
176 g_assert (index >= 0 && index < NUM_ALLOCATORS);
177 p = mono_lock_free_alloc (&allocators [index]);
180 MONO_GC_INTERNAL_ALLOC ((mword)p, size, type);
186 sgen_free_internal (void *addr, int type)
193 index = fixed_type_allocator_indexes [type];
194 g_assert (index >= 0 && index < NUM_ALLOCATORS);
196 mono_lock_free_free (addr);
198 if (MONO_GC_INTERNAL_DEALLOC_ENABLED ()) {
199 int size G_GNUC_UNUSED = allocator_sizes [index];
200 MONO_GC_INTERNAL_DEALLOC ((mword)addr, size, type);
205 sgen_dump_internal_mem_usage (FILE *heap_dump_file)
210 fprintf (heap_dump_file, "<other-mem-usage type=\"large-internal\" size=\"%lld\"/>\n", large_internal_bytes_alloced);
211 fprintf (heap_dump_file, "<other-mem-usage type=\"pinned-chunks\" size=\"%lld\"/>\n", pinned_chunk_bytes_alloced);
212 for (i = 0; i < INTERNAL_MEM_MAX; ++i) {
213 fprintf (heap_dump_file, "<other-mem-usage type=\"%s\" size=\"%ld\"/>\n",
214 description_for_type (i), unmanaged_allocator.small_internal_mem_bytes [i]);
220 sgen_report_internal_mem_usage (void)
222 /* FIXME: implement */
223 printf ("not implemented yet\n");
227 sgen_init_internal_allocator (void)
231 for (i = 0; i < INTERNAL_MEM_MAX; ++i)
232 fixed_type_allocator_indexes [i] = -1;
234 for (i = 0; i < NUM_ALLOCATORS; ++i) {
235 mono_lock_free_allocator_init_size_class (&size_classes [i], allocator_sizes [i]);
236 mono_lock_free_allocator_init_allocator (&allocators [i], &size_classes [i]);