Tcl Source Code

Check-in [b8f22672b2]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:New function TclAllocMaximize(). Let tclListObj.c find out the real allocated size, thus reducing the number of reallocs. It's good to avoid the interplay between List and Alloc both doubling just-in-case.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | mig-alloc-reform
Files: files | file ages | folders
SHA1: b8f22672b20ef57964ed0cf47ce82ad38e03b6e6
User & Date: mig 2011-03-18 16:16:09
Context
2011-03-18
18:06
remove unused mutex check-in: a3f0c08c7f user: mig tags: mig-alloc-reform
16:16
New function TclAllocMaximize(). Let tclListObj.c find out the real allocated size, thus reducing th... check-in: b8f22672b2 user: mig tags: mig-alloc-reform
13:32
README addition check-in: 3e9d5dacd9 user: mig tags: mig-alloc-reform
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tclAlloc.c.

193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#define OFFSET      ALIGN(sizeof(Block))

#define nextBlock	u.next
#define sourceBucket	u.s.bucket
#define magicNum1	u.s.magic1
#define magicNum2	u.s.magic2
#define MAGIC		0xEF
#define blockReqSize	reqSize

/*
 * The following defines the minimum and maximum block sizes and the number
 * of buckets in the bucket cache.
 *                        32b    64b    Apple-32b
 *     TCL_ALLOCALIGN       8     16       16
 *     sizeof(Block)        8     16       16







<







193
194
195
196
197
198
199

200
201
202
203
204
205
206
#define OFFSET      ALIGN(sizeof(Block))

#define nextBlock	u.next
#define sourceBucket	u.s.bucket
#define magicNum1	u.s.magic1
#define magicNum2	u.s.magic2
#define MAGIC		0xEF


/*
 * The following defines the minimum and maximum block sizes and the number
 * of buckets in the bucket cache.
 *                        32b    64b    Apple-32b
 *     TCL_ALLOCALIGN       8     16       16
 *     sizeof(Block)        8     16       16
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
    int bucket,
    unsigned int reqSize)
{
    register void *ptr;

    blockPtr->magicNum1 = blockPtr->magicNum2 = MAGIC;
    blockPtr->sourceBucket = bucket;
    blockPtr->blockReqSize = reqSize;
    ptr = (void *) (((char *)blockPtr) + OFFSET);
#if RCHECK
    ((unsigned char *)(ptr))[reqSize] = MAGIC;
#endif
    return (char *) ptr;
}

static inline Block *
Ptr2Block(
    char *ptr)
{
    register Block *blockPtr;

    blockPtr = (Block *) (((char *) ptr) - OFFSET);
    if (blockPtr->magicNum1 != MAGIC || blockPtr->magicNum2 != MAGIC) {
	Tcl_Panic("alloc: invalid block: %p: %x %x",
		blockPtr, blockPtr->magicNum1, blockPtr->magicNum2);
    }
#if RCHECK
    if (((unsigned char *) ptr)[blockPtr->blockReqSize] != MAGIC) {
	Tcl_Panic("alloc: invalid block: %p: %x %x %x",
		blockPtr, blockPtr->magicNum1, blockPtr->magicNum2,
		((unsigned char *) ptr)[blockPtr->blockReqSize]);
    }
#endif
    return blockPtr;
}

/*
 *----------------------------------------------------------------------







|



















|


|







380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
    int bucket,
    unsigned int reqSize)
{
    register void *ptr;

    blockPtr->magicNum1 = blockPtr->magicNum2 = MAGIC;
    blockPtr->sourceBucket = bucket;
    blockPtr->reqSize = reqSize;
    ptr = (void *) (((char *)blockPtr) + OFFSET);
#if RCHECK
    ((unsigned char *)(ptr))[reqSize] = MAGIC;
#endif
    return (char *) ptr;
}

static inline Block *
Ptr2Block(
    char *ptr)
{
    register Block *blockPtr;

    blockPtr = (Block *) (((char *) ptr) - OFFSET);
    if (blockPtr->magicNum1 != MAGIC || blockPtr->magicNum2 != MAGIC) {
	Tcl_Panic("alloc: invalid block: %p: %x %x",
		blockPtr, blockPtr->magicNum1, blockPtr->magicNum2);
    }
#if RCHECK
    if (((unsigned char *) ptr)[blockPtr->reqSize] != MAGIC) {
	Tcl_Panic("alloc: invalid block: %p: %x %x %x",
		blockPtr, blockPtr->magicNum1, blockPtr->magicNum2,
		((unsigned char *) ptr)[blockPtr->reqSize]);
    }
#endif
    return blockPtr;
}

/*
 *----------------------------------------------------------------------
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
     * blocks to the shared cache if there are now too many free.
     */

    blockPtr = Ptr2Block(ptr);
    bucket = blockPtr->sourceBucket;
    if (bucket == nBuckets) {
#ifdef ZIPPY_STATS
	cachePtr->totalAssigned -= blockPtr->blockReqSize;
#endif
	free(blockPtr);
	return;
    }

#ifdef ZIPPY_STATS
    cachePtr->buckets[bucket].totalAssigned -= blockPtr->blockReqSize;
#endif
    blockPtr->nextBlock = cachePtr->buckets[bucket].firstPtr;
    cachePtr->buckets[bucket].firstPtr = blockPtr;
    cachePtr->buckets[bucket].numFree++;
#ifdef ZIPPY_STATS
    cachePtr->buckets[bucket].numInserts++;
#endif







|






|







702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
     * blocks to the shared cache if there are now too many free.
     */

    blockPtr = Ptr2Block(ptr);
    bucket = blockPtr->sourceBucket;
    if (bucket == nBuckets) {
#ifdef ZIPPY_STATS
	cachePtr->totalAssigned -= blockPtr->reqSize;
#endif
	free(blockPtr);
	return;
    }

#ifdef ZIPPY_STATS
    cachePtr->buckets[bucket].totalAssigned -= blockPtr->reqSize;
#endif
    blockPtr->nextBlock = cachePtr->buckets[bucket].firstPtr;
    cachePtr->buckets[bucket].firstPtr = blockPtr;
    cachePtr->buckets[bucket].numFree++;
#ifdef ZIPPY_STATS
    cachePtr->buckets[bucket].numInserts++;
#endif
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833



















































834
835
836
837
838
839
840
	if (bucket > 0) {
	    min = bucketInfo[bucket-1].blockSize;
	} else {
	    min = 0;
	}
	if (size > min && size <= bucketInfo[bucket].blockSize) {
#ifdef ZIPPY_STATS
	    cachePtr->buckets[bucket].totalAssigned -= blockPtr->blockReqSize;
	    cachePtr->buckets[bucket].totalAssigned += reqSize;
#endif
	    return Block2Ptr(blockPtr, bucket, reqSize);
	}
    } else if (size > MAXALLOC) {
#ifdef ZIPPY_STATS
	cachePtr->totalAssigned -= blockPtr->blockReqSize;
	cachePtr->totalAssigned += reqSize;
#endif
	blockPtr = realloc(blockPtr, size);
	if (blockPtr == NULL) {
	    return NULL;
	}
	return Block2Ptr(blockPtr, nBuckets, reqSize);
    }

    /*
     * Finally, perform an expensive malloc/copy/free.
     */

    newPtr = TclpAlloc(reqSize);
    if (newPtr != NULL) {
	if (reqSize > blockPtr->blockReqSize) {
	    reqSize = blockPtr->blockReqSize;
	}
	memcpy(newPtr, ptr, reqSize);
	TclpFree(ptr);
    }
    return newPtr;
}



















































#ifdef ZIPPY_STATS

/*
 *----------------------------------------------------------------------
 *
 * Tcl_GetMemoryInfo --
 *







|






|















|
|






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
	if (bucket > 0) {
	    min = bucketInfo[bucket-1].blockSize;
	} else {
	    min = 0;
	}
	if (size > min && size <= bucketInfo[bucket].blockSize) {
#ifdef ZIPPY_STATS
	    cachePtr->buckets[bucket].totalAssigned -= blockPtr->reqSize;
	    cachePtr->buckets[bucket].totalAssigned += reqSize;
#endif
	    return Block2Ptr(blockPtr, bucket, reqSize);
	}
    } else if (size > MAXALLOC) {
#ifdef ZIPPY_STATS
	cachePtr->totalAssigned -= blockPtr->reqSize;
	cachePtr->totalAssigned += reqSize;
#endif
	blockPtr = realloc(blockPtr, size);
	if (blockPtr == NULL) {
	    return NULL;
	}
	return Block2Ptr(blockPtr, nBuckets, reqSize);
    }

    /*
     * Finally, perform an expensive malloc/copy/free.
     */

    newPtr = TclpAlloc(reqSize);
    if (newPtr != NULL) {
	if (reqSize > blockPtr->reqSize) {
	    reqSize = blockPtr->reqSize;
	}
	memcpy(newPtr, ptr, reqSize);
	TclpFree(ptr);
    }
    return newPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * TclAllocMaximize --
 *
 * Given a TclpAlloc'ed pointer, it returns the maximal size that can be used
 * by the allocated memory. This is almost always larger than the requested
 * size, as it corresponds to the bucket's size.
 *
 * Results:
 *	New size.
 *
 *----------------------------------------------------------------------
 */
 unsigned int
 TclAllocMaximize(
     void *ptr)
{
    Block *blockPtr;
    int bucket;
    size_t oldSize, newSize;

    if (allocator < aNONE) {
	/*
	 * No info, return UINT_MAX as a signal.
	 */
	
	return UINT_MAX;
    }
    
    blockPtr = Ptr2Block(ptr);
    bucket = blockPtr->sourceBucket;
    
    if (bucket == nBuckets) {
	/*
	 * System malloc'ed: no info
	 */
	
	return UINT_MAX;
    }

    oldSize = blockPtr->reqSize;
    newSize = bucketInfo[bucket].blockSize - OFFSET - RCHECK;
    blockPtr->reqSize = newSize;
#if RCHECK
    ((unsigned char *)(ptr))[newSize] = MAGIC;
#endif    
    return newSize;
}

#ifdef ZIPPY_STATS

/*
 *----------------------------------------------------------------------
 *
 * Tcl_GetMemoryInfo --
 *

Changes to generic/tclInt.h.

3860
3861
3862
3863
3864
3865
3866

3867
3868
3869
3870

3871
3872
3873
3874
3875
3876
3877
#  endif
#endif

#if TCL_ALLOCATOR < aNONE /* native or purify */
#    define TclpAlloc(size) ckalloc(size)
#    define TclpRealloc(ptr, size) ckrealloc((ptr),(size))
#    define TclpFree(size) ckfree(size)

#else
   MODULE_SCOPE char * TclpAlloc(unsigned int size);
   MODULE_SCOPE char * TclpRealloc(char * ptr, unsigned int size);
   MODULE_SCOPE void   TclpFree(char * ptr);

#endif

#if TCL_ALLOCATOR == aPURIFY
#  define TclSmallAlloc() ckalloc(sizeof(Tcl_Obj))
#  define TclSmallFree(ptr) ckfree(ptr)
#  define TclInitAlloc()
#  define TclFinalizeAlloc()







>




>







3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
#  endif
#endif

#if TCL_ALLOCATOR < aNONE /* native or purify */
#    define TclpAlloc(size) ckalloc(size)
#    define TclpRealloc(ptr, size) ckrealloc((ptr),(size))
#    define TclpFree(size) ckfree(size)
#    define TclAllocMaximize(ptr) UINT_MAX
#else
   MODULE_SCOPE char * TclpAlloc(unsigned int size);
   MODULE_SCOPE char * TclpRealloc(char * ptr, unsigned int size);
   MODULE_SCOPE void   TclpFree(char * ptr);
   MODULE_SCOPE unsigned int TclAllocMaximize(void *ptr);
#endif

#if TCL_ALLOCATOR == aPURIFY
#  define TclSmallAlloc() ckalloc(sizeof(Tcl_Obj))
#  define TclSmallFree(ptr) ckfree(ptr)
#  define TclInitAlloc()
#  define TclFinalizeAlloc()

Changes to generic/tclListObj.c.

62
63
64
65
66
67
68









69
70
71
72
73
74
75

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

96
97
98
99


100
101
102
103
104
105
106
 *
 * Side effects:
 *	The ref counts of the elements in objv are incremented since the
 *	resulting list now refers to them.
 *
 *----------------------------------------------------------------------
 */










static List *
NewListIntRep(
    int objc,
    Tcl_Obj *const objv[])
{
    List *listRepPtr;


    if (objc <= 0) {
	return NULL;
    }

    /*
     * First check to see if we'd overflow and try to allocate an object
     * larger than our memory allocator allows. Note that this is actually a
     * fairly small value when you're on a serious 64-bit machine, but that
     * requires API changes to fix. See [Bug 219196] for a discussion.
     */

    if ((size_t)objc > INT_MAX/sizeof(Tcl_Obj *)) {
	return NULL;
    }

    listRepPtr = attemptckalloc(sizeof(List) + ((objc-1) * sizeof(Tcl_Obj*)));
    if (listRepPtr == NULL) {
	return NULL;
    }


    listRepPtr->canonicalFlag = 0;
    listRepPtr->refCount = 0;
    listRepPtr->maxElemCount = objc;



    if (objv) {
	Tcl_Obj **elemPtrs;
	int i;

	listRepPtr->elemCount = objc;
	elemPtrs = &listRepPtr->elements;







>
>
>
>
>
>
>
>
>







>
|















|



>
|


|
>
>







62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
 *
 * Side effects:
 *	The ref counts of the elements in objv are incremented since the
 *	resulting list now refers to them.
 *
 *----------------------------------------------------------------------
 */

#define Elems2Size(n)					\
    ((n > 1)						\
	    ? (sizeof(List) + (n-1)*sizeof(Tcl_Obj *))	\
	    : (sizeof(List)))
#define Size2Elems(s)							\
    ((s > sizeof(List) + sizeof(Tcl_Obj *) -1)				\
	    ? (s - sizeof(List) + sizeof(Tcl_Obj *))/sizeof(Tcl_Obj *)	\
	    : 1)

static List *
NewListIntRep(
    int objc,
    Tcl_Obj *const objv[])
{
    List *listRepPtr;
    unsigned int allocSize;
    
    if (objc <= 0) {
	return NULL;
    }

    /*
     * First check to see if we'd overflow and try to allocate an object
     * larger than our memory allocator allows. Note that this is actually a
     * fairly small value when you're on a serious 64-bit machine, but that
     * requires API changes to fix. See [Bug 219196] for a discussion.
     */

    if ((size_t)objc > INT_MAX/sizeof(Tcl_Obj *)) {
	return NULL;
    }

    listRepPtr = attemptckalloc(Elems2Size(objc));
    if (listRepPtr == NULL) {
	return NULL;
    }
    allocSize = TclAllocMaximize(listRepPtr);
    
    listRepPtr->canonicalFlag = 0;
    listRepPtr->refCount = 0;
    listRepPtr->maxElemCount = (allocSize == UINT_MAX)
	? objc
	: Size2Elems(allocSize);

    if (objv) {
	Tcl_Obj **elemPtrs;
	int i;

	listRepPtr->elemCount = objc;
	elemPtrs = &listRepPtr->elements;
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
     * If there is no room in the current array of element pointers, allocate
     * a new, larger array and copy the pointers to it. If the List struct is
     * shared, allocate a new one.
     */

    if (numRequired > listRepPtr->maxElemCount){
	newMax = 2 * numRequired;
	newSize = sizeof(List) + ((newMax-1) * sizeof(Tcl_Obj *));
    } else {
	newMax = listRepPtr->maxElemCount;
	newSize = 0;
    }

    if (listRepPtr->refCount > 1) {
	List *oldListRepPtr = listRepPtr;







|







585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
     * If there is no room in the current array of element pointers, allocate
     * a new, larger array and copy the pointers to it. If the List struct is
     * shared, allocate a new one.
     */

    if (numRequired > listRepPtr->maxElemCount){
	newMax = 2 * numRequired;
	newSize = Elems2Size(newMax);
    } else {
	newMax = listRepPtr->maxElemCount;
	newSize = 0;
    }

    if (listRepPtr->refCount > 1) {
	List *oldListRepPtr = listRepPtr;
597
598
599
600
601
602
603

604


605
606
607
608
609
610
611
	    Tcl_IncrRefCount(elemPtrs[i]);
	}
	listRepPtr->elemCount = numElems;
	listRepPtr->refCount++;
	oldListRepPtr->refCount--;
    } else if (newSize) {
	listRepPtr = ckrealloc(listRepPtr, newSize);

	listRepPtr->maxElemCount = newMax;


    }
    listPtr->internalRep.twoPtrValue.ptr1 = listRepPtr;

    /*
     * Add objPtr to the end of listPtr's array of element pointers. Increment
     * the ref count for the (now shared) objPtr.
     */







>
|
>
>







610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
	    Tcl_IncrRefCount(elemPtrs[i]);
	}
	listRepPtr->elemCount = numElems;
	listRepPtr->refCount++;
	oldListRepPtr->refCount--;
    } else if (newSize) {
	listRepPtr = ckrealloc(listRepPtr, newSize);
	newSize = TclAllocMaximize(listRepPtr);
	listRepPtr->maxElemCount = (newSize == UINT_MAX)
	    ? newMax
	    : Size2Elems(newSize);
    }
    listPtr->internalRep.twoPtrValue.ptr1 = listRepPtr;

    /*
     * Add objPtr to the end of listPtr's array of element pointers. Increment
     * the ref count for the (now shared) objPtr.
     */