It is currently Thu Mar 28, 2024 2:58 pm

Mulle kybernetiK Optimization

Forum for Optimizations around Cocoa and Mac OS X

NSString - stringByAppendingString vs. appendString

Optimizations concerning <i>Foundation</i> or <i>Objective-C</i> and its runtime
User avatar
 
Posts: 42
Joined: Fri Aug 06, 2004 9:20 am
Location: Bochum
Website: http://www.mulle-kybernetik.com/weblog

NSString - stringByAppendingString vs. appendString

Post by Nat! » Sat Sep 11, 2004 1:09 pm

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: Select all

#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;
}

 
Posts: 1
Joined: Mon Sep 13, 2004 4:35 am
Location: Magdeburg
Website: http://docs.opengroupware.org/Members/helge/

Post by zool » Mon Sep 13, 2004 4:44 am

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: Select all

@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

 
Posts: 5
Joined: Tue Sep 07, 2004 4:50 am

Post by whitenoise » Mon Sep 13, 2004 5:12 am

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.

User avatar
 
Posts: 42
Joined: Fri Aug 06, 2004 9:20 am
Location: Bochum
Website: http://www.mulle-kybernetik.com/weblog

Post by Nat! » Mon Sep 13, 2004 2:43 pm

I would suggest rather <tt> s->parts[self->count + 1] = [x <font color="red">copy</font>];</tt>, to avoid mutable strings corrupting your string. (Although I have heard of a fringe philosophy, that is against that kind of coding :roll:)

 
Posts: 1
Joined: Sun Oct 10, 2004 8:40 pm

Post by hfriederich » Sun Oct 10, 2004 9:48 pm

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: Select all

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: Select all

    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]


Return to “Foundation & Objective-C”

Who is online

Users browsing this forum: No registered users and 1 guest