Quellcode durchsuchen

- malloc changes: fragment avoidance, bookkeeping, hooks for future
full mem. defragmenter

Andrei Pelinescu-Onciul vor 21 Jahren
Ursprung
Commit
46b467df20
5 geänderte Dateien mit 149 neuen und 36 gelöschten Zeilen
  1. 2 2
      Makefile.defs
  2. 59 14
      mem/f_malloc.c
  3. 10 4
      mem/f_malloc.h
  4. 71 12
      mem/q_malloc.c
  5. 7 4
      mem/q_malloc.h

+ 2 - 2
Makefile.defs

@@ -45,7 +45,7 @@ export makefile_defs
 VERSION = 0
 PATCHLEVEL = 8
 SUBLEVEL =   13
-EXTRAVERSION = -dev-35
+EXTRAVERSION = -dev-36-malloc
 
 RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 OS = $(shell uname -s | sed -e s/SunOS/solaris/ | tr "[A-Z]" "[a-z]")
@@ -282,8 +282,8 @@ DEFS+= $(extra_defs) \
 	 -DUSE_TCP \
 	 -DDISABLE_NAGLE \
 	 -DF_MALLOC \
-	# -DDBG_F_MALLOC \
 	# -DDBG_QM_MALLOC \
+	# -DDBG_F_MALLOC \
 	 #-DF_MALLOC \
 	 #-DNO_DEBUG \
 	 #-DNO_LOG

+ 59 - 14
mem/f_malloc.c

@@ -29,6 +29,9 @@
  * --------
  *              created by andrei
  *  2003-07-06  added fm_realloc (andrei)
+ *  2004-07-19  fragments book keeping code and support for 64 bits
+ *               memory blocks (64 bits machine & size >=2^32) 
+ *              GET_HASH s/</<=/ (avoids waste of 1 hash cell)   (andrei)
  */
 
 
@@ -63,15 +66,26 @@
 
 
 	/* finds the hash value for s, s=ROUNDTO multiple*/
-#define GET_HASH(s)   ( ((s)<F_MALLOC_OPTIMIZE)?(s)/ROUNDTO: \
+#define GET_HASH(s)   ( ((s)<=F_MALLOC_OPTIMIZE)?(s)/ROUNDTO: \
 						F_MALLOC_OPTIMIZE/ROUNDTO+big_hash_idx((s))- \
 							F_MALLOC_OPTIMIZE_FACTOR+1 )
 
-#define UN_HASH(h)	( ((h)<(F_MALLOC_OPTIMIZE/ROUNDTO))?(h)*ROUNDTO: \
+#define UN_HASH(h)	( ((h)<=(F_MALLOC_OPTIMIZE/ROUNDTO))?(h)*ROUNDTO: \
 						1<<((h)-F_MALLOC_OPTIMIZE/ROUNDTO+\
 							F_MALLOC_OPTIMIZE_FACTOR-1)\
 					)
 
+/* mark/test used/unused frags */
+#define FRAG_MARK_USED(f)
+#define FRAG_CLEAR_USED(f)
+#define FRAG_WAS_USED(f)   (1)
+
+/* other frag related defines:
+ * MEM_COALESCE_FRAGS 
+ * MEM_FRAG_AVOIDANCE
+ */
+#define MEM_FRAG_AVOIDANCE
+
 
 /* computes hash number for big buckets*/
 inline static int big_hash_idx(int s)
@@ -81,7 +95,8 @@ inline static int big_hash_idx(int s)
 	 * index= i such that 2^i > s >= 2^(i-1)
 	 *
 	 * => index = number of the first non null bit in s*/
-	for (idx=31; !(s&0x80000000) ; s<<=1, idx--);
+	idx=sizeof(long)*8-1;
+	for (; !(s&(1<<(sizeof(long)*8-1))) ; s<<=1, idx--);
 	return idx;
 }
 
@@ -100,8 +115,10 @@ static inline void fm_insert_free(struct fm_block* qm, struct fm_frag* frag)
 	int hash;
 	
 	hash=GET_HASH(frag->size);
-	f=&(qm->free_hash[hash]);
-	if (frag->size > F_MALLOC_OPTIMIZE){
+	f=&(qm->free_hash[hash].first);
+	if (frag->size > F_MALLOC_OPTIMIZE){ /* because of '<=' in GET_HASH,
+											(different from 0.8.1[24] on
+											 purpose --andrei ) */
 		for(; *f; f=&((*f)->u.nxt_free)){
 			if (frag->size <= (*f)->size) break;
 		}
@@ -110,6 +127,7 @@ static inline void fm_insert_free(struct fm_block* qm, struct fm_frag* frag)
 	/*insert it here*/
 	frag->u.nxt_free=*f;
 	*f=frag;
+	qm->free_hash[hash].no++;
 }
 
 
@@ -127,11 +145,17 @@ void fm_split_frag(struct fm_block* qm, struct fm_frag* frag,unsigned int size)
 	struct fm_frag* n;
 	
 	rest=frag->size-size;
+#ifdef MEM_FRAG_AVOIDANCE
+	if ((rest> (FRAG_OVERHEAD+F_MALLOC_OPTIMIZE))||
+		(rest>=(FRAG_OVERHEAD+size))){ /* the residue fragm. is big enough*/
+#else
 	if (rest>(FRAG_OVERHEAD+MIN_FRAG_SIZE)){
+#endif
 		frag->size=size;
 		/*split the fragment*/
 		n=FRAG_NEXT(frag);
 		n->size=rest-FRAG_OVERHEAD;
+		FRAG_CLEAR_USED(n); /* never used */
 #ifdef DBG_F_MALLOC
 		qm->real_used+=FRAG_OVERHEAD;
 		/* frag created by malloc, mark it*/
@@ -226,7 +250,7 @@ void* fm_malloc(struct fm_block* qm, unsigned int size)
 	/*search for a suitable free frag*/
 
 	for(hash=GET_HASH(size);hash<F_HASH_SIZE;hash++){
-		f=&(qm->free_hash[hash]);
+		f=&(qm->free_hash[hash].first);
 		for(;(*f); f=&((*f)->u.nxt_free))
 			if ((*f)->size>=size) goto found;
 		/* try in a bigger bucket */
@@ -240,6 +264,7 @@ found:
 	frag=*f;
 	*f=frag->u.nxt_free;
 	frag->u.nxt_free=0; /* mark it as 'taken' */
+	qm->free_hash[hash].no--;
 	
 	/*see if we'll use full frag, or we'll split it in 2*/
 	
@@ -260,6 +285,7 @@ found:
 #else
 	fm_split_frag(qm, frag, size);
 #endif
+	FRAG_MARK_USED(frag); /* mark it as used */
 	return (char*)frag+sizeof(struct fm_frag);
 }
 
@@ -318,6 +344,7 @@ void* fm_realloc(struct fm_block* qm, void* p, unsigned int size)
 	unsigned int orig_size;
 	struct fm_frag *n;
 	void *ptr;
+	int hash;
 	
 #ifdef DBG_F_MALLOC
 	DBG("fm_realloc(%p, %p, %d) called from %s: %s(%d)\n", qm, p, size,
@@ -371,9 +398,10 @@ void* fm_realloc(struct fm_block* qm, void* p, unsigned int size)
 				(n->u.nxt_free)&&((n->size+FRAG_OVERHEAD)>=diff)){
 			/* join  */
 			/* detach n from the free list */
-			pf=&(qm->free_hash[GET_HASH(n->size)]);
+			hash=GET_HASH(n->size);
+			pf=&(qm->free_hash[hash].first);
 			/* find it */
-			for(;(*pf)&&(*pf!=n); pf=&((*pf)->u.nxt_free));
+			for(;(*pf)&&(*pf!=n); pf=&((*pf)->u.nxt_free)); /*FIXME slow */
 			if (*pf==0){
 				/* not found, bad! */
 				LOG(L_CRIT, "BUG: fm_realloc: could not find %p in free "
@@ -382,6 +410,7 @@ void* fm_realloc(struct fm_block* qm, void* p, unsigned int size)
 			}
 			/* detach */
 			*pf=n->u.nxt_free;
+			qm->free_hash[hash].no--;
 			/* join */
 			f->size+=n->size+FRAG_OVERHEAD;
 		#ifdef DBG_F_MALLOC
@@ -436,6 +465,7 @@ void fm_status(struct fm_block* qm)
 	struct fm_frag* f;
 	int i,j;
 	int h;
+	int unused;
 	long size;
 
 	LOG(memlog, "fm_status (%p):\n", qm);
@@ -462,14 +492,29 @@ void fm_status(struct fm_block* qm)
 */
 	LOG(memlog, "dumping free list:\n");
 	for(h=0,i=0,size=0;h<F_HASH_SIZE;h++){
-		
-		for (f=qm->free_hash[h],j=0; f; size+=f->size,f=f->u.nxt_free,i++,j++);
-		if (j) LOG(memlog, "hash = %3d fragments no.: %5d,\n\t\t"
+		unused=0;
+		for (f=qm->free_hash[h].first,j=0; f;
+				size+=f->size,f=f->u.nxt_free,i++,j++){
+			if (!FRAG_WAS_USED(f)){
+				unused++;
+#ifdef DBG_FM_MALLOC
+				LOG(memlog, "unused fragm.: hash = %3d, fragment %x,"
+							" address %x size %d, created from %s: %s(%d)\n",
+						    h, f, (char*)f+sizeof(struct fm_frag), f->size,
+							f->file, f->func, f->line);
+#endif
+			};
+		}
+		if (j) LOG(memlog, "hash = %3d fragments no.: %5d, unused: %5d\n\t\t"
 							" bucket size: %9ld - %9ld (first %9ld)\n",
-							h, j, (long)UN_HASH(h),
-						(long)((h<F_MALLOC_OPTIMIZE/ROUNDTO)?1:2)*UN_HASH(h),
-							qm->free_hash[h]->size
+							h, j, unused, (long)UN_HASH(h),
+						(long)((h<=F_MALLOC_OPTIMIZE/ROUNDTO)?1:2)*UN_HASH(h),
+							qm->free_hash[h].first->size
 				);
+		if (j!=qm->free_hash[h].no){
+			LOG(L_CRIT, "BUG: fm_status: different free frag. count: %d!=%ld"
+					" for hash %3d\n", j, qm->free_hash[h].no, h);
+		}
 		/*
 		{
 			LOG(memlog, "   %5d.[%3d:%3d] %c  address=%x  size=%d(%x)\n",

+ 10 - 4
mem/f_malloc.h

@@ -30,6 +30,8 @@
  * --------
  *  2003-05-21  on sparc64 roundto 8 even in debugging mode (so malloc'ed
  *               long longs will be 64 bit aligned) (andrei)
+ *  2004-07-19  support for 64 bit (2^64 mem. block) and more info
+ *               for the future de-fragmentation support (andrei)
  */
 
 
@@ -60,14 +62,14 @@
 #define F_MALLOC_OPTIMIZE_FACTOR 11 /*used below */
 #define F_MALLOC_OPTIMIZE  (1<<F_MALLOC_OPTIMIZE_FACTOR)
 								/* size to optimize for,
-									(most allocs < this size),
+									(most allocs <= this size),
 									must be 2^k */
 
 #define F_HASH_SIZE (F_MALLOC_OPTIMIZE/ROUNDTO + \
-		(32-F_MALLOC_OPTIMIZE_FACTOR)+1)
+		(sizeof(long)*8-F_MALLOC_OPTIMIZE_FACTOR)+1)
 
 /* hash structure:
- * 0 .... F_MALLOC_OPTIMIE/ROUNDTO  - small buckets, size increases with
+ * 0 .... F_MALLOC_OPTIMIZE/ROUNDTO  - small buckets, size increases with
  *                            ROUNDTO from bucket to bucket
  * +1 .... end -  size = 2^k, big buckets */
 
@@ -85,6 +87,10 @@ struct fm_frag{
 #endif
 };
 
+struct fm_frag_lnk{
+	struct fm_frag* first;
+	unsigned long no;
+};
 
 struct fm_block{
 	unsigned long size; /* total size */
@@ -97,7 +103,7 @@ struct fm_block{
 	struct fm_frag* first_frag;
 	struct fm_frag* last_frag;
 	
-	struct fm_frag* free_hash[F_HASH_SIZE];
+	struct fm_frag_lnk free_hash[F_HASH_SIZE];
 };
 
 

+ 71 - 12
mem/q_malloc.c

@@ -30,6 +30,9 @@
  *  ????-??-??  created by andrei
  *  2003-04-14  more debugging added in DBG_QM_MALLOC mode (andrei)
  *  2003-06-29  added qm_realloc (andrei)
+ *  2004-07-19  fragments book keeping code and suport for 64 bits
+ *               memory blocks (64 bits machine & size>=2^32) (andrei)
+ *              GET_HASH s/</<=/ (avoids waste of 1 hash cell) (andrei)
  */
 
 
@@ -77,10 +80,28 @@
 
 
 	/* finds the hash value for s, s=ROUNDTO multiple*/
-#define GET_HASH(s)   ( ((s)<QM_MALLOC_OPTIMIZE)?(s)/ROUNDTO: \
+#define GET_HASH(s)   ( ((s)<=QM_MALLOC_OPTIMIZE)?(s)/ROUNDTO: \
 						QM_MALLOC_OPTIMIZE/ROUNDTO+big_hash_idx((s))- \
 							QM_MALLOC_OPTIMIZE_FACTOR+1 )
 
+#define UN_HASH(h)	( ((h)<=(QM_MALLOC_OPTIMIZE/ROUNDTO))?(h)*ROUNDTO: \
+						1<<((h)-QM_MALLOC_OPTIMIZE/ROUNDTO+\
+							QM_MALLOC_OPTIMIZE_FACTOR-1)\
+					)
+
+
+/* mark/test used/unused frags */
+#define FRAG_MARK_USED(f)
+#define FRAG_CLEAR_USED(f)
+#define FRAG_WAS_USED(f)   (1)
+
+/* other frag related defines:
+ * MEM_COALESCE_FRAGS 
+ * MEM_FRAG_AVOIDANCE
+ */
+
+#define MEM_FRAG_AVOIDANCE
+
 
 /* computes hash number for big buckets*/
 inline static int big_hash_idx(int s)
@@ -90,7 +111,8 @@ inline static int big_hash_idx(int s)
 	 * index= i such that 2^i > s >= 2^(i-1)
 	 *
 	 * => index = number of the first non null bit in s*/
-	for (idx=31; !(s&0x80000000) ; s<<=1, idx--);
+	idx=sizeof(long)*8-1;
+	for (; !(s&(1<<(sizeof(long)*8-1))) ; s<<=1, idx--);
 	return idx;
 }
 
@@ -152,6 +174,7 @@ static inline void qm_insert_free(struct qm_block* qm, struct qm_frag* frag)
 	FRAG_END(frag)->prev_free=prev;
 	frag->u.nxt_free=f;
 	FRAG_END(f)->prev_free=frag;
+	qm->free_hash[hash].no++;
 }
 
 
@@ -243,10 +266,12 @@ static inline void qm_detach_free(struct qm_block* qm, struct qm_frag* frag)
 #ifdef DBG_QM_MALLOC
 static inline struct qm_frag* qm_find_free(struct qm_block* qm, 
 											unsigned int size,
+											int *h,
 											unsigned int *count)
 #else
 static inline struct qm_frag* qm_find_free(struct qm_block* qm, 
-											unsigned int size)
+											unsigned int size,
+											int* h)
 #endif
 {
 	int hash;
@@ -258,7 +283,7 @@ static inline struct qm_frag* qm_find_free(struct qm_block* qm,
 #ifdef DBG_QM_MALLOC
 			*count+=1; /* *count++ generates a warning with gcc 2.9* -Wall */
 #endif
-			if (f->size>=size) return f;
+			if (f->size>=size){ *h=hash; return f; }
 		}
 	/*try in a bigger bucket*/
 	}
@@ -282,7 +307,12 @@ int split_frag(struct qm_block* qm, struct qm_frag* f, unsigned int new_size)
 	struct qm_frag_end* end;
 	
 	rest=f->size-new_size;
+#ifdef MEM_FRAG_AVOIDANCE
+	if ((rest> (FRAG_OVERHEAD+QM_MALLOC_OPTIMIZE))||
+		(rest>=(FRAG_OVERHEAD+new_size))){/* the residue fragm. is big enough*/
+#else
 	if (rest>(FRAG_OVERHEAD+MIN_FRAG_SIZE)){
+#endif
 		f->size=new_size;
 		/*split the fragment*/
 		end=FRAG_END(f);
@@ -290,6 +320,7 @@ int split_frag(struct qm_block* qm, struct qm_frag* f, unsigned int new_size)
 		n=(struct qm_frag*)((char*)end+sizeof(struct qm_frag_end));
 		n->size=rest-FRAG_OVERHEAD;
 		FRAG_END(n)->size=n->size;
+		FRAG_CLEAR_USED(n); /* never used */
 		qm->real_used+=FRAG_OVERHEAD;
 #ifdef DBG_QM_MALLOC
 		end->check1=END_CHECK_PATTERN1;
@@ -319,6 +350,7 @@ void* qm_malloc(struct qm_block* qm, unsigned int size)
 #endif
 {
 	struct qm_frag* f;
+	int hash;
 	
 #ifdef DBG_QM_MALLOC
 	unsigned int list_cntr;
@@ -333,9 +365,9 @@ void* qm_malloc(struct qm_block* qm, unsigned int size)
 
 	/*search for a suitable free frag*/
 #ifdef DBG_QM_MALLOC
-	if ((f=qm_find_free(qm, size, &list_cntr))!=0){
+	if ((f=qm_find_free(qm, size, &hash, &list_cntr))!=0){
 #else
-	if ((f=qm_find_free(qm, size))!=0){
+	if ((f=qm_find_free(qm, size, &hash))!=0){
 #endif
 		/* we found it!*/
 		/*detach it from the free list*/
@@ -345,6 +377,7 @@ void* qm_malloc(struct qm_block* qm, unsigned int size)
 		qm_detach_free(qm, f);
 		/*mark it as "busy"*/
 		f->u.is_free=0;
+		qm->free_hash[hash].no--;
 		/* we ignore split return */
 #ifdef DBG_QM_MALLOC
 		split_frag(qm, f, size, file, "fragm. from qm_malloc", line);
@@ -422,6 +455,7 @@ void qm_free(struct qm_block* qm, void* p)
 		qm_detach_free(qm, next);
 		size+=next->size+FRAG_OVERHEAD;
 		qm->real_used-=FRAG_OVERHEAD;
+		qm->free_hash[GET_HASH(next->size)].no--; /* FIXME slow */
 	}
 	
 	if (f > qm->first_frag){
@@ -436,6 +470,7 @@ void qm_free(struct qm_block* qm, void* p)
 			qm_detach_free(qm, prev);
 			size+=prev->size+FRAG_OVERHEAD;
 			qm->real_used-=FRAG_OVERHEAD;
+			qm->free_hash[GET_HASH(prev->size)].no--; /* FIXME slow */
 			f=prev;
 		}
 	}
@@ -530,6 +565,7 @@ void* qm_realloc(struct qm_block* qm, void* p, unsigned int size)
 					(n->u.is_free)&&((n->size+FRAG_OVERHEAD)>=diff)){
 				/* join  */
 				qm_detach_free(qm, n);
+				qm->free_hash[GET_HASH(n->size)].no--; /*FIXME: slow*/
 				f->size+=n->size+FRAG_OVERHEAD;
 				qm->real_used-=FRAG_OVERHEAD;
 				FRAG_END(f)->size=f->size;
@@ -582,6 +618,7 @@ void qm_status(struct qm_block* qm)
 	struct qm_frag* f;
 	int i,j;
 	int h;
+	int unused;
 
 	LOG(memlog, "qm_status (%p):\n", qm);
 	if (!qm) return;
@@ -591,13 +628,14 @@ void qm_status(struct qm_block* qm)
 			qm->used, qm->real_used, qm->size-qm->real_used);
 	LOG(memlog, " max used (+overhead)= %ld\n", qm->max_real_used);
 	
-	LOG(memlog, "dumping all allocked. fragments:\n");
+	LOG(memlog, "dumping all alloc'ed. fragments:\n");
 	for (f=qm->first_frag, i=0;(char*)f<(char*)qm->last_frag_end;f=FRAG_NEXT(f)
 			,i++){
 		if (! f->u.is_free){
-			LOG(memlog, "    %3d. %c  address=%p frag=%p size=%ld\n", i, 
+			LOG(memlog, "    %3d. %c  address=%p frag=%p size=%ld used=%d\n",
+				i, 
 				(f->u.is_free)?'a':'N',
-				(char*)f+sizeof(struct qm_frag), f, f->size);
+				(char*)f+sizeof(struct qm_frag), f, f->size, FRAG_WAS_USED(f));
 #ifdef DBG_QM_MALLOC
 			LOG(memlog, "            %s from %s: %s(%ld)\n",
 				(f->u.is_free)?"freed":"alloc'd", f->file, f->func, f->line);
@@ -608,10 +646,31 @@ void qm_status(struct qm_block* qm)
 	}
 	LOG(memlog, "dumping free list stats :\n");
 	for(h=0,i=0;h<QM_HASH_SIZE;h++){
-		
+		unused=0;
 		for (f=qm->free_hash[h].head.u.nxt_free,j=0; 
-				f!=&(qm->free_hash[h].head); f=f->u.nxt_free, i++, j++);
-			if (j) LOG(memlog, "hash= %3d. fragments no.: %5d\n", h, j);
+				f!=&(qm->free_hash[h].head); f=f->u.nxt_free, i++, j++){
+				if (!FRAG_WAS_USED(f)){
+					unused++;
+#ifdef DBG_QM_MALLOC
+					LOG(memlog, "unused fragm.: hash = %3d, fragment %p,"
+						" address %p size %lu, created from %s: %s(%lu)\n",
+					    h, f, (char*)f+sizeof(struct qm_frag), f->size,
+						f->file, f->func, f->line);
+#endif
+				}
+		}
+
+		if (j) LOG(memlog, "hash= %3d. fragments no.: %5d, unused: %5d\n"
+					"\t\t bucket size: %9ld - %9ld (first %9ld)\n",
+					h, j, unused, (long)UN_HASH(h),
+					(long)((h<=QM_MALLOC_OPTIMIZE/ROUNDTO)?1:2)*UN_HASH(h),
+					qm->free_hash[h].head.u.nxt_free->size
+				);
+		if (j!=qm->free_hash[h].no){
+			LOG(L_CRIT, "BUG: qm_status: different free frag. count: %d!=%lu"
+				" for hash %3d\n", j, qm->free_hash[h].no, h);
+		}
+
 	}
 	LOG(memlog, "-----------------------------\n");
 }

+ 7 - 4
mem/q_malloc.h

@@ -30,6 +30,8 @@
  * --------
  *  2003-05-21  on sparc64 roundto 8 even in debugging mode (so malloc'ed
  *               long longs will be 64 bit aligned) (andrei)
+ *  2004-07-19  support for 64 bit (2^64 mem. block) and more info
+ *               for the future de-fragmentation support (andrei)
  */
 
 
@@ -62,11 +64,11 @@
 #define QM_MALLOC_OPTIMIZE_FACTOR 11 /*used below */
 #define QM_MALLOC_OPTIMIZE  ((unsigned long)(1<<QM_MALLOC_OPTIMIZE_FACTOR))
 								/* size to optimize for,
-									(most allocs < this size),
+									(most allocs <= this size),
 									must be 2^k */
 
 #define QM_HASH_SIZE ((unsigned long)(QM_MALLOC_OPTIMIZE/ROUNDTO + \
-		(32-QM_MALLOC_OPTIMIZE_FACTOR)+1))
+		(sizeof(long)-QM_MALLOC_OPTIMIZE_FACTOR)+1))
 
 /* hash structure:
  * 0 .... QM_MALLOC_OPTIMIE/ROUNDTO  - small buckets, size increases with
@@ -100,9 +102,10 @@ struct qm_frag_end{
 
 
 
-struct qm_frag_full{
+struct qm_frag_lnk{
 	struct qm_frag head;
 	struct qm_frag_end tail;
+	unsigned long no;
 };
 
 
@@ -115,7 +118,7 @@ struct qm_block{
 	struct qm_frag* first_frag;
 	struct qm_frag_end* last_frag_end;
 	
-	struct qm_frag_full free_hash[QM_HASH_SIZE];
+	struct qm_frag_lnk free_hash[QM_HASH_SIZE];
 	/*struct qm_frag_end free_lst_end;*/
 };