memory usage interrogation

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@38799 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2015-07-15 14:14:21 +00:00
parent 8af37de38b
commit 3efbfa42e2
17 changed files with 428 additions and 16 deletions

View file

@ -1,3 +1,24 @@
2015-07-15 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/GNUstepBase/GSIMap.h:
* Headers/GNUstepBase/NSObject+GNUstepBase.h:
* Source/Additions/GSMime.m:
* Source/Additions/NSObject+GNUstepBase.m:
* Source/GSArray.m:
* Source/GSCountedSet.m:
* Source/GSDictionary.m:
* Source/GSPrivate.h:
* Source/GSSet.m:
* Source/GSString.m:
* Source/NSArray.m:
* Source/NSData.m:
* Source/NSDictionary.m:
* Source/NSObject.m:
* Source/NSSet.m:
* Source/NSString.m:
Extension API to interrogate object memory usage (stolen from
GSCache and modified a bit).
2015-07-14 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSPropertyList.m: Write xml document headers referring to

View file

@ -1259,6 +1259,37 @@ GSIMapInitWithZoneAndCapacity(GSIMapTable map, NSZone *zone, uintptr_t capacity)
GSIMapMoreNodes(map, capacity);
}
GS_STATIC_INLINE NSUInteger
GSIMapSize(GSIMapTable map)
{
NSUInteger index;
NSUInteger size;
GSIMapNode node;
/* Map table plus arrays of pointers to chunks
*/
size = sizeof(*map) + map->chunkCount * sizeof(void*);
/* Add the array of buckets.
*/
size += map->bucketCount * sizeof(GSIMapBucket_t);
/* Add the free nodes.
*/
for (node = map->freeNodes; 0 != node; node = node->nextInBucket)
{
size += sizeof(GSIMapNode_t);
}
/* Add the used nodes (in the buckets).
*/
for (index = 0; index < map->bucketCount; index++)
{
size += sizeof(GSIMapNode_t) * map->buckets[index].nodeCount;
}
return size;
}
#if defined(__cplusplus)
}
#endif

View file

@ -36,6 +36,8 @@ extern "C" {
#if OS_API_VERSION(GS_API_NONE,GS_API_LATEST)
@class NSHashTable;
@interface NSObject (GNUstepBase)
/**
@ -96,6 +98,15 @@ extern "C" {
@end
/** This is an informal protocol ... classes may implement the method to
* report how much memory is used by the instance and any objects it acts
* as a container for. The method should return zero if calling the
* superclass version returns zero (ie the object is in the exclude table).
*/
@interface NSObject(MemorySize)
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude;
@end
/** This is an informal protocol ... classes may implement the method and
* register themselves to have it called on process exit.
*/

View file

@ -4085,6 +4085,21 @@ appendString(NSMutableData *m, NSUInteger offset, NSUInteger fold,
{
return value;
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = [super sizeInBytes: exclude];
if (size > 0)
{
size += [name sizeInBytes: exclude];
size += [value sizeInBytes: exclude];
size += [objects sizeInBytes: exclude];
size += [params sizeInBytes: exclude];
}
return size;
}
@end
@ -6488,6 +6503,18 @@ appendString(NSMutableData *m, NSUInteger offset, NSUInteger fold,
return hdr;
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = [super sizeInBytes: exclude];
if (size > 0)
{
size += [headers sizeInBytes: exclude];
size += [content sizeInBytes: exclude];
}
return size;
}
@end
@implementation GSMimeDocument (Private)

View file

@ -25,6 +25,7 @@
#import "common.h"
#import "Foundation/NSArray.h"
#import "Foundation/NSException.h"
#import "Foundation/NSHashTable.h"
#import "Foundation/NSLock.h"
#import "GNUstepBase/NSObject+GNUstepBase.h"
#import "GNUstepBase/NSDebug+GNUstepBase.h"
@ -293,6 +294,33 @@ handleExit()
#else
NSUInteger
GSPrivateMemorySize(NSObject *self, NSHashTable *exclude)
{
if (0 == NSHashGet(exclude, self))
{
NSHashInsert(exclude, self);
return class_getInstanceSize(object_getClass(self));
}
return 0;
}
@interface NSObject (MemorySize)
+ (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
return 0;
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
if (0 == NSHashGet(exclude, self))
{
NSHashInsert(exclude, self);
return class_getInstanceSize(object_getClass(self));
}
return 0;
}
@end
/* Dummy implementation
*/
@implementation NSObject(GSCleanup)

View file

@ -387,6 +387,7 @@ static Class GSInlineArrayClass;
state->state += count;
return count;
}
@end
#if !GS_WITH_GC
@ -970,6 +971,23 @@ static Class GSInlineArrayClass;
state->itemsPtr = stackbuf;
return count;
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = GSPrivateMemorySize(self, exclude);
if (size > 0)
{
NSUInteger count = _count;
size += _capacity*sizeof(void*);
while (count-- > 0)
{
size += [[self objectAtIndex: count] sizeInBytes: exclude];
}
}
return size;
}
@end

View file

@ -393,4 +393,30 @@ static GC_descr nodeDesc; // Type descriptor for map node.
return GSIMapCountByEnumeratingWithStateObjectsCount
(&map, state, stackbuf, len);
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = GSPrivateMemorySize(self, exclude);
if (size > 0)
{
NSUInteger count = [self count];
size += GSIMapSize(&map) - sizeof(map);
if (count > 0)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSEnumerator *enumerator = [self keyEnumerator];
NSObject *k;
while ((k = [enumerator nextObject]) != nil)
{
size += [k sizeInBytes: exclude];
}
[pool release];
}
}
return size;
}
@end

View file

@ -364,6 +364,34 @@ static SEL objSel;
return GSIMapCountByEnumeratingWithStateObjectsCount
(&map, state, stackbuf, len);
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = GSPrivateMemorySize(self, exclude);
if (size > 0)
{
NSUInteger count = [self count];
size += GSIMapSize(&map) - sizeof(map);
if (count > 0)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSEnumerator *enumerator = [self keyEnumerator];
NSObject *k;
while ((k = [enumerator nextObject]) != nil)
{
NSObject *o = [self objectForKey: k];
size += [k sizeInBytes: exclude] + [o sizeInBytes: exclude];
}
[pool release];
}
}
return size;
}
@end
@implementation GSMutableDictionary

View file

@ -571,6 +571,16 @@ uint32_t
GSPrivateFinishHash(uint32_t s0, uint32_t s1, uint32_t totalLength)
GS_ATTRIB_PRIVATE;
@class NSHashTable;
/* If 'self' is not a member of 'exclude', adds to the hash
* table and returns the memory footprint of 'self' assuming
* it contains no pointers and has no extra memory allocated.
* Otherwise returns 0.
*/
NSUInteger
GSPrivateMemorySize(NSObject *self, NSHashTable *exclude)
GS_ATTRIB_PRIVATE;
/* Return the current thread ID as an NSUInteger.
* Ideally, we use the operating-system's notion of a thread ID so
* that external process monitoring software will be using the same

View file

@ -537,6 +537,32 @@ static Class mutableSetClass;
return GSIMapCountByEnumeratingWithStateObjectsCount
(&map, state, stackbuf, len);
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = GSPrivateMemorySize(self, exclude);
if (size > 0)
{
NSUInteger count = [self count];
size += GSIMapSize(&map) - sizeof(map);
if (count > 0)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSEnumerator *enumerator = [self keyEnumerator];
NSObject *k;
while ((k = [enumerator nextObject]) != nil)
{
size += [k sizeInBytes: exclude];
}
[pool release];
}
}
return size;
}
@end
@implementation GSMutableSet

View file

@ -1087,6 +1087,16 @@ tsbytes(uintptr_t s, char *buf)
{
return;
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
if (0 == NSMapGet(exclude, self))
{
return 0;
}
return 8;
}
@end
/**
@ -3834,6 +3844,21 @@ transmute(GSStr self, NSString *aString)
freeWhenDone: flag];
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = GSPrivateMemorySize(self, exclude);
if (size > 0 && _flags.owned)
{
size += _count;
if (_flags.wide)
{
size += _count;
}
}
return size;
}
@end
@ -5640,6 +5665,21 @@ NSAssert(_flags.owned == 1 && _zone != 0, NSInternalInconsistencyException);
return _count;
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = GSPrivateMemorySize(self, exclude);
if (size > 0 && _flags.owned)
{
size += _capacity;
if (_flags.wide)
{
size += _capacity;
}
}
return size;
}
@end

View file

@ -1771,6 +1771,7 @@ compare(id elem1, id elem2, void* context)
{
[self enumerateObjectsWithOptions: 0 usingBlock: aBlock];
}
- (void) enumerateObjectsWithOptions: (NSEnumerationOptions)opts
usingBlock: (GSEnumeratorBlock)aBlock
{
@ -1792,18 +1793,18 @@ compare(id elem1, id elem2, void* context)
FOR_IN (id, obj, enumerator)
GS_DISPATCH_SUBMIT_BLOCK(enumQueueGroup, enumQueue, if (YES == shouldStop) {return;}, return, aBlock, obj, count, &shouldStop);
if (isReverse)
{
count--;
}
{
count--;
}
else
{
count++;
}
{
count++;
}
if (shouldStop)
{
break;
}
{
break;
}
END_FOR_IN(enumerator)
GS_DISPATCH_TEARDOWN_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
}
@ -1888,8 +1889,8 @@ compare(id elem1, id elem2, void* context)
passingTest: predicate];
}
- (NSUInteger)indexOfObjectWithOptions: (NSEnumerationOptions)opts
passingTest: (GSPredicateBlock)predicate
- (NSUInteger) indexOfObjectWithOptions: (NSEnumerationOptions)opts
passingTest: (GSPredicateBlock)predicate
{
/* TODO: Concurrency. */
id<NSFastEnumeration> enumerator = self;
@ -1954,13 +1955,30 @@ compare(id elem1, id elem2, void* context)
return [self indexOfObjectWithOptions: 0 passingTest: predicate];
}
- (NSUInteger)indexOfObjectAtIndexes: (NSIndexSet*)indexSet
options: (NSEnumerationOptions)opts
passingTest: (GSPredicateBlock)predicate
- (NSUInteger) indexOfObjectAtIndexes: (NSIndexSet*)indexSet
options: (NSEnumerationOptions)opts
passingTest: (GSPredicateBlock)predicate
{
return [[self objectsAtIndexes: indexSet]
indexOfObjectWithOptions: 0
passingTest: predicate];
indexOfObjectWithOptions: 0
passingTest: predicate];
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = [super sizeInBytes: exclude];
if (size > 0)
{
NSUInteger count = [self count];
size += count*sizeof(void*);
while (count-- > 0)
{
size += [[self objectAtIndex: count] sizeInBytes: exclude];
}
}
return size;
}
@end

View file

@ -1980,6 +1980,18 @@ failure:
}
return NO;
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = [super sizeInBytes: exclude];
if (size > 0)
{
size += [self length];
}
return size;
}
@end
/**
@ -3282,6 +3294,13 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
}
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = GSPrivateMemorySize(self, exclude);
return size;
}
@end
@ -3339,6 +3358,17 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
return self;
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = GSPrivateMemorySize(self, exclude);
if (size > 0)
{
size += length;
}
return size;
}
@end
#if GS_WITH_GC
@ -4162,6 +4192,17 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
length = size;
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = GSPrivateMemorySize(self, exclude);
if (size > 0)
{
size += capacity;
}
return size;
}
@end
#if GS_WITH_GC

View file

@ -1229,6 +1229,33 @@ compareIt(id o1, id o2, void* context)
[self subclassResponsibility: _cmd];
return 0;
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = [super sizeInBytes: exclude];
if (size > 0)
{
NSUInteger count = [self count];
size += 3 * sizeof(void*) * count;
if (count > 0)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSEnumerator *enumerator = [self keyEnumerator];
NSObject *k;
while ((k = [enumerator nextObject]) != nil)
{
NSObject *o = [self objectForKey: k];
size += [k sizeInBytes: exclude] + [o sizeInBytes: exclude];
}
[pool release];
}
}
return size;
}
@end

View file

@ -41,6 +41,7 @@
#import "Foundation/NSAutoreleasePool.h"
#import "Foundation/NSArray.h"
#import "Foundation/NSException.h"
#import "Foundation/NSHashTable.h"
#import "Foundation/NSPortCoder.h"
#import "Foundation/NSDistantObject.h"
#import "Foundation/NSThread.h"
@ -2607,3 +2608,24 @@ static id gs_weak_load(id obj)
}
@end
NSUInteger
GSPrivateMemorySize(NSObject *self, NSHashTable *exclude)
{
if (0 == NSHashGet(exclude, self))
{
NSHashInsert(exclude, self);
return class_getInstanceSize(object_getClass(self));
}
return 0;
}
@implementation NSObject (MemorySize)
+ (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
return 0;
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
return GSPrivateMemorySize(self, exclude);
}
@end

View file

@ -27,6 +27,7 @@
#import "common.h"
#import "Foundation/NSArray.h"
#import "Foundation/NSAutoreleasePool.h"
#import "Foundation/NSSet.h"
#import "Foundation/NSCoder.h"
#import "Foundation/NSArray.h"
@ -997,6 +998,32 @@ static Class NSMutableSet_concrete_class;
[self subclassResponsibility: _cmd];
return 0;
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = [super sizeInBytes: exclude];
if (size > 0)
{
NSUInteger count = [self count];
size += 3 * sizeof(void*) * count;
if (count > 0)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSEnumerator *enumerator = [self objectEnumerator];
NSObject *o;
while ((o = [enumerator nextObject]) != nil)
{
size += [o sizeInBytes: exclude];
}
[pool release];
}
}
return size;
}
@end

View file

@ -5923,6 +5923,17 @@ static NSFileManager *fm = nil;
return GSPropertyListFromStringsFormat(self);
}
- (NSUInteger) sizeInBytes: (NSHashTable*)exclude
{
NSUInteger size = [super sizeInBytes: exclude];
if (size > 0)
{
size += sizeof(unichar) * [self length];
}
return size;
}
@end
/**