| View previous topic :: View next topic |
| Author |
Message |
Nat!

Joined: 06 Aug 2004 Posts: 42 Location: Bochum
|
Posted: Sat Sep 11, 2004 1:09 pm Post subject: NSString - stringByAppendingString vs. appendString |
|
|
When concatenating strings, appendString can outperform stringByAppendingString significantly. The appended demo code runs eight times faster with the mutable variety.
This was tested on a G5 running 10.3.5.
| Code: | #import <Foundation/Foundation.h>
NSString *foo( NSString *s, int times)
{
NSMutableString *string;
unsigned int i;
string = [NSMutableString string];
for( i = 0; i < times; i++)
[string appendString:s];
return( string);
}
NSString *bar( NSString *s, int times)
{
NSString *string;
unsigned int i;
string = @"";
for( i = 0; i < times; i++)
string = [string stringByAppendingString:s];
return( string);
}
#define LOOPS 100000
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSAutoreleasePool * pool2;
unsigned int i;
NSLog( @"Start mutable");
for( i = 0; i < LOOPS; i++)
{
pool2 = [[NSAutoreleasePool alloc] init];
foo( @"foo", 100);
[pool2 release];
}
NSLog( @"End mutable");
NSLog( @"Start immutable");
for( i = 0; i < LOOPS; i++)
{
pool2 = [[NSAutoreleasePool alloc] init];
bar( @"bar", 100);
[pool2 release];
}
NSLog( @"End immutable");
[pool release];
return 0;
}
|
|
|
| Back to top |
|
 |
zool
Joined: 13 Sep 2004 Posts: 1 Location: Magdeburg
|
Posted: Mon Sep 13, 2004 4:44 am Post subject: |
|
|
I wonder whether this is just true for Apple Foundation or whether it is generically true. The initial impression is that the immutable methods could be faster in a lot of cases since the mutable ones are more or less required to copy things around.
The more or less obvious thing to implement -stringByAppendingString would be to use a wrapper, right?
| Code: | @interface JoinedString : NSString
{
NSString **parts;
unsigned count;
}
- stringByAppendingString:x {
s = [JoinedString allocForCapacity:self->count + 1]
memcpy(s->parts, self->parts, self->count * sizeof(id));
s->parts[self->count + 1] = [x retain];
return s;
}
|
I would assume (but don't know) that this would work well in practice where a lot of append operations are being done.
But probably I'm completely wrong ;-) At least -autorelease might be the reason why the method will be always slower, but then we have Tiger ;-)
(nat) broken tags edited |
|
| Back to top |
|
 |
whitenoise
Joined: 07 Sep 2004 Posts: 5
|
Posted: Mon Sep 13, 2004 5:12 am Post subject: |
|
|
Might be interesting to reimplement NSString stringByAppendingString: in the obvious way and find out how much of the hit is allocation overhead.
But then, it shouldn't be too difficult to trace through stringByAppendingString and find out directly what's happening. Or use Shark. |
|
| Back to top |
|
 |
Nat!

Joined: 06 Aug 2004 Posts: 42 Location: Bochum
|
Posted: Mon Sep 13, 2004 2:43 pm Post subject: |
|
|
I would suggest rather s->parts[self->count + 1] = [x copy];, to avoid mutable strings corrupting your string. (Although I have heard of a fringe philosophy, that is against that kind of coding ) |
|
| Back to top |
|
 |
hfriederich
Joined: 10 Oct 2004 Posts: 1
|
Posted: Sun Oct 10, 2004 9:48 pm Post subject: |
|
|
In my attempts to optimize some code wich deals with parsing the output of another command-line program, I was coming across this page. Since it did not answers my questions directly, I did some testing on my own. Just thought you might be interested
The old code was:
NSString *new;
NSString *parseString;
NSString *tmp;
| Code: |
while( true)
{
new = [self getAllAvailableOutput] //gets all data that can be read
if([new length] > 0)
{
tmp = parseString;
parseString = [[NSString alloc] initWithFormat:@"%@%@",
parseString,
new];
[tmp release];
// now try parsing the string.
// if successful, clean the parseString (@"")
// since this part could be parsed.
}
}
|
Since this code bit gets called very often, I was wondering whether using NSMutableString was faster or not, so I did some testing. The results are quite interesting:
New code:
| Code: |
if([new length] > 0)
{
[parseString appendString:new]
// now try parsing the string.
// if successful, clean the parseString (@"")
// since this part could be parsed.
}
|
This is eventually faster than the other apprach. But this string has also to be read quite often, and reading from a MutableString is probably different than from an immutable one.
The first test was pure character reading: I used rangeOfString: and searched for a substring which wasn't present.
string: "testtesttesttesttest"
substring: "a" or "testabc"
When searching for "a", the results are completely unusable since the result was completely different at everey time.
When searching for "testabc", the time was roughly the same. Of course, this search took a lot more time since the beginning of the substring is occurring often in the teststring.
The second test was to subsequently add a string to the existing one, using the two techniques mentioned above and performing the same test as above.
The mutableString approach was always faster by a constant of about 1.6s, the overall time varied depending on the substring.
Conclusion: NSMutableString can really be faster, even if no autorelease happens at all. I guess this has to do with some optimized memory allocation in the background[/code] |
|
| Back to top |
|
 |
|