r411: refactored kalloc for clarity
The new version is closer to K&R's original implementation.
This commit is contained in:
parent
60485790b4
commit
11081c6c27
1
align.c
1
align.c
|
|
@ -1,5 +1,6 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include "minimap.h"
|
#include "minimap.h"
|
||||||
#include "mmpriv.h"
|
#include "mmpriv.h"
|
||||||
#include "ksw2.h"
|
#include "ksw2.h"
|
||||||
|
|
|
||||||
1
hit.c
1
hit.c
|
|
@ -1,4 +1,5 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "mmpriv.h"
|
#include "mmpriv.h"
|
||||||
#include "kalloc.h"
|
#include "kalloc.h"
|
||||||
|
|
|
||||||
244
kalloc.c
244
kalloc.c
|
|
@ -1,175 +1,144 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
|
||||||
#include "kalloc.h"
|
#include "kalloc.h"
|
||||||
|
|
||||||
/* The whole thing is: ("@" for the kheader_t of the block, "-" for free
|
/* In kalloc, a *core* is a large chunk of contiguous memory. Each core is
|
||||||
* memory, and "+" for allocated memory. One char for one unit.)
|
* associated with a master header, which keeps the size of the current core
|
||||||
|
* and the pointer to next core. Kalloc allocates small *blocks* of memory from
|
||||||
|
* the cores and organizes free memory blocks in a circular single-linked list.
|
||||||
*
|
*
|
||||||
* This region is core 1. This region is core 2.
|
* In the following diagram, "@" stands for the header of a free block (of type
|
||||||
|
* header_t), "#" for the header of an allocated block (of type size_t), "-"
|
||||||
|
* for free memory, and "+" for allocated memory.
|
||||||
*
|
*
|
||||||
* @-------@++++++@++++++++++++@------------ @----------@++++++++++++@+++++++@------------
|
* master This region is core 1. master This region is core 2.
|
||||||
* | | | |
|
* | |
|
||||||
* p=p->ptr->ptr->ptr->ptr p->ptr p->ptr->ptr p->ptr->ptr->ptr
|
* *@-------#++++++#++++++++++++@-------- *@----------#++++++++++++#+++++++@------------
|
||||||
|
* | | | |
|
||||||
|
* p=p->ptr->ptr->ptr->ptr p->ptr p->ptr->ptr p->ptr->ptr->ptr
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PTR(p) ((size_t*)((size_t*)p)[1])
|
#define MIN_CORE_SIZE 0x80000
|
||||||
|
|
||||||
typedef struct _allocated_t {
|
typedef struct header_t {
|
||||||
struct _allocated_t *next;
|
size_t size;
|
||||||
size_t *ptr;
|
struct header_t *ptr;
|
||||||
} allocated_t;
|
} header_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t base[2], *loop_head;
|
header_t base, *loop_head, *core_head; /* base is a zero-sized block always kept in the loop */
|
||||||
allocated_t list_head, *list_tail;
|
|
||||||
size_t total_allocated;
|
|
||||||
} kmem_t;
|
} kmem_t;
|
||||||
|
|
||||||
void *km_init()
|
static void panic(const char *s)
|
||||||
{
|
|
||||||
return calloc(1, sizeof(kmem_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void kerror(const char *s)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s\n", s);
|
fprintf(stderr, "%s\n", s);
|
||||||
exit(1);
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t *morecore(kmem_t *km, size_t nu)
|
void *km_init(void)
|
||||||
{
|
{
|
||||||
size_t rnu, *up;
|
return calloc(1, sizeof(kmem_t));
|
||||||
|
|
||||||
rnu = (nu + 0xfffff) & (~(size_t)0xfffff);
|
|
||||||
up = (size_t*)malloc(rnu * sizeof(size_t));
|
|
||||||
if (!up) { /* fail to allocate memory */
|
|
||||||
km_stat(km);
|
|
||||||
fprintf(stderr, "[morecore] %lu bytes requested but not available.\n", (unsigned long)rnu * sizeof(size_t));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
/* put the pointer in km->list_head */
|
|
||||||
if (km->list_tail == 0) km->list_tail = &km->list_head;
|
|
||||||
km->list_tail->ptr = up;
|
|
||||||
km->list_tail->next = (allocated_t*)calloc(1, sizeof(allocated_t));
|
|
||||||
km->list_tail = km->list_tail->next;
|
|
||||||
|
|
||||||
km->total_allocated += rnu * sizeof(size_t);
|
|
||||||
*up = rnu; /* the size of the current block, and in this case the block is the same as the new core */
|
|
||||||
kfree(km, up + 1); /* initialize the new "core" */
|
|
||||||
return km->loop_head;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void km_destroy(void *_km)
|
void km_destroy(void *_km)
|
||||||
{
|
{
|
||||||
kmem_t *km = (kmem_t*)_km;
|
kmem_t *km = (kmem_t*)_km;
|
||||||
allocated_t *p, *q;
|
header_t *p, *q;
|
||||||
if (km == 0) return;
|
if (km == NULL) return;
|
||||||
p = &km->list_head;
|
for (p = km->core_head; p != NULL;) {
|
||||||
do {
|
q = p->ptr;
|
||||||
q = p->next;
|
free(p);
|
||||||
free(p->ptr);
|
|
||||||
if (p != &km->list_head) free(p);
|
|
||||||
p = q;
|
p = q;
|
||||||
} while (p && p->next);
|
}
|
||||||
if (p != &km->list_head) free(p);
|
|
||||||
free(km);
|
free(km);
|
||||||
}
|
}
|
||||||
|
|
||||||
void kfree(void *_km, void *ap)
|
static header_t *morecore(kmem_t *km, size_t nu)
|
||||||
{
|
{
|
||||||
size_t *p, *q;
|
header_t *q;
|
||||||
|
size_t bytes, *p;
|
||||||
|
nu = (nu + 1 + (MIN_CORE_SIZE - 1)) / MIN_CORE_SIZE * MIN_CORE_SIZE; /* the first +1 for core header */
|
||||||
|
bytes = nu * sizeof(header_t);
|
||||||
|
q = (header_t*)malloc(bytes);
|
||||||
|
if (!q) panic("[morecore] insufficient memory");
|
||||||
|
q->ptr = km->core_head, q->size = nu, km->core_head = q;
|
||||||
|
p = (size_t*)(q + 1);
|
||||||
|
*p = nu - 1; /* the size of the free block; -1 because the first unit is used for the core header */
|
||||||
|
kfree(km, p + 1); /* initialize the new "core"; NB: the core header is not looped. */
|
||||||
|
return km->loop_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
void kfree(void *_km, void *ap) /* kfree() also adds a new core to the circular list */
|
||||||
|
{
|
||||||
|
header_t *p, *q;
|
||||||
kmem_t *km = (kmem_t*)_km;
|
kmem_t *km = (kmem_t*)_km;
|
||||||
|
|
||||||
if (!ap) return;
|
if (!ap) return;
|
||||||
if (km == 0) {
|
if (km == NULL) {
|
||||||
free(ap);
|
free(ap);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p = (size_t*)ap - 1; /* *p is the size of the current block */
|
p = (header_t*)((size_t*)ap - 1);
|
||||||
|
p->size = *((size_t*)ap - 1);
|
||||||
/* Find the pointer that points to the block to be freed. The following loop can stop on two conditions:
|
/* Find the pointer that points to the block to be freed. The following loop can stop on two conditions:
|
||||||
*
|
*
|
||||||
* a) "p>q && p<q->ptr": @------@++++++++@+++++++@------- @---------------@+++++++@-------
|
* a) "p>q && p<q->ptr": @------#++++++++#+++++++@------- @---------------#+++++++@-------
|
||||||
* (can also be in | | | -> | |
|
* (can also be in | | | -> | |
|
||||||
* two cores) q p q->ptr q q->ptr
|
* two cores) q p q->ptr q q->ptr
|
||||||
*
|
*
|
||||||
* @-------- @+++++++++@-------- @-------- @------------------
|
* @-------- #+++++++++@-------- @-------- @------------------
|
||||||
* | | | -> | |
|
* | | | -> | |
|
||||||
* q p q->ptr q q->ptr
|
* q p q->ptr q q->ptr
|
||||||
*
|
*
|
||||||
* b) "q>=q->ptr && (p>q || p<q->ptr)": @-------@+++++ @--------@+++++++ @-------@+++++ @----------------
|
* b) "q>=q->ptr && (p>q || p<q->ptr)": @-------#+++++ @--------#+++++++ @-------#+++++ @----------------
|
||||||
* | | | -> | |
|
* | | | -> | |
|
||||||
* q->ptr q p q->ptr q
|
* q->ptr q p q->ptr q
|
||||||
*
|
*
|
||||||
* @+++++++@----- @++++++++@------- @------------- @++++++++@-------
|
* #+++++++@----- #++++++++@------- @------------- #++++++++@-------
|
||||||
* | | | -> | |
|
* | | | -> | |
|
||||||
* p q->ptr q q->ptr q
|
* p q->ptr q q->ptr q
|
||||||
*/
|
*/
|
||||||
for (q = km->loop_head; !(p > q && p < PTR(q)); q = PTR(q))
|
for (q = km->loop_head; !(p > q && p < q->ptr); q = q->ptr)
|
||||||
if (q >= PTR(q) && (p > q || p < PTR(q))) break;
|
if (q >= q->ptr && (p > q || p < q->ptr)) break;
|
||||||
if (p + (*p) == PTR(q)) { /* two adjacent blocks, merge p and q->ptr (the 2nd and 4th cases) */
|
if (p + p->size == q->ptr) { /* two adjacent blocks, merge p and q->ptr (the 2nd and 4th cases) */
|
||||||
*p += *PTR(q); /* this is the new q->ptr size */
|
p->size += q->ptr->size;
|
||||||
p[1] = (size_t)PTR(PTR(q)); /* this is the new q->ptr->ptr */
|
p->ptr = q->ptr->ptr;
|
||||||
/* p is actually the new q->ptr. The actual change happens a few lines below. */
|
} else if (p + p->size > q->ptr && q->ptr >= p) {
|
||||||
} else if (p + (*p) > PTR(q) && PTR(q) >= p) { /* the end of the allocated block is in the next free block */
|
panic("[kfree] The end of the allocated block enters a free block.");
|
||||||
kerror("[kfree] The end of the allocated block enters a free block.");
|
} else p->ptr = q->ptr; /* backup q->ptr */
|
||||||
} else p[1] = (size_t)PTR(q); /* backup q->ptr */
|
|
||||||
|
|
||||||
if (q + (*q) == p) { /* two adjacent blocks, merge q and p (the other two cases) */
|
if (q + q->size == p) { /* two adjacent blocks, merge q and p (the other two cases) */
|
||||||
*q += *p;
|
q->size += p->size;
|
||||||
q[1] = (size_t)PTR(p);
|
q->ptr = p->ptr;
|
||||||
km->loop_head = q;
|
km->loop_head = q;
|
||||||
} else if (q + (*q) > p && p >= q) { /* the end of a free block in the allocated block */
|
} else if (q + q->size > p && p >= q) {
|
||||||
kerror("[kfree] The end of a free block enters the allocated block.");
|
panic("[kfree] The end of a free block enters the allocated block.");
|
||||||
} else km->loop_head = p, q[1] = (size_t)p; /* in two cores, cannot be merged */
|
} else km->loop_head = p, q->ptr = p; /* in two cores, cannot be merged; create a new block in the list */
|
||||||
}
|
|
||||||
|
|
||||||
void *krealloc(void *_km, void *ap, size_t n_bytes)
|
|
||||||
{
|
|
||||||
kmem_t *km = (kmem_t*)_km;
|
|
||||||
size_t n_units, *p, *q;
|
|
||||||
|
|
||||||
if (n_bytes == 0) {
|
|
||||||
kfree(km, ap); return 0;
|
|
||||||
}
|
|
||||||
if (km == 0) return realloc(ap, n_bytes);
|
|
||||||
if (!ap) return kmalloc(km, n_bytes);
|
|
||||||
n_units = 1 + (n_bytes + sizeof(size_t) - 1) / sizeof(size_t);
|
|
||||||
p = (size_t*)ap - 1;
|
|
||||||
if (*p >= n_units) return ap; /* TODO: this prevents shrinking */
|
|
||||||
q = (size_t*)kmalloc(km, n_bytes);
|
|
||||||
memcpy(q, ap, (*p - 1) * sizeof(size_t));
|
|
||||||
kfree(km, ap);
|
|
||||||
return q;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *kmalloc(void *_km, size_t n_bytes)
|
void *kmalloc(void *_km, size_t n_bytes)
|
||||||
{
|
{
|
||||||
kmem_t *km = (kmem_t*)_km;
|
kmem_t *km = (kmem_t*)_km;
|
||||||
size_t n_units, *p, *q;
|
size_t n_units;
|
||||||
|
header_t *p, *q;
|
||||||
|
|
||||||
if (n_bytes == 0) return 0;
|
if (n_bytes == 0) return 0;
|
||||||
if (km == 0) return malloc(n_bytes);
|
if (km == NULL) return malloc(n_bytes);
|
||||||
/* "n_units" means the number of units. The size of one unit equals to sizeof(kheader_t).
|
n_units = (n_bytes + sizeof(size_t) + sizeof(header_t) - 1) / sizeof(header_t) + 1;
|
||||||
* "1" is the kheader_t of a block, which is always required. */
|
|
||||||
n_units = 1 + (n_bytes + sizeof(size_t) - 1) / sizeof(size_t);
|
|
||||||
if (n_units&1) ++n_units; /* make n_units an even number, or it will segfault if only one unit remains */
|
|
||||||
|
|
||||||
if (!(q = km->loop_head)) { /* the first time when kmalloc() is called, intialization */
|
if (!(q = km->loop_head)) /* the first time when kmalloc() is called, intialize it */
|
||||||
km->base[1] = (size_t)(km->loop_head = q = km->base); *q = 0;
|
q = km->loop_head = km->base.ptr = &km->base;
|
||||||
}
|
for (p = q->ptr;; q = p, p = p->ptr) { /* search for a suitable block */
|
||||||
for (p = PTR(q);; q = p, p = PTR(p)) { /* search for a suitable block */
|
if (p->size >= n_units) { /* p->size if the size of current block. This line means the current block is large enough. */
|
||||||
if (*p >= n_units) { /* p->size if the size of current block. This line means the current block is large enough. */
|
if (p->size == n_units) q->ptr = p->ptr; /* no need to split the block */
|
||||||
if (*p == n_units) q[1] = (size_t)PTR(p); /* no need to split the block */
|
else { /* split the block. NB: memory is allocated at the end of the block! */
|
||||||
else { /* split the block */
|
p->size -= n_units; /* reduce the size of the free block */
|
||||||
/* memory is allocated at the end of the block */
|
p += p->size; /* p points to the allocated block */
|
||||||
*p -= n_units; /* reduce the size of the free block */
|
*(size_t*)p = n_units; /* set the size */
|
||||||
p += *p; /* skip to the kheader_t of the allocated block */
|
|
||||||
*p = n_units; /* set the size */
|
|
||||||
}
|
}
|
||||||
km->loop_head = q; /* set the end of chain */
|
km->loop_head = q; /* set the end of chain */
|
||||||
return p + 1; /* skip the kheader_t */
|
return (size_t*)p + 1;
|
||||||
}
|
}
|
||||||
if (p == km->loop_head) { /* then ask for more "cores" */
|
if (p == km->loop_head) { /* then ask for more "cores" */
|
||||||
if ((p = morecore(km, n_units)) == 0) return 0;
|
if ((p = morecore(km, n_units)) == 0) return 0;
|
||||||
|
|
@ -182,33 +151,44 @@ void *kcalloc(void *_km, size_t count, size_t size)
|
||||||
kmem_t *km = (kmem_t*)_km;
|
kmem_t *km = (kmem_t*)_km;
|
||||||
void *p;
|
void *p;
|
||||||
if (size == 0 || count == 0) return 0;
|
if (size == 0 || count == 0) return 0;
|
||||||
if (km == 0) return calloc(count, size);
|
if (km == NULL) return calloc(count, size);
|
||||||
p = kmalloc(km, count * size);
|
p = kmalloc(km, count * size);
|
||||||
memset(p, 0, count * size);
|
memset(p, 0, count * size);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void km_stat(const void *_km)
|
void *krealloc(void *_km, void *ap, size_t n_bytes) // TODO: this can be made more efficient in principle
|
||||||
{
|
{
|
||||||
kmem_t *km = (kmem_t*)_km;
|
kmem_t *km = (kmem_t*)_km;
|
||||||
unsigned n_blocks, n_units;
|
size_t n_units, *p, *q;
|
||||||
size_t max_block = 0, *p, *q;
|
|
||||||
float frag;
|
|
||||||
|
|
||||||
if (km == 0 || !(p = km->loop_head)) return;
|
if (n_bytes == 0) {
|
||||||
n_blocks = n_units = 0;
|
kfree(km, ap); return 0;
|
||||||
do {
|
}
|
||||||
q = PTR(p);
|
if (km == NULL) return realloc(ap, n_bytes);
|
||||||
if (*p > max_block) max_block = *p;
|
if (ap == NULL) return kmalloc(km, n_bytes);
|
||||||
n_units += *p;
|
n_units = (n_bytes + sizeof(size_t) + sizeof(header_t) - 1) / sizeof(header_t);
|
||||||
if (p + (*p) > q && q > p)
|
p = (size_t*)ap - 1;
|
||||||
kerror("[kr_stat] The end of a free block enters another free block.");
|
if (*p >= n_units) return ap; /* TODO: this prevents shrinking */
|
||||||
p = q;
|
q = (size_t*)kmalloc(km, n_bytes);
|
||||||
++n_blocks;
|
memcpy(q, ap, (*p - 1) * sizeof(header_t));
|
||||||
} while (p != km->loop_head);
|
kfree(km, ap);
|
||||||
|
return q;
|
||||||
--n_blocks;
|
}
|
||||||
frag = 1.0/1024.0 * n_units * sizeof(size_t) / n_blocks;
|
|
||||||
fprintf(stderr, "[kr_stat] tot=%lu, free=%lu, n_block=%u, max_block=%lu, frag_len=%.3fK\n",
|
void km_stat(const void *_km, km_stat_t *s)
|
||||||
(unsigned long)km->total_allocated, (unsigned long)n_units * sizeof(size_t), n_blocks, (unsigned long)max_block * sizeof(size_t), frag);
|
{
|
||||||
|
kmem_t *km = (kmem_t*)_km;
|
||||||
|
header_t *p;
|
||||||
|
memset(s, 0, sizeof(km_stat_t));
|
||||||
|
if (km == NULL || km->loop_head == NULL) return;
|
||||||
|
for (p = km->loop_head;; p = p->ptr) {
|
||||||
|
s->available += p->size * sizeof(header_t);
|
||||||
|
if (p->size != 0) ++s->n_blocks; /* &kmem_t::base is always one of the cores. It is zero-sized. */
|
||||||
|
if (p->ptr > p && p + p->size > p->ptr)
|
||||||
|
panic("[km_stat] The end of a free block enters another free block.");
|
||||||
|
if (p->ptr == km->loop_head) break;
|
||||||
|
}
|
||||||
|
for (p = km->core_head; p != NULL; p = p->ptr)
|
||||||
|
++s->n_cores, s->capacity += p->size * sizeof(header_t);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
kalloc.h
11
kalloc.h
|
|
@ -1,14 +1,16 @@
|
||||||
#ifndef _KALLOC_H_
|
#ifndef _KALLOC_H_
|
||||||
#define _KALLOC_H_
|
#define _KALLOC_H_
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stddef.h> /* for size_t */
|
||||||
|
|
||||||
#define km_size(x) (*(((size_t*)(x))-1) * sizeof(size_t))
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t capacity, available, n_blocks, n_cores;
|
||||||
|
} km_stat_t;
|
||||||
|
|
||||||
void *kmalloc(void *km, size_t size);
|
void *kmalloc(void *km, size_t size);
|
||||||
void *krealloc(void *km, void *ptr, size_t size);
|
void *krealloc(void *km, void *ptr, size_t size);
|
||||||
void *kcalloc(void *km, size_t count, size_t size);
|
void *kcalloc(void *km, size_t count, size_t size);
|
||||||
|
|
@ -16,8 +18,7 @@ void kfree(void *km, void *ptr);
|
||||||
|
|
||||||
void *km_init(void);
|
void *km_init(void);
|
||||||
void km_destroy(void *km);
|
void km_destroy(void *km);
|
||||||
|
void km_stat(const void *_km, km_stat_t *s);
|
||||||
void km_stat(const void *km); // TODO: return numbers instead of print to stderr
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue