If request's object size is know at compile time than zone where it will be placed can be determined at this time.
There was added a wrapper which determines, whether size is constant or variable. It works similarly to linux's kmalloc in linux/slab_def.h To some of variables which don't change their value after initialization where added const specifier. Signed-off-by: Maksym Planeta <mcsim.plan...@gmail.com> --- kern/kalloc.c | 80 +---------------------------------------- kern/kalloc.h | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++- kern/zone_sizes.h | 17 +++++++++ 3 files changed, 120 insertions(+), 80 deletions(-) create mode 100644 kern/zone_sizes.h diff --git a/kern/kalloc.c b/kern/kalloc.c index 4460d59..db794b8 100644 --- a/kern/kalloc.c +++ b/kern/kalloc.c @@ -39,66 +39,10 @@ #include <mach/vm_param.h> #include <kern/debug.h> -#include <kern/zalloc.h> #include <kern/kalloc.h> -#include <vm/vm_kern.h> #include <vm/vm_object.h> #include <vm/vm_map.h> - - -vm_map_t kalloc_map; -vm_size_t kalloc_map_size = 8 * 1024 * 1024; -vm_size_t kalloc_max; - -/* - * All allocations of size less than kalloc_max are rounded to the - * next highest power of 2. This allocator is built on top of - * the zone allocator. A zone is created for each potential size - * that we are willing to get in small blocks. - * - * We assume that kalloc_max is not greater than 64K; - * thus 16 is a safe array size for k_zone and k_zone_name. - */ - -int first_k_zone = -1; -struct zone *k_zone[16]; -static char *k_zone_name[16] = { - "kalloc.1", "kalloc.2", - "kalloc.4", "kalloc.8", - "kalloc.16", "kalloc.32", - "kalloc.64", "kalloc.128", - "kalloc.256", "kalloc.512", - "kalloc.1024", "kalloc.2048", - "kalloc.4096", "kalloc.8192", - "kalloc.16384", "kalloc.32768" -}; - -/* - * Max number of elements per zone. zinit rounds things up correctly - * Doing things this way permits each zone to have a different maximum size - * based on need, rather than just guessing; it also - * means its patchable in case you're wrong! - */ -unsigned long k_zone_max[16] = { - 1024, /* 1 Byte */ - 1024, /* 2 Byte */ - 1024, /* 4 Byte */ - 1024, /* 8 Byte */ - 1024, /* 16 Byte */ - 4096, /* 32 Byte */ - 4096, /* 64 Byte */ - 4096, /* 128 Byte */ - 4096, /* 256 Byte */ - 1024, /* 512 Byte */ - 1024, /* 1024 Byte */ - 1024, /* 2048 Byte */ - 1024, /* 4096 Byte */ - 4096, /* 8192 Byte */ - 64, /* 16384 Byte */ - 64, /* 32768 Byte */ -}; - /* * Initialize the memory allocator. This should be called only * once on a system wide basis (i.e. first processor to get here @@ -107,10 +51,6 @@ unsigned long k_zone_max[16] = { * This initializes all of the zones. */ -#ifndef NDEBUG -static int kalloc_init_called; -#endif - void kalloc_init() { vm_offset_t min, max; @@ -121,18 +61,6 @@ void kalloc_init() kalloc_map = kmem_suballoc(kernel_map, &min, &max, kalloc_map_size, FALSE); - - /* - * Ensure that zones up to size 8192 bytes exist. - * This is desirable because messages are allocated - * with kalloc, and messages up through size 8192 are common. - */ - - if (PAGE_SIZE < 16*1024) - kalloc_max = 16*1024; - else - kalloc_max = PAGE_SIZE; - /* * Allocate a zone for each size we are going to handle. * We specify non-paged memory. @@ -142,9 +70,7 @@ void kalloc_init() k_zone[i] = 0; continue; } - if (size == MINSIZE) { - first_k_zone = i; - } + k_zone[i] = zinit(size, 0, k_zone_max[i] * size, size, size >= PAGE_SIZE ? ZONE_COLLECTABLE : 0, k_zone_name[i]); @@ -155,7 +81,7 @@ void kalloc_init() #endif } -vm_offset_t kalloc(size) +vm_offset_t __kalloc(size) vm_size_t size; { register int zindex; @@ -164,8 +90,6 @@ vm_offset_t kalloc(size) /* compute the size of the block that we will actually allocate */ - assert (kalloc_init_called); - allocsize = size; if (size < kalloc_max) { allocsize = MINSIZE; diff --git a/kern/kalloc.h b/kern/kalloc.h index a80f6db..3a6d7b2 100644 --- a/kern/kalloc.h +++ b/kern/kalloc.h @@ -28,13 +28,112 @@ #define _KERN_KALLOC_H_ #include <mach/machine/vm_types.h> +#include <kern/zalloc.h> +#include <vm/vm_kern.h> #define MINSIZE 16 -extern vm_offset_t kalloc (vm_size_t size); +vm_map_t kalloc_map; +const vm_size_t kalloc_map_size = 8 * 1024 * 1024; + +/* + * Ensure that zones up to size 8192 bytes exist. + * This is desirable because messages are allocated + * with kalloc, and messages up through size 8192 are common. + */ +const vm_size_t kalloc_max = PAGE_SIZE < 32 * 1024 ? 32 * 1024 : PAGE_SIZE; + +/* + * All allocations of size less than kalloc_max are rounded to the + * next highest power of 2. This allocator is built on top of + * the zone allocator. A zone is created for each potential size + * that we are willing to get in small blocks. + * + * We assume that kalloc_max is not greater than 64K; + * thus 16 is a safe array size for k_zone and k_zone_name. + */ + +#define ZONE(val, pow) \ + MINSIZE == val ? pow : +const int first_k_zone = +#include "zone_sizes.h" + -1; +#undef ZONE + +struct zone *k_zone[16]; + +#define ZONE(val, pow)\ + "kalloc."#val , +static char *k_zone_name[16] = { +#include "zone_sizes.h" +}; +#undef ZONE + +/* + * Max number of elements per zone. zinit rounds things up correctly + * Doing things this way permits each zone to have a different maximum size + * based on need, rather than just guessing; it also + * means its patchable in case you're wrong! + */ +const unsigned long k_zone_max[16] = { + 1024, /* 1 Byte */ + 1024, /* 2 Byte */ + 1024, /* 4 Byte */ + 1024, /* 8 Byte */ + 1024, /* 16 Byte */ + 4096, /* 32 Byte */ + 4096, /* 64 Byte */ + 4096, /* 128 Byte */ + 4096, /* 256 Byte */ + 1024, /* 512 Byte */ + 1024, /* 1024 Byte */ + 1024, /* 2048 Byte */ + 1024, /* 4096 Byte */ + 4096, /* 8192 Byte */ + 64, /* 16384 Byte */ + 64, /* 32768 Byte */ +}; + +#ifndef NDEBUG +static int kalloc_init_called; +#endif + +extern vm_offset_t __kalloc (vm_size_t size); extern vm_offset_t kget (vm_size_t size); extern void kfree (vm_offset_t data, vm_size_t size); - extern void kalloc_init (void); +inline vm_offset_t kalloc(size) + vm_size_t size; +{ + assert (kalloc_init_called); + + if (__builtin_constant_p(size)) { + int zindex = 0; + vm_offset_t addr; + + /* + * If our size is small enough, check the queue for that size + * and allocate. + */ + if (size < kalloc_max) { +#define ZONE(val, index) \ + if ((size <= val)&&(index >= first_k_zone)) \ + goto found; \ + else \ + zindex++; +#include "zone_sizes.h" +#undef CACHE + found: + addr = zalloc(k_zone[zindex]); + } else { + if (kmem_alloc_wired(kalloc_map, &addr, size) + != KERN_SUCCESS) + addr = 0; + } + return(addr); + } + return __kalloc(size); +} + #endif /* _KERN_KALLOC_H_ */ diff --git a/kern/zone_sizes.h b/kern/zone_sizes.h new file mode 100644 index 0000000..029b3bd --- /dev/null +++ b/kern/zone_sizes.h @@ -0,0 +1,17 @@ +ZONE(1, 0); +ZONE(2, 1); +ZONE(4, 2); +ZONE(8, 3); +ZONE(16, 4); +ZONE(32, 5); +ZONE(64, 6); +ZONE(128, 8); +ZONE(256, 9); +ZONE(512, 10); +ZONE(1024, 11); +ZONE(2048, 12); +ZONE(4096, 13); +ZONE(8192, 14); +ZONE(16384, 15); +ZONE(32768, 16); + -- 1.7.2.3