From 24cf296541899a0b39a59c91c1cee75ba8912a7f Mon Sep 17 00:00:00 2001 From: richard Date: Mon, 3 Aug 1998 15:31:33 +0000 Subject: [PATCH] Performance hacks git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@2895 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 20 ++++++ Headers/gnustep/base/NSGCString.h | 2 + Headers/gnustep/base/NSGString.h | 2 + Source/NSGCString.m | 113 ++++++++++++++++++++++++++++-- Source/NSGString.m | 13 ++++ Source/NSString.m | 102 ++++++++++++++------------- Source/o_map.m | 4 ++ 7 files changed, 199 insertions(+), 57 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8b749244c..11a47e167 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +Thu Aug 3 35:00:00 1998 Richard Frith-Macdonald + + * src/include/NSGCString.h: Added _hash instance variable. + * src/include/NSGString.h: Added _hash instance variable. + * src/NSGCString.m: Added implementation of [-hash] to handle caching + of strings hash value, also added implementation of a few other + methods for the sake of performance. Modified NSGMutableCString + methods to reset hash cache when string is modified. + * src/NSGString.m: Added implementation of [-hash] to handle caching + of strings hash value. Modified NSGMutableString methods to reset + hash cache when string is modified. + * src/NSString.m: Misc performance hacks - use alloca() rather than + malloc/free where possible etc. + YMMV, but the above changes got me a 20% performance improvement in + the app I was working with. + * src/o_map.m: Don't use o_map_key_callbacks() - access the field + in the structure directly to avoid the function-call overhead as this + function was being called LOTS of times. Only a tiny performance + improvement - but every little helps. + Thu Jul 30 16:00:00 1998 Richard Frith-Macdonald * src/include/NSSet.h: Corrected protocol conformance diff --git a/Headers/gnustep/base/NSGCString.h b/Headers/gnustep/base/NSGCString.h index 8ecb03471..9ea2bcf4a 100644 --- a/Headers/gnustep/base/NSGCString.h +++ b/Headers/gnustep/base/NSGCString.h @@ -35,6 +35,7 @@ char * _contents_chars; int _count; BOOL _free_contents; + unsigned _hash; } @end @@ -43,6 +44,7 @@ char * _contents_chars; int _count; BOOL _free_contents; + unsigned _hash; int _capacity; } @end diff --git a/Headers/gnustep/base/NSGString.h b/Headers/gnustep/base/NSGString.h index 5ec115e60..2e5ca0547 100644 --- a/Headers/gnustep/base/NSGString.h +++ b/Headers/gnustep/base/NSGString.h @@ -39,6 +39,7 @@ unichar * _contents_chars; int _count; BOOL _free_contents; + unsigned _hash; } @end @@ -47,6 +48,7 @@ unichar * _contents_chars; int _count; BOOL _free_contents; + unsigned _hash; int _capacity; } @end diff --git a/Source/NSGCString.m b/Source/NSGCString.m index 83bca3ca3..fbf6c139b 100644 --- a/Source/NSGCString.m +++ b/Source/NSGCString.m @@ -34,9 +34,22 @@ #include +static Class immutableClass; +static Class mutableClass; @implementation NSGCString ++ (void) initialize +{ + static int done = 0; + if (!done) + { + done = 1; + immutableClass = [NSGCString class]; + mutableClass = [NSGMutableCString class]; + } +} + - (void)dealloc { if (_free_contents) @@ -44,6 +57,14 @@ [super dealloc]; } +- (unsigned) hash +{ + if (_hash == 0) + if ((_hash = [super hash]) == 0) + _hash = 0xffffffff; + return _hash; +} + /* This is the designated initializer for this class. */ - (id) initWithCStringNoCopy: (char*)byteString length: (unsigned int)length @@ -132,10 +153,53 @@ return _contents_chars; } -/* xxx Remove this method, now that we have cStringNoCopy */ -- (const char *) _cStringContents +- (void) getCString: (char*)buffer { - return _contents_chars; + memcpy(buffer, _contents_chars, _count); + buffer[_count] = '\0'; +} + +- (void) getCString: (char*)buffer + maxLength: (unsigned int)maxLength +{ + if (maxLength > _count) + maxLength = _count; + memcpy(buffer, _contents_chars, maxLength); + buffer[maxLength] = '\0'; +} + +- (void) getCString: (char*)buffer + maxLength: (unsigned int)maxLength + range: (NSRange)aRange + remainingRange: (NSRange*)leftoverRange +{ + int len; + + if (aRange.location >= _count) + [NSException raise: NSRangeException format:@"Invalid location."]; + if (aRange.length > (_count - aRange.location)) + [NSException raise: NSRangeException format:@"Invalid location+length."]; + if (maxLength < aRange.length) + { + len = maxLength; + if (leftoverRange) + { + leftoverRange->location = 0; + leftoverRange->length = 0; + } + } + else + { + len = aRange.length; + if (leftoverRange) + { + leftoverRange->location = aRange.location + maxLength; + leftoverRange->length = aRange.length - maxLength; + } + } + + memcpy(buffer, &_contents_chars[aRange.location], len); + buffer[len] = '\0'; } - (unsigned) count @@ -155,11 +219,30 @@ - (unichar) characterAtIndex: (unsigned int)index { - /* xxx This should raise an NSException. */ CHECK_INDEX_RANGE_ERROR(index, _count); return chartouni(_contents_chars[index]); } +- (void) getCharacters: (unichar*)buffer +{ + int i; + + for (i = 0; i < _count; i++) + buffer[i] = chartouni(((unsigned char *)_contents_chars)[i]); +} + +- (void) getCharacters: (unichar*)buffer range: (NSRange)aRange +{ + int e, i; + + if (aRange.location >= _count) + [NSException raise: NSRangeException format:@"Invalid location."]; + if (aRange.length > (_count - aRange.location)) + [NSException raise: NSRangeException format:@"Invalid location+length."]; + e = aRange.location + aRange.length; + for (i = aRange.location; i < e; i++) + *buffer++ = chartouni(((unsigned char *)_contents_chars)[i]); +} - (NSString*) substringFromRange: (NSRange)aRange { @@ -184,16 +267,27 @@ return [NSString defaultCStringEncoding]; } -// Override for speed - (BOOL) isEqualToString: (NSString*)aString { - if([self class] == [aString class]) - return ! strcmp([self cStringNoCopy], [aString cStringNoCopy]); + Class c = [aString class]; + if (c == immutableClass || c == mutableClass) + { + NSGCString *other = (NSGCString*)aString; + + if (_count != other->_count) + return NO; + if (_hash && other->_hash && (_hash != other->_hash)) + return NO; + if (memcmp(_contents_chars, other->_contents_chars, _count) != 0) + return NO; + return YES; + } else return [super isEqualToString: aString]; return YES; } + // FOR IndexedCollection SUPPORT; - objectAtIndex: (unsigned)index @@ -247,6 +341,7 @@ stringIncrementCountAndMakeHoleAt(NSGMutableCStringStruct *self, self->_count - index); #endif /* STABLE_MEMCPY */ (self->_count) += size; + (self->_hash) = 0; } static inline void @@ -265,6 +360,7 @@ stringDecrementCountAndFillHoleAt(NSGMutableCStringStruct *self, self->_contents_chars + index, self->_count - index); #endif /* STABLE_MEMCPY */ + (self->_hash) = 0; } /* This is the designated initializer for this class */ @@ -318,6 +414,7 @@ stringDecrementCountAndFillHoleAt(NSGMutableCStringStruct *self, memcpy(_contents_chars + _count, [aString cStringNoCopy], c); _count += c; _contents_chars[_count] = '\0'; + _hash = 0; } - (void) setString: (NSString*)aString @@ -332,6 +429,7 @@ stringDecrementCountAndFillHoleAt(NSGMutableCStringStruct *self, memcpy(_contents_chars, s, length); _contents_chars[length] = '\0'; _count = length; + _hash = 0; } /* xxx This method may be removed in future. */ @@ -345,6 +443,7 @@ stringDecrementCountAndFillHoleAt(NSGMutableCStringStruct *self, memcpy(_contents_chars, byteString, length); _contents_chars[length] = '\0'; _count = length; + _hash = 0; } /* Override NSString's designated initializer for CStrings. */ diff --git a/Source/NSGString.m b/Source/NSGString.m index 2d0ce03c9..7c16233a7 100644 --- a/Source/NSGString.m +++ b/Source/NSGString.m @@ -55,6 +55,14 @@ [super dealloc]; } +- (unsigned) hash +{ + if (_hash == 0) + if ((_hash = [super hash]) == 0) + _hash = 0xffffffff; + return _hash; +} + // Initializing Newly Allocated Strings /* This is the designated initializer for this class. */ @@ -302,6 +310,7 @@ stringIncrementCountAndMakeHoleAt(NSGMutableStringStruct *self, 2*(self->_count - index)); #endif /* STABLE_MEMCPY */ (self->_count) += size; + (self->_hash) = 0; } static inline void @@ -320,6 +329,7 @@ stringDecrementCountAndFillHoleAt(NSGMutableStringStruct *self, self->_contents_chars + index, 2*(self->_count - index)); #endif // STABLE_MEMCPY + (self->_hash) = 0; } // Initializing Newly Allocated Strings @@ -407,6 +417,7 @@ stringDecrementCountAndFillHoleAt(NSGMutableStringStruct *self, #endif [aString getCharacters: &_contents_chars[aRange.location]]; _count += offset; + _hash = 0; } - (void) setString: (NSString*)aString @@ -421,6 +432,7 @@ stringDecrementCountAndFillHoleAt(NSGMutableStringStruct *self, } [aString getCharacters: _contents_chars]; _count = len; + _hash = 0; } // ************ Stuff from NSGCString ********* @@ -437,6 +449,7 @@ stringDecrementCountAndFillHoleAt(NSGMutableStringStruct *self, } strtoustr(_contents_chars, byteString, length); _count = length; + _hash = 0; } /* Override NSString's designated initializer for CStrings. */ diff --git a/Source/NSString.m b/Source/NSString.m index 90dee52de..cb3838109 100644 --- a/Source/NSString.m +++ b/Source/NSString.m @@ -1261,7 +1261,7 @@ handle_printf_atsign (FILE *stream, { id obj; void *bufstate; - bufstate = (void *)pl_scan_string([self cString]); + bufstate = (void *)pl_scan_string([self cStringNoCopy]); obj = (id)plparse(); pl_delete_buffer(bufstate); return obj; @@ -1273,7 +1273,7 @@ handle_printf_atsign (FILE *stream, id dict = [[[NSMutableDictionary alloc] init] autorelease]; void *bufstate; - bufstate = (void *)sf_scan_string([self cString]); + bufstate = (void *)sf_scan_string([self cStringNoCopy]); sfSetDict(dict); sfparse(dict); sf_delete_buffer(bufstate); @@ -1416,11 +1416,15 @@ else { id mySeq, strSeq; NSRange myRange, strRange; - unsigned int myLength = [self length]; - unsigned int strLength = [aString length]; + unsigned int myLength; + unsigned int strLength; unsigned int myIndex = 0; unsigned int strIndex = 0; + if ([self hash] != [aString hash]) + return NO; + myLength = [self length]; + strLength = [aString length]; if((!myLength) && (!strLength)) return YES; if(!myLength) @@ -1484,13 +1488,12 @@ else { if(len > NSHashStringLength) len = NSHashStringLength; - OBJC_MALLOC(source, unichar, len*MAXDEC + 1); + source = alloca(sizeof(unichar)*(len*MAXDEC+1)); [self getCharacters: source range:NSMakeRange(0,len)]; source[len]=(unichar)0; // decompose - - OBJC_MALLOC(target, unichar, len*MAXDEC+1); + target = alloca(sizeof(unichar)*(len*MAXDEC+1)); spoint = source; tpoint = target; do @@ -1512,7 +1515,6 @@ else tpoint = target; spoint = source; } while(notdone); - OBJC_FREE(target); // order @@ -1554,7 +1556,6 @@ else ret ^= *p++ << ctr; ctr = (ctr + 1) % sizeof (void*); } - OBJC_FREE(source); return ret; } else @@ -1569,11 +1570,11 @@ else if(mask & NSLiteralSearch) { int prefix_len = 0; - unichar *s1; - unichar *s2; unichar *u,*w; - OBJC_MALLOC(s1, unichar,[self length] +1); - OBJC_MALLOC(s2, unichar,[aString length] +1); + unichar a1[[self length]+1]; + unichar *s1 = a1; + unichar a2[[aString length]+1]; + unichar *s2 = a2; u=s1; [self getCharacters:s1]; s1[[self length]] = (unichar)0; @@ -1597,7 +1598,6 @@ else s2++; prefix_len++; } - OBJC_FREE(w); return [NSString stringWithCharacters: u length: prefix_len]; } else @@ -2520,11 +2520,8 @@ else if ([self length] == 0 || [self rangeOfCharacterFromSet: quotables].length > 0) { - NSString *result; - const char *cstring = [self cString]; + const char *cstring = [self cStringNoCopy]; const char *from; - char *buf; - char *ptr; int len = 0; for (from = cstring; *from; from++) { @@ -2553,38 +2550,44 @@ else } } - buf = objc_malloc(len + 3); - ptr = buf; - *ptr++ = '"'; - for (from = cstring; *from; from++) { - switch (*from) { - case '\a': *ptr++ = '\\'; *ptr++ = 'a'; break; - case '\b': *ptr++ = '\\'; *ptr++ = 'b'; break; - case '\t': *ptr++ = '\\'; *ptr++ = 't'; break; - case '\r': *ptr++ = '\\'; *ptr++ = 'r'; break; - case '\n': *ptr++ = '\\'; *ptr++ = 'n'; break; - case '\v': *ptr++ = '\\'; *ptr++ = 'v'; break; - case '\f': *ptr++ = '\\'; *ptr++ = 'f'; break; - case '\\': *ptr++ = '\\'; *ptr++ = '\\'; break; - case '\'': *ptr++ = '\\'; *ptr++ = '\''; break; - case '"' : *ptr++ = '\\'; *ptr++ = '"'; break; - - default: - if (isprint(*from) || *from == ' ') { - *ptr++ = *from; - } - else { - sprintf(ptr, "\\%03o", *(unsigned char*)from); - ptr = &ptr[4]; - } - break; - } + if (len == 0) { + return @"\"\""; + } + else { + char buf[len+3]; + char *ptr = buf; + NSString *result; + + *ptr++ = '"'; + for (from = cstring; *from; from++) { + switch (*from) { + case '\a': *ptr++ = '\\'; *ptr++ = 'a'; break; + case '\b': *ptr++ = '\\'; *ptr++ = 'b'; break; + case '\t': *ptr++ = '\\'; *ptr++ = 't'; break; + case '\r': *ptr++ = '\\'; *ptr++ = 'r'; break; + case '\n': *ptr++ = '\\'; *ptr++ = 'n'; break; + case '\v': *ptr++ = '\\'; *ptr++ = 'v'; break; + case '\f': *ptr++ = '\\'; *ptr++ = 'f'; break; + case '\\': *ptr++ = '\\'; *ptr++ = '\\'; break; + case '\'': *ptr++ = '\\'; *ptr++ = '\''; break; + case '"' : *ptr++ = '\\'; *ptr++ = '"'; break; + + default: + if (isprint(*from) || *from == ' ') { + *ptr++ = *from; + } + else { + sprintf(ptr, "\\%03o", *(unsigned char*)from); + ptr = &ptr[4]; + } + break; + } + } + *ptr++ = '"'; + *ptr = '\0'; + result = [NSString stringWithCString: buf]; + return result; } - *ptr++ = '"'; - *ptr = '\0'; - result = [NSString stringWithCString: buf]; - objc_free(buf); - return result; } return self; } @@ -2793,7 +2796,6 @@ else - (unichar) characterAtIndex: (unsigned int)index { - /* xxx This should raise an NSException. */ CHECK_INDEX_RANGE_ERROR(index, _count); return (unichar)_contents_chars[index]; } diff --git a/Source/o_map.m b/Source/o_map.m index f6ab6f6ed..48d9347ff 100644 --- a/Source/o_map.m +++ b/Source/o_map.m @@ -30,6 +30,10 @@ #include #include +/* Efficiency hack - the o_map_key_callbacks() incurs a function-call + overhead and we use it a lot! */ +#define o_map_key_callbacks(X) ((X)->key_callbacks) + /* To easily un-inline functions for debugging */ #define INLINE inline