performance - Swift Dictionary slow even with optimizations: doing uncessary retain/release? -


the following code, maps simple value holders booleans, runs on 20x faster in java swift 2 - xcode 7 beta3, "fastest, aggressive optimizations [-ofast]", , "fast, whole module optimizations" turned on. can on 280m lookups/sec in java 10m in swift.

when @ in instruments see of time going pair of retain/release calls associated map lookup. suggestions on why happening or workaround appreciated.

the structure of code simplified version of real code, has more complex key class , stores other types (though boolean actual case me). also, note using single mutable key instance retrieval avoid allocating objects inside loop , according tests faster in swift immutable key.

edit: have tried switching nsmutabledictionary when used swift objects keys seems terribly slow.

edit2: have tried implementing test in objc (which wouldn't have optional unwrapping overhead) , faster still on order of magnitude slower java... i'm going pose example question see if has ideas.

edit3 - answer. have posted conclusions , workaround in answer below.

public final class mykey : hashable {     var xi : int = 0     init( _ xi : int ) { set( xi ) }       final func set( xi : int) { self.xi = xi }     public final var hashvalue: int { return xi } } public func == (lhs: mykey, rhs: mykey) -> bool {     if ( lhs === rhs ) { return true }     return lhs.xi==rhs.xi }  ... var map = dictionary<mykey,bool>() let range = 2500 x in 0...range { map[ mykey(x) ] = true } let runs = 10 _ in 0...runs {     let time = time()     let reps = 10000     let key = mykey(0)     _ in 0...reps {         x in 0...range {             key.set(x)             if ( map[ key ] == nil ) { xctasserttrue(false) }         }     }     print("rate=\(time.rate( reps*range )) lookups/s") } 

and here corresponding java code:

public class mykey  {     public int xi;     public mykey( int xi ) { set( xi ); }     public void set( int xi) { this.xi = xi; }      @override public int hashcode() { return xi; }      @override     public boolean equals( object o ) {         if ( o == ) { return true; }         mykey mk = (mykey)o;         return mk.xi == this.xi;     } } ...     map<mykey,boolean> map = new hashmap<>();     int range = 2500;         for(int x=0; x<range; x++) { map.put( new mykey(x), true ); }      int runs = 10;     for(int run=0; run<runs; run++)     {         time time = new time();         int reps = 10000;         mykey buffer = new mykey( 0 );         (int = 0; < reps; it++) {             (int x = 0; x < range; x++) {                 buffer.set( x );                 if ( map.get( buffer ) == null ) { assert.asserttrue( false ); }             }         }         float rate = reps*range/time.s();         system.out.println( "rate = " + rate );     } 

after experimentation have come conclusions , found workaround (albeit extreme).

first let me recognize kind of fine grained data structure access within tight loop not representative of general performance, affect application , i'm imagining others games , heavily numeric applications. let me know swift moving target , i'm sure improve - perhaps workaround (hacks) below not necessary time read this. if trying today , looking @ instruments , seeing majority of application time spent in retain/release , don't want rewrite entire app in objc please read on.

what have found almost 1 in swift touches object reference incurs arc retain/release penalty. additionally optional values - optional primitives - incur cost. pretty rules out using dictionary or nsdictionary.

here things fast can include in workaround:

a) arrays of primitive types.

b) arrays of final objects long as long array on stack , not on heap. e.g. declare array within method body (but outside of loop of course) , iteratively copy values it. not array(array) copy it.

putting can construct data structure based on arrays stores e.g. ints , store array indexes objects in data structure. within loop can objects index in fast local array. before ask "couldn't data structure store array me" - no, because incur 2 of penalties mentioned above :(

all things considered workaround not bad - if can enumerate entities want store in dictionary / data structure should able host them in array described. using technique above able exceed java performance factor of 2x in swift in case.

if still reading , interested @ point consider updating example code , posting.

edit: i'd add option: c) possible use unsafemutablepointer<> or unmanaged<> in swift create reference not retained when passed around. not aware of when started , hesitate recommend in general because it's hack, i've used in few cases wrap heavily used array incurring retain/release every time referenced.


Comments

Popular posts from this blog

java - Andrioid studio start fail: Fatal error initializing 'null' -

android - Gradle sync Error:Configuration with name 'default' not found -

StringGrid issue in Delphi XE8 firemonkey mobile app -