最佳适配内存分配算法(二)
上次的blog
http://blog.csdn.net/leeshuheng/article/details/6736194
中的代码对最佳适配内存分配算法做了简单的演绎。
由于现实中程序经常分配小内存块,且常常重复分配和释放相同
大小的内存块,所以下面的代码对上述blog中代码做了如下优化,
具体内容请看后面的代码:
1. 每次free内存后,并未马上将其和临近的空闲
内存合并,而是直接插入bin中。直到free的
调用次数达到某个值,才进行内存块合并,这时
只合并大内存块;
2. 当由于没有大的空闲内存块而无法满足内存分配时,
进行空闲内存块合并,包括大内存块和小内存块
的合并;
3. 对大空闲块和小空闲块的查找做了不同处理;
4. 对锁进行了重新设计;
由于只是用于实验的原型代码,所以下面的代码存在如下问题:
1.对多进程和多线程支持的不好。
2.mem_alloc返回的是内存的偏移,而不是指针。
这主要是考虑了对共享内存的分配。
3.内存块散列的不好,大约有20个槽总是空的。
4.代码没经过仔细编写。许多代码是临时写的。
整个main.c中代码都是临时拼凑的。
代码显得凌乱,程序有bug。
5.还存在其他问题。
代码并未真正分配内存,只是在已分配的内存上作切割,是个
池式共享内存分配器。
代码在fedora 11上做了简单的测试。
编译: 使用make
执行: ./mytest 1
停止: Ctrl-C
下面是代码:
mem_alloc.h:
===========================================================
// 2011年 08月 24日 星期三 09:10:32 CST
// author: 李小丹(Li Shao Dan) 字殊恒(shuheng)
// K.I.S.S
// S.P.O.T
#ifndef MEM_ALLOC_H
#define MEM_ALLOC_H
#include <sys/ipc.h>
//#define SINGLE_PROCESS
#ifdef __cplusplus
extern "C" {
#endif
struct mem_info;
struct mem_info *mem_link_shm(key_t, size_t, int);
int mem_detach_shm(struct mem_info *);
struct mem_info *mem_init(void *, unsigned long, int);
void mem_destroy(struct mem_info *);
unsigned long mem_alloc(struct mem_info *, unsigned long);
void mem_free(struct mem_info *, unsigned long);
unsigned long mem_ptr_2_off(struct mem_info *, void *);
void *mem_off_2_ptr(struct mem_info *, unsigned long);
#ifdef __cplusplus
}
#endif
#endif
===========================================================
mem_alloc.c:
===========================================================
// 2011年 08月 24日 星期三 09:19:52 CST
// author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
// K.I.S.S
// S.P.O.T
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/shm.h>
#include "mem_alloc.h"
//#include "futex.h"
#include "mem_lock.h"
#ifdef SINGLE_PROCESS
#pragma message "not use lock"
#undef mem_lock_init
#undef mem_lock_lock
#undef mem_lock_unlock
//#undef futex_create
#define mem_lock_init(x)
#define mem_lock_lock(x)
#define mem_lock_unlock(x)
//#define futex_create(x)
#endif
#define BIN_NUMBER 128UL
#define BIN_SMALL_THRESHOLD 64
#define SIZE_SMALL_THRESHOLD 512UL
#define BIN_SIZE \
(unsigned long)(BIN_NUMBER * sizeof(unsigned long))
//#define LOW_SIZE (BIN_SIZE + sizeof(futex_t))
#define LOW_SIZE (BIN_SIZE + sizeof(mem_lock_t))
#define SMALLEST_SIZE \
((unsigned long)(sizeof(unsigned long) << 2))
#define CHAR_BIT_SHIFT 3
#define BIGBIN_SHIFT 8U
#define SMALL_SIZE_2_INDEX(x) (x >> CHAR_BIT_SHIFT)
#define BIG_SIZE_2_INDEX(s, i) \
{\
unsigned long x = s >> BIGBIN_SHIFT;\
if (x == 0)\
i = 0;\
else {\
unsigned long y = \
((unsigned long)sizeof(unsigned long)) \
* __CHAR_BIT__ - 1 - __builtin_clz(x); \
i = (int)((y << 1) + ((s >> (y + (BIGBIN_SHIFT - 1)))));\
i += BIN_SMALL_THRESHOLD; \
}\
}
#define TAG_SIZE (sizeof(unsigned long) << 1)
#define node_size(x) \
((x) & ~(1UL << ((sizeof(unsigned long) << CHAR_BIT_SHIFT) - 1)))
#define node_isused(x) \
((x) & (1UL << ((sizeof(unsigned long) << CHAR_BIT_SHIFT) - 1)))
#define node_used(x) \
((x) |= (1UL << ((sizeof(unsigned long) << CHAR_BIT_SHIFT) - 1)))
#define node_unused(x) \
((x) &= ~(1UL << ((sizeof(unsigned long) << CHAR_BIT_SHIFT) - 1)))
#define off_to_addr(x, y) ((x)->mem_block + (y))
#define off_to_node(p, off) \
(off ? (struct mem_node *)(p + off) : 0)
#define ptr_to_off(p, n) ((void *)n - (void *)p)
#define node_to_tail(p, s) \
(((void *)p) + s - sizeof(unsigned long))
#define node_tail_size(p, s) \
(*(unsigned long *)node_to_tail(p, s))
#define node_head_size(p) (*(unsigned long *)p)
#define node_prev_size(p) \
(*(unsigned long *)((void *)p - sizeof(unsigned long)))
#define node_to_next(p, s) (((void *)p) + s)
#define node_to_prev(p, n) \
((void *)n <= (void *)p + LOW_SIZE ? \
0 : ((void *)n) - node_prev_size(n))
#define node_list_next(p, node) \
(node->next ? \
(struct mem_node *)(p + node->next) : 0)
#define node_list_prev(p, node) \
(node->prev ? \
(struct mem_node *)(p + node->prev) : 0)
#define number_align(x, y) (((x) + (y) - 1) & ~((y) - 1))
#define align_8(x) number_align(x, 8)
struct mem_node {
unsigned long use_a_size;
unsigned long prev;
unsigned long next;
};
struct mem_info {
void *mem_block;
unsigned long block_size;
//futex_t *futex;
mem_lock_t *lock;
//long error;
int shmid;
unsigned long *mem_bin;
};
inline static unsigned long size_2_index(unsigned long);
inline static void __node_init(
struct mem_node *, unsigned long);
inline static int __node_insert(
struct mem_info *, unsigned long);
inline static unsigned long __node_merge(
struct mem_info *, unsigned long);
inline static unsigned long __node_merge_core(
struct mem_info *, unsigned long);
inline static unsigned long __node_merge_next(
struct mem_info *, unsigned long);
inline static int __node_can_merge_next(
struct mem_info *, unsigned long);
inline static unsigned long __node_merge_prev(
struct mem_info *, unsigned long);
inline static unsigned long __node_can_merge_prev(
struct mem_info *, unsigned long);
inline static unsigned long __node_remove(
struct mem_info *, unsigned long);
inline static unsigned long __node_split(
struct mem_info *,
unsigned long,
unsigned long);
inline static unsigned long __node_find(
struct mem_info *, unsigned long);
static struct mem_node *__node_find_min(
void *, unsigned long *, unsigned long);
#ifdef SMALL_SIZE_BOOST
static void __node_merge_all(struct mem_info *, int, int);
static struct mem_node *__node_find_low(
void *, unsigned long *, unsigned long, unsigned long);
static struct mem_node *__node_find_high(
void *, unsigned long *, unsigned long, unsigned long);
#endif
inline static unsigned long size_2_index(unsigned long s)
{
int idx;
if(s <= SIZE_SMALL_THRESHOLD)
idx = SMALL_SIZE_2_INDEX(s);
else
BIG_SIZE_2_INDEX(s, idx);
return idx;
}
static void __node_init(struct mem_node *p, unsigned long s)
{
p->use_a_size = s;
p->next = p->prev = 0;
node_tail_size(p, s) = s;
}
inline static int __node_insert(
struct mem_info *info, unsigned long off)
{
struct mem_node *p = info->mem_block + off;
p->next = p->prev = 0;
unsigned long s = node_size(p->use_a_size);
int idx = size_2_index(s);
p->next = info->mem_bin[idx];
info->mem_bin[idx] = off;
if(p->next) {
struct mem_node *next =
(struct mem_node *)
off_to_addr(info, p->next);
next->prev = off;
}
return 0;
}
inline static unsigned long __node_merge(
struct mem_info *info, unsigned long off)
{
off = __node_merge_core(info, off);
assert(off);
/*void *p = info->mem_block;
struct mem_node *node =
(struct mem_node *)(p + off);
node->prev = node->next = 0;*/
return off;
}
inline static unsigned long __node_merge_core(
struct mem_info *info, unsigned long off)
{
off = __node_merge_next(info, off);
off = __node_merge_prev(info, off);
return off;
}
inline static unsigned long __node_can_merge_prev(
struct mem_info *info, unsigned long off)
{
if(off >= LOW_SIZE) {
void *p = info->mem_block;
struct mem_node *node =
(struct mem_node *)(p + off);
//unsigned long cs = node_size(node->use_a_size);
struct mem_node *prev = node_to_prev(p, node);
void *high = p + LOW_SIZE;
if((void *)prev < high)
return 0;
return !node_isused(prev->use_a_size);
}
return 0;
}
inline static unsigned long __node_merge_prev(
struct mem_info *info, unsigned long off)
{
if(off >= LOW_SIZE) {
void *p = info->mem_block;
struct mem_node *node =
(struct mem_node *)(p + off);
unsigned long cs = node_size(node->use_a_size);
struct mem_node *prev = node_to_prev(p, node);
void *high = p + LOW_SIZE;
if((void *)prev < high)
return off;
if(!node_isused(prev->use_a_size)) {
unsigned long ps =
node_size(prev->use_a_size);
assert(ps);
__node_remove(info, off - ps);
unsigned long sum = cs + ps;
node_tail_size(prev, sum) = sum;
prev->use_a_size = sum;
return __node_merge_prev(info, off - ps);
}
return off;
}
assert(0);
return 0;
}
#ifdef SMALL_SIZE_BOOST
static void __node_merge_all(struct mem_info *info, int b, int e)
{
unsigned long *bin = info->mem_bin;
void *p = info->mem_block;
for(int i = b; i < e; ++i) {
for(struct mem_node *n =
off_to_node(p, bin[i]); n;) {
unsigned long off = ptr_to_off(p, n);
if(__node_can_merge_prev(info, off) ||
__node_can_merge_next(info, off)) {
__node_remove(info, off);
off = __node_merge(info, off);
__node_insert(info, off);
n = off_to_node(p, bin[i]);
} else {
n = node_list_next(p, n);
}
}
}
}
#endif
inline static int __node_can_merge_next(
struct mem_info *info, unsigned long off)
{
if(off < info->block_size) {
void *p = info->mem_block;
struct mem_node *node =
(struct mem_node *)(p + off);
unsigned long cs = node_size(node->use_a_size);
unsigned long hs = info->block_size;
if(off + cs >= hs)
return 0;
struct mem_node *next =
(struct mem_node *)node_to_next(
node, cs);
return !node_isused(next->use_a_size);
}
return 0;
}
inline static unsigned long __node_merge_next(
struct mem_info *info, unsigned long off)
{
if(off < info->block_size) {
void *p = info->mem_block;
struct mem_node *node =
(struct mem_node *)(p + off);
unsigned long cs = node_size(node->use_a_size);
unsigned long hs = info->block_size;
if(off + cs >= hs)
return off;
struct mem_node *next =
(struct mem_node *)node_to_next(
node, cs);
if(!node_isused(next->use_a_size)) {
__node_remove(info, off + cs);
unsigned long ns = node_size(
next->use_a_size);
assert(ns);
unsigned long sum = cs + ns;
node->use_a_size = sum;
node_tail_size(node, sum) = sum;
return __node_merge_next(
info, off);
}
return off;
}
assert(0);
return 0;
}
inline static unsigned long __node_remove(
struct mem_info *info, unsigned long off)
{
void *p = info->mem_block;
struct mem_node *node =
(struct mem_node *)(p + off);
if(node->prev) {
struct mem_node *prev =
(struct mem_node *)(p + node->prev);
prev->next = node->next;
} else {
unsigned long s = node_size(node->use_a_size);
int idx = size_2_index(s);
unsigned long *bin = info->mem_bin;
bin[idx] = node->next;
}
if(node->next) {
struct mem_node *next =
(struct mem_node *)(p + node->next);
next->prev = node->prev;
}
node->prev = node->next = 0;
return off;
}
inline static unsigned long __node_split(
struct mem_info *info,
unsigned long off,
unsigned long s)
{
void *p = info->mem_block;
struct mem_node *node =
(struct mem_node *)(p + off);
unsigned long ns = node_size(node->use_a_size);
if(s + SMALLEST_SIZE >= ns)
return off;
node->use_a_size = s;
node_tail_size(node, s) = s;
struct mem_node *next =
(struct mem_node *)node_to_next(node, s);
ns -= s;
next->use_a_size = ns;
node_tail_size(next, ns) = ns;
__node_insert(info, off + s);
return off;
}
static struct mem_node *__node_find_min(
void *p, unsigned long *bin, unsigned long s)
{
#ifdef SMALL_SIZE_BOOST
int idx = size_2_index(s);
struct mem_node *node = 0;
if(idx <= BIN_SMALL_THRESHOLD)
node = __node_find_low(p, bin, idx, s);
return (node ? node : __node_find_high(p, bin, idx, s));
#else
int idx = size_2_index(s);
struct mem_node *node, *nmin = 0;
unsigned long min, tmp;
for(unsigned i = idx; i < BIN_NUMBER; ++i) {
node = off_to_node(p, bin[i]);
if(node) min = node_size(node->use_a_size) + 1;
for(; node; node = node_list_next(p, node)) {
tmp = node_size(node->use_a_size);
if(tmp >= s && tmp < min) {
nmin = node;
min = tmp;
}
}
if(nmin)
return nmin;
}
return 0;
#endif
}
#ifdef SMALL_SIZE_BOOST
static struct mem_node *__node_find_high(
void *p, unsigned long *bin, unsigned long idx, unsigned long s)
{
//int idx = size_2_index(s);
struct mem_node *node, *nmin = 0;
unsigned long min, tmp;
for(unsigned i = idx; i < BIN_NUMBER; ++i) {
node = off_to_node(p, bin[i]);
if(node) min = node_size(node->use_a_size) + 1;
for(; node; node = node_list_next(p, node)) {
tmp = node_size(node->use_a_size);
if(tmp >= s && tmp < min) {
nmin = node;
min = tmp;
}
}
if(nmin)
return nmin;
}
return 0;
}
static struct mem_node *__node_find_low(
void *p, unsigned long *bin, unsigned long idx, unsigned long s)
{
//int idx = size_2_index(s);
struct mem_node *node;
for(unsigned long i = idx; i <= BIN_SMALL_THRESHOLD; ++i) {
for(node = off_to_node(p, bin[i]); node;
node = node_list_next(p, node)) {
if(node_size(node->use_a_size) >= s)
return node;
}
}
return 0;
}
#endif
// XXX hot spot
inline static unsigned long __node_find(
struct mem_info *info, unsigned long s)
{
unsigned long *bin = info->mem_bin;
void *p = info->mem_block;
struct mem_node *node;
#ifdef SMALL_SIZE_BOOST
int m = 2;
while(m){
#endif
if((node = __node_find_min(p, bin, s))) {
unsigned long ret = (void *)node - p;
unsigned long ns = node_size(node->use_a_size);
__node_remove(info, ret);
if(ns > s)
ret = __node_split(info, ret, s);
return ret;
}
//break;
#ifdef SMALL_SIZE_BOOST
if(--m) __node_merge_all(info, 0, (int)BIN_NUMBER);
//printf("%s: %s: %d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__);
}
#endif
return 0;
}
unsigned long mem_alloc(struct mem_info *info, unsigned long s)
{
if(!s) return 0;
if((s = align_8(s + TAG_SIZE)) < SMALLEST_SIZE)
s = SMALLEST_SIZE;
unsigned long off;
//futex_lock(info->futex);
mem_lock_lock(info->lock);
if(!(off = __node_find(info, s))) {
//futex_unlock(info->futex);
mem_lock_unlock(info->lock);
return 0;
}
struct mem_node *node =
off_to_node(info->mem_block, off);
node_used(node->use_a_size);
//futex_unlock(info->futex);
mem_lock_unlock(info->lock);
return off + sizeof(unsigned long);
}
void mem_free(struct mem_info *info, unsigned long off)
{
off -= sizeof(unsigned long);
assert(off >= LOW_SIZE);
assert(off < info->block_size);
struct mem_node *node =
off_to_node(info->mem_block, off);
//futex_lock(info->futex);
mem_lock_lock(info->lock);
node_unused(node->use_a_size);
//node->prev = node->next = 0;
#ifndef SMALL_SIZE_BOOST
off = __node_merge(info, off);
#endif
__node_insert(info, off);
#ifdef SMALL_SIZE_BOOST
static int count = 0;
if(++count == 70) {
count = 0;
//printf("%s: %s: %d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__);
__node_merge_all(info, BIN_SMALL_THRESHOLD, (int)BIN_NUMBER);
}
#endif
//futex_unlock(info->futex);
mem_lock_unlock(info->lock);
}
struct mem_info *mem_init(void *p, unsigned long s, int b)
{
if(s < LOW_SIZE + SMALLEST_SIZE)
return 0;
struct mem_info *info =
(struct mem_info *)
malloc(sizeof(struct mem_info));
//info->futex = (futex_t *)p;
info->lock = (mem_lock_t *)p;
//info->mem_bin = (unsigned long *)(p + sizeof(futex_t));
info->mem_bin = (unsigned long *)(p + sizeof(mem_lock_t));
info->mem_block = p;
info->block_size = s;
//info->error = 0;
info->shmid = -1;
//futex_create();
if(b) {
//futex_init(info->lock);
mem_lock_init(info->lock);
//futex_lock(info->futex);
mem_lock_lock(info->lock);
memset(info->mem_bin, 0, BIN_SIZE);
struct mem_node *node =
(struct mem_node *)(p + LOW_SIZE);
__node_init(node, info->block_size - LOW_SIZE);
__node_insert(info, LOW_SIZE);
//futex_unlock(info->futex);
mem_lock_unlock(info->lock);
}
return info;
}
void mem_destroy(struct mem_info *info)
{
//futex_lock(info->futex);
mem_lock_lock(info->lock);
if(info->shmid >= 0)
shmctl(info->shmid, IPC_RMID, 0);
free(info);
//futex_unlock(info->futex);
mem_lock_unlock(info->lock);
}
struct mem_info *mem_link_shm(key_t key, size_t s, int init)
{
int mid;
s += LOW_SIZE + SMALLEST_SIZE;
s = align_8(s);
if((mid = shmget(key, s, IPC_CREAT | 0666)) < 0) {
perror("shmget");
return 0;
}
void *p;
if((p = shmat(mid, 0, 0)) == (void *)-1) {
perror("shmat");
return 0;
}
struct mem_info *info =
mem_init(p, (unsigned long)s, init);
assert(info);
info->shmid = mid;
return info;
}
int mem_detach_shm(struct mem_info *info)
{
if(shmdt(info->mem_block)) {
perror("shmdt");
return -1;
}
return 0;
}
void *mem_off_2_ptr(struct mem_info *info, unsigned long off)
{
if(off >= LOW_SIZE)
return info->mem_block + off;
return 0;
}
unsigned long mem_ptr_2_off(struct mem_info *info, void *p)
{
unsigned long off;
if((off = p - info->mem_block) >= LOW_SIZE)
return off;
return 0;
}
===========================================================
mem_lock.h:
===========================================================
// 2011年 09月 13日 星期二 10:43:03 CST
// author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
// K.I.S.S
// S.P.O.T
#ifndef MEM_LOCK_H
#define MEM_LOCK_H
#include <unistd.h>
#include <sched.h>
#include <sys/syscall.h>
typedef struct __mem_lock {
unsigned long tid;
unsigned long lock;
} mem_lock_t;
inline static int mem_lock_init(mem_lock_t *);
inline static int mem_lock_lock(mem_lock_t *);
inline static int mem_lock_unlock(mem_lock_t *);
inline static int mem_lock_init(mem_lock_t *lk)
{
lk->tid = 0;
lk->lock = 0;
return 0;
}
#define SPIN_YIELD_INTERVAL 31U
inline static int mem_lock_lock(mem_lock_t *lk)
{
pid_t now = syscall(SYS_gettid);
pid_t old =
(pid_t)__sync_and_and_fetch(&lk->tid, ~0UL);
//if(__sync_bool_compare_and_swap(
// &lk->tid, now, now))
if(old == now)
return 1;
int c = 0;
while(__sync_lock_test_and_set(
&lk->lock, 1)) {
if(!(++c & SPIN_YIELD_INTERVAL))
sched_yield();
}
lk->tid = (unsigned long)now;
return 0;
}
inline static int mem_lock_unlock(mem_lock_t *lk)
{
unsigned long now =
(unsigned long)syscall(SYS_gettid);
unsigned long old =
__sync_and_and_fetch(&lk->tid, ~0UL);
//if(!__sync_bool_compare_and_swap(
// &lk->tid, now, now))
if(old != now)
return -1;
lk->tid = 0;
__sync_lock_release(&lk->lock);
return 0;
}
#endif
===========================================================
main.c:
===========================================================
// 2011年 08月 26日 星期五 10:17:33 CST
// author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
// K.I.S.S
// S.P.O.T
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "mem_alloc.h"
#include "mem_lock.h"
//#ifndef SINGLE_PROCESS
#define BUF_SIZE (0x1FFFFFUL << 1)
//#else
//#define BUF_SIZE 0xFFFFFUL
//#endif
struct mem_info *info;
static void sig_handle(int);
void *do_work(void *);
int main(int argc, char *argv[])
{
if(argc != 2)
exit(1);
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sig_handle;
sigemptyset(&sa.sa_mask);
if(sigaction(SIGINT, &sa, 0) < 0) {
perror("sigaction");
exit(1);
}
srand(time(0));
unsigned long as = BUF_SIZE;
//void *p = malloc(as);
key_t key = ftok("./main.c", 0);
info = mem_link_shm(key, as, atoi(argv[1]));
#ifndef SINGLE_PROCESS
pthread_t tid;
pthread_create(&tid, 0, do_work, (void *)0);
#endif
//info = mem_init(p, as, 1);
assert(info);
unsigned long p1, p2, p3, p4;
unsigned long s1, s2, s3;
p1 = mem_alloc(info, 524288);
assert(p1);
char *ptr4[4];
// not free
unsigned long h1 = mem_alloc(info, 12);
ptr4[0] = mem_off_2_ptr(info, h1);
strcpy(ptr4[0], "hello,world");
p2 = mem_alloc(info, 8192);
assert(p2);
// not free
unsigned long h2 = mem_alloc(info, 12);
ptr4[1] = mem_off_2_ptr(info, h2);
strcpy(ptr4[1], "hello,world");
//
p3 = mem_alloc(info, 32768);
assert(p3);
// not free
unsigned long h3 = mem_alloc(info, 12);
ptr4[2] = mem_off_2_ptr(info, h3);
strcpy(ptr4[2], "hello,world");
/
p4 = mem_alloc(info, 65535);
assert(p4);
// not free
unsigned long h4 = mem_alloc(info, 12);
ptr4[3] = mem_off_2_ptr(info, h4);
strcpy(ptr4[3], "hello,world");
///
void *ppp = mem_off_2_ptr(info, p1);
unsigned long pp1 = mem_ptr_2_off(info, ppp);
assert(pp1 == p1);
mem_free(info, p1);
mem_free(info, p2);
mem_free(info, p3);
mem_free(info, p4);
int count = 0;
time_t cur, last = time(0);
for(;;) {
while(!(s1 = rand() % 524288)) ;
while(!(s2 = rand() % 8192)) ;
p1 = mem_alloc(info, s1);
p2 = mem_alloc(info, s2);
assert(p1);
assert(p2);
if(s1 > 16) {
char *ppp = mem_off_2_ptr(info, p1);
strcpy(ppp, "hello,world");
//printf("%s\n", ppp);
}
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
mem_free(info, p2);
mem_free(info, p1);
while(!(s1 = rand() % 32)) ;
while(!(s2 = rand() % 65535)) ;
p1 = mem_alloc(info, s1);
p2 = mem_alloc(info, s2);
assert(p1);
assert(p2);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
mem_free(info, p2);
while(!(s3 = rand() % 4096)) ;
p3 = mem_alloc(info, s3);
assert(p3);
unsigned long pp[100];
for(int i = 0; i < 100; ++i) {
while(!(s3 = rand() % 4096)) ;
//while(!(s3 = rand() % 409)) ;
pp[i] = mem_alloc(info, s3);
assert(pp[i]);
/*if(s3 > 16) {
char *ppp = mem_off_2_ptr(info, pp[i]);
strcpy(ppp, "hello,world");
//printf("%s\n", ppp);
}*/
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, pp[i]);
}
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, p3);
mem_free(info, p3);
mem_free(info, p1);
//while(!(s1 = rand() % 524288)) ;
while(!(s1 = rand() % 124288)) ;
while(!(s2 = rand() % 64)) ;
while(!(s3 = rand() % 32768)) ;
p1 = mem_alloc(info, s1);
p2 = mem_alloc(info, s2);
p3 = mem_alloc(info, s3);
assert(p1);
assert(p2);
assert(p3);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, p3);
mem_free(info, p2);
mem_free(info, p3);
for(int i = 99; i >= 0; --i)
mem_free(info, pp[i]);
mem_free(info, p1);
//static int aaaaaaa = 0;
if(++count == 100000) {
cur = time(0);
printf("XXX: %lu\n", cur - last);
for(int i = 0; i < 4; ++i)
printf("%s\n", ptr4[i]);
count = 0;
last = cur;
/*if(++aaaaaaa == 3)
exit(0);*/
}
}
return 0;
}
static void sig_handle(int s)
{
printf("\ntid is %ld\n", syscall(SYS_gettid));
psignal(s, "\ndestroy shared memory");
mem_destroy(info);
exit(0);
}
void *do_work(void *p)
{
int mi = (int)p;
unsigned long as = BUF_SIZE;
//void *p = malloc(as);
key_t key = ftok("./main.c", 0);
info = mem_link_shm(key, as, mi);
//info = mem_init(p, as, 1);
assert(info);
unsigned long p1, p2, p3, p4;
unsigned long s1, s2, s3;
p1 = mem_alloc(info, 524288);
assert(p1);
char *ptr4[4];
// not free
unsigned long h1 = mem_alloc(info, 12);
ptr4[0] = mem_off_2_ptr(info, h1);
strcpy(ptr4[0], "hello,world");
p2 = mem_alloc(info, 8192);
assert(p2);
// not free
unsigned long h2 = mem_alloc(info, 12);
ptr4[1] = mem_off_2_ptr(info, h2);
strcpy(ptr4[1], "hello,world");
//
p3 = mem_alloc(info, 32768);
assert(p3);
// not free
unsigned long h3 = mem_alloc(info, 12);
ptr4[2] = mem_off_2_ptr(info, h3);
strcpy(ptr4[2], "hello,world");
/
p4 = mem_alloc(info, 65535);
assert(p4);
// not free
unsigned long h4 = mem_alloc(info, 12);
ptr4[3] = mem_off_2_ptr(info, h4);
strcpy(ptr4[3], "hello,world");
///
void *ppp = mem_off_2_ptr(info, p1);
unsigned long pp1 = mem_ptr_2_off(info, ppp);
assert(pp1 == p1);
mem_free(info, p1);
mem_free(info, p2);
mem_free(info, p3);
mem_free(info, p4);
int count = 0;
time_t cur, last = time(0);
for(;;) {
while(!(s1 = rand() % 524288)) ;
while(!(s2 = rand() % 8192)) ;
p1 = mem_alloc(info, s1);
p2 = mem_alloc(info, s2);
assert(p1);
assert(p2);
if(s1 > 16) {
char *ppp = mem_off_2_ptr(info, p1);
strcpy(ppp, "hello,world");
//printf("%s\n", ppp);
}
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
mem_free(info, p2);
mem_free(info, p1);
while(!(s1 = rand() % 32)) ;
while(!(s2 = rand() % 65535)) ;
p1 = mem_alloc(info, s1);
p2 = mem_alloc(info, s2);
assert(p1);
assert(p2);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
mem_free(info, p2);
while(!(s3 = rand() % 4096)) ;
p3 = mem_alloc(info, s3);
assert(p3);
unsigned long pp[100];
for(int i = 0; i < 100; ++i) {
while(!(s3 = rand() % 4096)) ;
//while(!(s3 = rand() % 409)) ;
pp[i] = mem_alloc(info, s3);
assert(pp[i]);
if(s3 > 16) {
char *ppp = mem_off_2_ptr(info, pp[i]);
strcpy(ppp, "hello,world");
//printf("%s\n", ppp);
}
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, pp[i]);
}
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, p3);
mem_free(info, p3);
mem_free(info, p1);
//while(!(s1 = rand() % 524288)) ;
while(!(s1 = rand() % 124288)) ;
while(!(s2 = rand() % 64)) ;
while(!(s3 = rand() % 32768)) ;
p1 = mem_alloc(info, s1);
p2 = mem_alloc(info, s2);
p3 = mem_alloc(info, s3);
assert(p1);
assert(p2);
assert(p3);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, p3);
mem_free(info, p2);
mem_free(info, p3);
for(int i = 99; i >= 0; --i)
mem_free(info, pp[i]);
mem_free(info, p1);
//static int aaaaaaa = 0;
if(++count == 100000) {
cur = time(0);
printf("XXX: %lu\n", cur - last);
for(int i = 0; i < 4; ++i)
printf("%s\n", ptr4[i]);
count = 0;
last = cur;
/*if(++aaaaaaa == 3)
exit(0);*/
}
}
return (void *)0;
}
===========================================================
makefile:
===========================================================
mod=SMALL_SIZE_BOOST
proc=SINGLE_PROCESS
mytest: main.c mem_alloc.c mem_alloc.h mem_lock.h
gcc -std=c99 -O2 -g -W -Wall -Wextra -D_GNU_SOURCE -D$(mod) -o $@ main.c mem_alloc.c -lpthread
.PHONY:clean
clean:
-rm -rf mytest
===========================================================
上次的blog
http://blog.csdn.net/leeshuheng/article/details/6736194
中的代码对最佳适配内存分配算法做了简单的演绎。
由于现实中程序经常分配小内存块,且常常重复分配和释放相同
大小的内存块,所以下面的代码对上述blog中代码做了如下优化,
具体内容请看后面的代码:
1. 每次free内存后,并未马上将其和临近的空闲
内存合并,而是直接插入bin中。直到free的
调用次数达到某个值,才进行内存块合并,这时
只合并大内存块;
2. 当由于没有大的空闲内存块而无法满足内存分配时,
进行空闲内存块合并,包括大内存块和小内存块
的合并;
3. 对大空闲块和小空闲块的查找做了不同处理;
4. 对锁进行了重新设计;
由于只是用于实验的原型代码,所以下面的代码存在如下问题:
1.对多进程和多线程支持的不好。
2.mem_alloc返回的是内存的偏移,而不是指针。
这主要是考虑了对共享内存的分配。
3.内存块散列的不好,大约有20个槽总是空的。
4.代码没经过仔细编写。许多代码是临时写的。
整个main.c中代码都是临时拼凑的。
代码显得凌乱,程序有bug。
5.还存在其他问题。
代码并未真正分配内存,只是在已分配的内存上作切割,是个
池式共享内存分配器。
代码在fedora 11上做了简单的测试。
编译: 使用make
执行: ./mytest 1
停止: Ctrl-C
下面是代码:
mem_alloc.h:
===========================================================
// 2011年 08月 24日 星期三 09:10:32 CST
// author: 李小丹(Li Shao Dan) 字殊恒(shuheng)
// K.I.S.S
// S.P.O.T
#ifndef MEM_ALLOC_H
#define MEM_ALLOC_H
#include <sys/ipc.h>
//#define SINGLE_PROCESS
#ifdef __cplusplus
extern "C" {
#endif
struct mem_info;
struct mem_info *mem_link_shm(key_t, size_t, int);
int mem_detach_shm(struct mem_info *);
struct mem_info *mem_init(void *, unsigned long, int);
void mem_destroy(struct mem_info *);
unsigned long mem_alloc(struct mem_info *, unsigned long);
void mem_free(struct mem_info *, unsigned long);
unsigned long mem_ptr_2_off(struct mem_info *, void *);
void *mem_off_2_ptr(struct mem_info *, unsigned long);
#ifdef __cplusplus
}
#endif
#endif
===========================================================
mem_alloc.c:
===========================================================
// 2011年 08月 24日 星期三 09:19:52 CST
// author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
// K.I.S.S
// S.P.O.T
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/shm.h>
#include "mem_alloc.h"
//#include "futex.h"
#include "mem_lock.h"
#ifdef SINGLE_PROCESS
#pragma message "not use lock"
#undef mem_lock_init
#undef mem_lock_lock
#undef mem_lock_unlock
//#undef futex_create
#define mem_lock_init(x)
#define mem_lock_lock(x)
#define mem_lock_unlock(x)
//#define futex_create(x)
#endif
#define BIN_NUMBER 128UL
#define BIN_SMALL_THRESHOLD 64
#define SIZE_SMALL_THRESHOLD 512UL
#define BIN_SIZE \
(unsigned long)(BIN_NUMBER * sizeof(unsigned long))
//#define LOW_SIZE (BIN_SIZE + sizeof(futex_t))
#define LOW_SIZE (BIN_SIZE + sizeof(mem_lock_t))
#define SMALLEST_SIZE \
((unsigned long)(sizeof(unsigned long) << 2))
#define CHAR_BIT_SHIFT 3
#define BIGBIN_SHIFT 8U
#define SMALL_SIZE_2_INDEX(x) (x >> CHAR_BIT_SHIFT)
#define BIG_SIZE_2_INDEX(s, i) \
{\
unsigned long x = s >> BIGBIN_SHIFT;\
if (x == 0)\
i = 0;\
else {\
unsigned long y = \
((unsigned long)sizeof(unsigned long)) \
* __CHAR_BIT__ - 1 - __builtin_clz(x); \
i = (int)((y << 1) + ((s >> (y + (BIGBIN_SHIFT - 1)))));\
i += BIN_SMALL_THRESHOLD; \
}\
}
#define TAG_SIZE (sizeof(unsigned long) << 1)
#define node_size(x) \
((x) & ~(1UL << ((sizeof(unsigned long) << CHAR_BIT_SHIFT) - 1)))
#define node_isused(x) \
((x) & (1UL << ((sizeof(unsigned long) << CHAR_BIT_SHIFT) - 1)))
#define node_used(x) \
((x) |= (1UL << ((sizeof(unsigned long) << CHAR_BIT_SHIFT) - 1)))
#define node_unused(x) \
((x) &= ~(1UL << ((sizeof(unsigned long) << CHAR_BIT_SHIFT) - 1)))
#define off_to_addr(x, y) ((x)->mem_block + (y))
#define off_to_node(p, off) \
(off ? (struct mem_node *)(p + off) : 0)
#define ptr_to_off(p, n) ((void *)n - (void *)p)
#define node_to_tail(p, s) \
(((void *)p) + s - sizeof(unsigned long))
#define node_tail_size(p, s) \
(*(unsigned long *)node_to_tail(p, s))
#define node_head_size(p) (*(unsigned long *)p)
#define node_prev_size(p) \
(*(unsigned long *)((void *)p - sizeof(unsigned long)))
#define node_to_next(p, s) (((void *)p) + s)
#define node_to_prev(p, n) \
((void *)n <= (void *)p + LOW_SIZE ? \
0 : ((void *)n) - node_prev_size(n))
#define node_list_next(p, node) \
(node->next ? \
(struct mem_node *)(p + node->next) : 0)
#define node_list_prev(p, node) \
(node->prev ? \
(struct mem_node *)(p + node->prev) : 0)
#define number_align(x, y) (((x) + (y) - 1) & ~((y) - 1))
#define align_8(x) number_align(x, 8)
struct mem_node {
unsigned long use_a_size;
unsigned long prev;
unsigned long next;
};
struct mem_info {
void *mem_block;
unsigned long block_size;
//futex_t *futex;
mem_lock_t *lock;
//long error;
int shmid;
unsigned long *mem_bin;
};
inline static unsigned long size_2_index(unsigned long);
inline static void __node_init(
struct mem_node *, unsigned long);
inline static int __node_insert(
struct mem_info *, unsigned long);
inline static unsigned long __node_merge(
struct mem_info *, unsigned long);
inline static unsigned long __node_merge_core(
struct mem_info *, unsigned long);
inline static unsigned long __node_merge_next(
struct mem_info *, unsigned long);
inline static int __node_can_merge_next(
struct mem_info *, unsigned long);
inline static unsigned long __node_merge_prev(
struct mem_info *, unsigned long);
inline static unsigned long __node_can_merge_prev(
struct mem_info *, unsigned long);
inline static unsigned long __node_remove(
struct mem_info *, unsigned long);
inline static unsigned long __node_split(
struct mem_info *,
unsigned long,
unsigned long);
inline static unsigned long __node_find(
struct mem_info *, unsigned long);
static struct mem_node *__node_find_min(
void *, unsigned long *, unsigned long);
#ifdef SMALL_SIZE_BOOST
static void __node_merge_all(struct mem_info *, int, int);
static struct mem_node *__node_find_low(
void *, unsigned long *, unsigned long, unsigned long);
static struct mem_node *__node_find_high(
void *, unsigned long *, unsigned long, unsigned long);
#endif
inline static unsigned long size_2_index(unsigned long s)
{
int idx;
if(s <= SIZE_SMALL_THRESHOLD)
idx = SMALL_SIZE_2_INDEX(s);
else
BIG_SIZE_2_INDEX(s, idx);
return idx;
}
static void __node_init(struct mem_node *p, unsigned long s)
{
p->use_a_size = s;
p->next = p->prev = 0;
node_tail_size(p, s) = s;
}
inline static int __node_insert(
struct mem_info *info, unsigned long off)
{
struct mem_node *p = info->mem_block + off;
p->next = p->prev = 0;
unsigned long s = node_size(p->use_a_size);
int idx = size_2_index(s);
p->next = info->mem_bin[idx];
info->mem_bin[idx] = off;
if(p->next) {
struct mem_node *next =
(struct mem_node *)
off_to_addr(info, p->next);
next->prev = off;
}
return 0;
}
inline static unsigned long __node_merge(
struct mem_info *info, unsigned long off)
{
off = __node_merge_core(info, off);
assert(off);
/*void *p = info->mem_block;
struct mem_node *node =
(struct mem_node *)(p + off);
node->prev = node->next = 0;*/
return off;
}
inline static unsigned long __node_merge_core(
struct mem_info *info, unsigned long off)
{
off = __node_merge_next(info, off);
off = __node_merge_prev(info, off);
return off;
}
inline static unsigned long __node_can_merge_prev(
struct mem_info *info, unsigned long off)
{
if(off >= LOW_SIZE) {
void *p = info->mem_block;
struct mem_node *node =
(struct mem_node *)(p + off);
//unsigned long cs = node_size(node->use_a_size);
struct mem_node *prev = node_to_prev(p, node);
void *high = p + LOW_SIZE;
if((void *)prev < high)
return 0;
return !node_isused(prev->use_a_size);
}
return 0;
}
inline static unsigned long __node_merge_prev(
struct mem_info *info, unsigned long off)
{
if(off >= LOW_SIZE) {
void *p = info->mem_block;
struct mem_node *node =
(struct mem_node *)(p + off);
unsigned long cs = node_size(node->use_a_size);
struct mem_node *prev = node_to_prev(p, node);
void *high = p + LOW_SIZE;
if((void *)prev < high)
return off;
if(!node_isused(prev->use_a_size)) {
unsigned long ps =
node_size(prev->use_a_size);
assert(ps);
__node_remove(info, off - ps);
unsigned long sum = cs + ps;
node_tail_size(prev, sum) = sum;
prev->use_a_size = sum;
return __node_merge_prev(info, off - ps);
}
return off;
}
assert(0);
return 0;
}
#ifdef SMALL_SIZE_BOOST
static void __node_merge_all(struct mem_info *info, int b, int e)
{
unsigned long *bin = info->mem_bin;
void *p = info->mem_block;
for(int i = b; i < e; ++i) {
for(struct mem_node *n =
off_to_node(p, bin[i]); n;) {
unsigned long off = ptr_to_off(p, n);
if(__node_can_merge_prev(info, off) ||
__node_can_merge_next(info, off)) {
__node_remove(info, off);
off = __node_merge(info, off);
__node_insert(info, off);
n = off_to_node(p, bin[i]);
} else {
n = node_list_next(p, n);
}
}
}
}
#endif
inline static int __node_can_merge_next(
struct mem_info *info, unsigned long off)
{
if(off < info->block_size) {
void *p = info->mem_block;
struct mem_node *node =
(struct mem_node *)(p + off);
unsigned long cs = node_size(node->use_a_size);
unsigned long hs = info->block_size;
if(off + cs >= hs)
return 0;
struct mem_node *next =
(struct mem_node *)node_to_next(
node, cs);
return !node_isused(next->use_a_size);
}
return 0;
}
inline static unsigned long __node_merge_next(
struct mem_info *info, unsigned long off)
{
if(off < info->block_size) {
void *p = info->mem_block;
struct mem_node *node =
(struct mem_node *)(p + off);
unsigned long cs = node_size(node->use_a_size);
unsigned long hs = info->block_size;
if(off + cs >= hs)
return off;
struct mem_node *next =
(struct mem_node *)node_to_next(
node, cs);
if(!node_isused(next->use_a_size)) {
__node_remove(info, off + cs);
unsigned long ns = node_size(
next->use_a_size);
assert(ns);
unsigned long sum = cs + ns;
node->use_a_size = sum;
node_tail_size(node, sum) = sum;
return __node_merge_next(
info, off);
}
return off;
}
assert(0);
return 0;
}
inline static unsigned long __node_remove(
struct mem_info *info, unsigned long off)
{
void *p = info->mem_block;
struct mem_node *node =
(struct mem_node *)(p + off);
if(node->prev) {
struct mem_node *prev =
(struct mem_node *)(p + node->prev);
prev->next = node->next;
} else {
unsigned long s = node_size(node->use_a_size);
int idx = size_2_index(s);
unsigned long *bin = info->mem_bin;
bin[idx] = node->next;
}
if(node->next) {
struct mem_node *next =
(struct mem_node *)(p + node->next);
next->prev = node->prev;
}
node->prev = node->next = 0;
return off;
}
inline static unsigned long __node_split(
struct mem_info *info,
unsigned long off,
unsigned long s)
{
void *p = info->mem_block;
struct mem_node *node =
(struct mem_node *)(p + off);
unsigned long ns = node_size(node->use_a_size);
if(s + SMALLEST_SIZE >= ns)
return off;
node->use_a_size = s;
node_tail_size(node, s) = s;
struct mem_node *next =
(struct mem_node *)node_to_next(node, s);
ns -= s;
next->use_a_size = ns;
node_tail_size(next, ns) = ns;
__node_insert(info, off + s);
return off;
}
static struct mem_node *__node_find_min(
void *p, unsigned long *bin, unsigned long s)
{
#ifdef SMALL_SIZE_BOOST
int idx = size_2_index(s);
struct mem_node *node = 0;
if(idx <= BIN_SMALL_THRESHOLD)
node = __node_find_low(p, bin, idx, s);
return (node ? node : __node_find_high(p, bin, idx, s));
#else
int idx = size_2_index(s);
struct mem_node *node, *nmin = 0;
unsigned long min, tmp;
for(unsigned i = idx; i < BIN_NUMBER; ++i) {
node = off_to_node(p, bin[i]);
if(node) min = node_size(node->use_a_size) + 1;
for(; node; node = node_list_next(p, node)) {
tmp = node_size(node->use_a_size);
if(tmp >= s && tmp < min) {
nmin = node;
min = tmp;
}
}
if(nmin)
return nmin;
}
return 0;
#endif
}
#ifdef SMALL_SIZE_BOOST
static struct mem_node *__node_find_high(
void *p, unsigned long *bin, unsigned long idx, unsigned long s)
{
//int idx = size_2_index(s);
struct mem_node *node, *nmin = 0;
unsigned long min, tmp;
for(unsigned i = idx; i < BIN_NUMBER; ++i) {
node = off_to_node(p, bin[i]);
if(node) min = node_size(node->use_a_size) + 1;
for(; node; node = node_list_next(p, node)) {
tmp = node_size(node->use_a_size);
if(tmp >= s && tmp < min) {
nmin = node;
min = tmp;
}
}
if(nmin)
return nmin;
}
return 0;
}
static struct mem_node *__node_find_low(
void *p, unsigned long *bin, unsigned long idx, unsigned long s)
{
//int idx = size_2_index(s);
struct mem_node *node;
for(unsigned long i = idx; i <= BIN_SMALL_THRESHOLD; ++i) {
for(node = off_to_node(p, bin[i]); node;
node = node_list_next(p, node)) {
if(node_size(node->use_a_size) >= s)
return node;
}
}
return 0;
}
#endif
// XXX hot spot
inline static unsigned long __node_find(
struct mem_info *info, unsigned long s)
{
unsigned long *bin = info->mem_bin;
void *p = info->mem_block;
struct mem_node *node;
#ifdef SMALL_SIZE_BOOST
int m = 2;
while(m){
#endif
if((node = __node_find_min(p, bin, s))) {
unsigned long ret = (void *)node - p;
unsigned long ns = node_size(node->use_a_size);
__node_remove(info, ret);
if(ns > s)
ret = __node_split(info, ret, s);
return ret;
}
//break;
#ifdef SMALL_SIZE_BOOST
if(--m) __node_merge_all(info, 0, (int)BIN_NUMBER);
//printf("%s: %s: %d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__);
}
#endif
return 0;
}
unsigned long mem_alloc(struct mem_info *info, unsigned long s)
{
if(!s) return 0;
if((s = align_8(s + TAG_SIZE)) < SMALLEST_SIZE)
s = SMALLEST_SIZE;
unsigned long off;
//futex_lock(info->futex);
mem_lock_lock(info->lock);
if(!(off = __node_find(info, s))) {
//futex_unlock(info->futex);
mem_lock_unlock(info->lock);
return 0;
}
struct mem_node *node =
off_to_node(info->mem_block, off);
node_used(node->use_a_size);
//futex_unlock(info->futex);
mem_lock_unlock(info->lock);
return off + sizeof(unsigned long);
}
void mem_free(struct mem_info *info, unsigned long off)
{
off -= sizeof(unsigned long);
assert(off >= LOW_SIZE);
assert(off < info->block_size);
struct mem_node *node =
off_to_node(info->mem_block, off);
//futex_lock(info->futex);
mem_lock_lock(info->lock);
node_unused(node->use_a_size);
//node->prev = node->next = 0;
#ifndef SMALL_SIZE_BOOST
off = __node_merge(info, off);
#endif
__node_insert(info, off);
#ifdef SMALL_SIZE_BOOST
static int count = 0;
if(++count == 70) {
count = 0;
//printf("%s: %s: %d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__);
__node_merge_all(info, BIN_SMALL_THRESHOLD, (int)BIN_NUMBER);
}
#endif
//futex_unlock(info->futex);
mem_lock_unlock(info->lock);
}
struct mem_info *mem_init(void *p, unsigned long s, int b)
{
if(s < LOW_SIZE + SMALLEST_SIZE)
return 0;
struct mem_info *info =
(struct mem_info *)
malloc(sizeof(struct mem_info));
//info->futex = (futex_t *)p;
info->lock = (mem_lock_t *)p;
//info->mem_bin = (unsigned long *)(p + sizeof(futex_t));
info->mem_bin = (unsigned long *)(p + sizeof(mem_lock_t));
info->mem_block = p;
info->block_size = s;
//info->error = 0;
info->shmid = -1;
//futex_create();
if(b) {
//futex_init(info->lock);
mem_lock_init(info->lock);
//futex_lock(info->futex);
mem_lock_lock(info->lock);
memset(info->mem_bin, 0, BIN_SIZE);
struct mem_node *node =
(struct mem_node *)(p + LOW_SIZE);
__node_init(node, info->block_size - LOW_SIZE);
__node_insert(info, LOW_SIZE);
//futex_unlock(info->futex);
mem_lock_unlock(info->lock);
}
return info;
}
void mem_destroy(struct mem_info *info)
{
//futex_lock(info->futex);
mem_lock_lock(info->lock);
if(info->shmid >= 0)
shmctl(info->shmid, IPC_RMID, 0);
free(info);
//futex_unlock(info->futex);
mem_lock_unlock(info->lock);
}
struct mem_info *mem_link_shm(key_t key, size_t s, int init)
{
int mid;
s += LOW_SIZE + SMALLEST_SIZE;
s = align_8(s);
if((mid = shmget(key, s, IPC_CREAT | 0666)) < 0) {
perror("shmget");
return 0;
}
void *p;
if((p = shmat(mid, 0, 0)) == (void *)-1) {
perror("shmat");
return 0;
}
struct mem_info *info =
mem_init(p, (unsigned long)s, init);
assert(info);
info->shmid = mid;
return info;
}
int mem_detach_shm(struct mem_info *info)
{
if(shmdt(info->mem_block)) {
perror("shmdt");
return -1;
}
return 0;
}
void *mem_off_2_ptr(struct mem_info *info, unsigned long off)
{
if(off >= LOW_SIZE)
return info->mem_block + off;
return 0;
}
unsigned long mem_ptr_2_off(struct mem_info *info, void *p)
{
unsigned long off;
if((off = p - info->mem_block) >= LOW_SIZE)
return off;
return 0;
}
===========================================================
mem_lock.h:
===========================================================
// 2011年 09月 13日 星期二 10:43:03 CST
// author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
// K.I.S.S
// S.P.O.T
#ifndef MEM_LOCK_H
#define MEM_LOCK_H
#include <unistd.h>
#include <sched.h>
#include <sys/syscall.h>
typedef struct __mem_lock {
unsigned long tid;
unsigned long lock;
} mem_lock_t;
inline static int mem_lock_init(mem_lock_t *);
inline static int mem_lock_lock(mem_lock_t *);
inline static int mem_lock_unlock(mem_lock_t *);
inline static int mem_lock_init(mem_lock_t *lk)
{
lk->tid = 0;
lk->lock = 0;
return 0;
}
#define SPIN_YIELD_INTERVAL 31U
inline static int mem_lock_lock(mem_lock_t *lk)
{
pid_t now = syscall(SYS_gettid);
pid_t old =
(pid_t)__sync_and_and_fetch(&lk->tid, ~0UL);
//if(__sync_bool_compare_and_swap(
// &lk->tid, now, now))
if(old == now)
return 1;
int c = 0;
while(__sync_lock_test_and_set(
&lk->lock, 1)) {
if(!(++c & SPIN_YIELD_INTERVAL))
sched_yield();
}
lk->tid = (unsigned long)now;
return 0;
}
inline static int mem_lock_unlock(mem_lock_t *lk)
{
unsigned long now =
(unsigned long)syscall(SYS_gettid);
unsigned long old =
__sync_and_and_fetch(&lk->tid, ~0UL);
//if(!__sync_bool_compare_and_swap(
// &lk->tid, now, now))
if(old != now)
return -1;
lk->tid = 0;
__sync_lock_release(&lk->lock);
return 0;
}
#endif
===========================================================
main.c:
===========================================================
// 2011年 08月 26日 星期五 10:17:33 CST
// author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
// K.I.S.S
// S.P.O.T
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "mem_alloc.h"
#include "mem_lock.h"
//#ifndef SINGLE_PROCESS
#define BUF_SIZE (0x1FFFFFUL << 1)
//#else
//#define BUF_SIZE 0xFFFFFUL
//#endif
struct mem_info *info;
static void sig_handle(int);
void *do_work(void *);
int main(int argc, char *argv[])
{
if(argc != 2)
exit(1);
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sig_handle;
sigemptyset(&sa.sa_mask);
if(sigaction(SIGINT, &sa, 0) < 0) {
perror("sigaction");
exit(1);
}
srand(time(0));
unsigned long as = BUF_SIZE;
//void *p = malloc(as);
key_t key = ftok("./main.c", 0);
info = mem_link_shm(key, as, atoi(argv[1]));
#ifndef SINGLE_PROCESS
pthread_t tid;
pthread_create(&tid, 0, do_work, (void *)0);
#endif
//info = mem_init(p, as, 1);
assert(info);
unsigned long p1, p2, p3, p4;
unsigned long s1, s2, s3;
p1 = mem_alloc(info, 524288);
assert(p1);
char *ptr4[4];
// not free
unsigned long h1 = mem_alloc(info, 12);
ptr4[0] = mem_off_2_ptr(info, h1);
strcpy(ptr4[0], "hello,world");
p2 = mem_alloc(info, 8192);
assert(p2);
// not free
unsigned long h2 = mem_alloc(info, 12);
ptr4[1] = mem_off_2_ptr(info, h2);
strcpy(ptr4[1], "hello,world");
//
p3 = mem_alloc(info, 32768);
assert(p3);
// not free
unsigned long h3 = mem_alloc(info, 12);
ptr4[2] = mem_off_2_ptr(info, h3);
strcpy(ptr4[2], "hello,world");
/
p4 = mem_alloc(info, 65535);
assert(p4);
// not free
unsigned long h4 = mem_alloc(info, 12);
ptr4[3] = mem_off_2_ptr(info, h4);
strcpy(ptr4[3], "hello,world");
///
void *ppp = mem_off_2_ptr(info, p1);
unsigned long pp1 = mem_ptr_2_off(info, ppp);
assert(pp1 == p1);
mem_free(info, p1);
mem_free(info, p2);
mem_free(info, p3);
mem_free(info, p4);
int count = 0;
time_t cur, last = time(0);
for(;;) {
while(!(s1 = rand() % 524288)) ;
while(!(s2 = rand() % 8192)) ;
p1 = mem_alloc(info, s1);
p2 = mem_alloc(info, s2);
assert(p1);
assert(p2);
if(s1 > 16) {
char *ppp = mem_off_2_ptr(info, p1);
strcpy(ppp, "hello,world");
//printf("%s\n", ppp);
}
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
mem_free(info, p2);
mem_free(info, p1);
while(!(s1 = rand() % 32)) ;
while(!(s2 = rand() % 65535)) ;
p1 = mem_alloc(info, s1);
p2 = mem_alloc(info, s2);
assert(p1);
assert(p2);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
mem_free(info, p2);
while(!(s3 = rand() % 4096)) ;
p3 = mem_alloc(info, s3);
assert(p3);
unsigned long pp[100];
for(int i = 0; i < 100; ++i) {
while(!(s3 = rand() % 4096)) ;
//while(!(s3 = rand() % 409)) ;
pp[i] = mem_alloc(info, s3);
assert(pp[i]);
/*if(s3 > 16) {
char *ppp = mem_off_2_ptr(info, pp[i]);
strcpy(ppp, "hello,world");
//printf("%s\n", ppp);
}*/
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, pp[i]);
}
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, p3);
mem_free(info, p3);
mem_free(info, p1);
//while(!(s1 = rand() % 524288)) ;
while(!(s1 = rand() % 124288)) ;
while(!(s2 = rand() % 64)) ;
while(!(s3 = rand() % 32768)) ;
p1 = mem_alloc(info, s1);
p2 = mem_alloc(info, s2);
p3 = mem_alloc(info, s3);
assert(p1);
assert(p2);
assert(p3);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, p3);
mem_free(info, p2);
mem_free(info, p3);
for(int i = 99; i >= 0; --i)
mem_free(info, pp[i]);
mem_free(info, p1);
//static int aaaaaaa = 0;
if(++count == 100000) {
cur = time(0);
printf("XXX: %lu\n", cur - last);
for(int i = 0; i < 4; ++i)
printf("%s\n", ptr4[i]);
count = 0;
last = cur;
/*if(++aaaaaaa == 3)
exit(0);*/
}
}
return 0;
}
static void sig_handle(int s)
{
printf("\ntid is %ld\n", syscall(SYS_gettid));
psignal(s, "\ndestroy shared memory");
mem_destroy(info);
exit(0);
}
void *do_work(void *p)
{
int mi = (int)p;
unsigned long as = BUF_SIZE;
//void *p = malloc(as);
key_t key = ftok("./main.c", 0);
info = mem_link_shm(key, as, mi);
//info = mem_init(p, as, 1);
assert(info);
unsigned long p1, p2, p3, p4;
unsigned long s1, s2, s3;
p1 = mem_alloc(info, 524288);
assert(p1);
char *ptr4[4];
// not free
unsigned long h1 = mem_alloc(info, 12);
ptr4[0] = mem_off_2_ptr(info, h1);
strcpy(ptr4[0], "hello,world");
p2 = mem_alloc(info, 8192);
assert(p2);
// not free
unsigned long h2 = mem_alloc(info, 12);
ptr4[1] = mem_off_2_ptr(info, h2);
strcpy(ptr4[1], "hello,world");
//
p3 = mem_alloc(info, 32768);
assert(p3);
// not free
unsigned long h3 = mem_alloc(info, 12);
ptr4[2] = mem_off_2_ptr(info, h3);
strcpy(ptr4[2], "hello,world");
/
p4 = mem_alloc(info, 65535);
assert(p4);
// not free
unsigned long h4 = mem_alloc(info, 12);
ptr4[3] = mem_off_2_ptr(info, h4);
strcpy(ptr4[3], "hello,world");
///
void *ppp = mem_off_2_ptr(info, p1);
unsigned long pp1 = mem_ptr_2_off(info, ppp);
assert(pp1 == p1);
mem_free(info, p1);
mem_free(info, p2);
mem_free(info, p3);
mem_free(info, p4);
int count = 0;
time_t cur, last = time(0);
for(;;) {
while(!(s1 = rand() % 524288)) ;
while(!(s2 = rand() % 8192)) ;
p1 = mem_alloc(info, s1);
p2 = mem_alloc(info, s2);
assert(p1);
assert(p2);
if(s1 > 16) {
char *ppp = mem_off_2_ptr(info, p1);
strcpy(ppp, "hello,world");
//printf("%s\n", ppp);
}
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
mem_free(info, p2);
mem_free(info, p1);
while(!(s1 = rand() % 32)) ;
while(!(s2 = rand() % 65535)) ;
p1 = mem_alloc(info, s1);
p2 = mem_alloc(info, s2);
assert(p1);
assert(p2);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
mem_free(info, p2);
while(!(s3 = rand() % 4096)) ;
p3 = mem_alloc(info, s3);
assert(p3);
unsigned long pp[100];
for(int i = 0; i < 100; ++i) {
while(!(s3 = rand() % 4096)) ;
//while(!(s3 = rand() % 409)) ;
pp[i] = mem_alloc(info, s3);
assert(pp[i]);
if(s3 > 16) {
char *ppp = mem_off_2_ptr(info, pp[i]);
strcpy(ppp, "hello,world");
//printf("%s\n", ppp);
}
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, pp[i]);
}
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, p3);
mem_free(info, p3);
mem_free(info, p1);
//while(!(s1 = rand() % 524288)) ;
while(!(s1 = rand() % 124288)) ;
while(!(s2 = rand() % 64)) ;
while(!(s3 = rand() % 32768)) ;
p1 = mem_alloc(info, s1);
p2 = mem_alloc(info, s2);
p3 = mem_alloc(info, s3);
assert(p1);
assert(p2);
assert(p3);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
// printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, p3);
mem_free(info, p2);
mem_free(info, p3);
for(int i = 99; i >= 0; --i)
mem_free(info, pp[i]);
mem_free(info, p1);
//static int aaaaaaa = 0;
if(++count == 100000) {
cur = time(0);
printf("XXX: %lu\n", cur - last);
for(int i = 0; i < 4; ++i)
printf("%s\n", ptr4[i]);
count = 0;
last = cur;
/*if(++aaaaaaa == 3)
exit(0);*/
}
}
return (void *)0;
}
===========================================================
makefile:
===========================================================
mod=SMALL_SIZE_BOOST
proc=SINGLE_PROCESS
mytest: main.c mem_alloc.c mem_alloc.h mem_lock.h
gcc -std=c99 -O2 -g -W -Wall -Wextra -D_GNU_SOURCE -D$(mod) -o $@ main.c mem_alloc.c -lpthread
.PHONY:clean
clean:
-rm -rf mytest
===========================================================