July 7, 2014

Swift, C libraries, and a Speed Test

Posted in iPhone development, mac development tagged , , , , , , , , , at 7:20 pm by tetontech

In a previous post I showed how to statically link a C library into a Swift app. I mentioned in that posting that converting data for use in libraries written in other languages can be costly. I have done some testing by passing 3 basic data types between Swift and C. The results are very interesting and not what I would have predicted based on calling C functions from other languages I’ve used.

The three types I tested were Ints, Doubles, and Strings. I did the test by calling an echo function for each type in both Swift and C. I supposed that calling the C echo function would be slower that calling the Swift echo function in each case. This was not so. It was faster to convert a Swift Int to a c int, pass it to a C function, and then convert the returned C int into a Swift Int than to call the Swift echo function that required no conversion. The difference was not huge, around 300 milliseconds for 100,000,000 calls, but it was consistent.

Doing conversions for Doubles, passing them to a C function, and converting the resultant c double to a Swift Double was also faster than calling a Swift function that echoed a Swift double it was passed. Once again the difference was not huge. There was around an 80 millisecond difference.

The Swift String to char* conversion is messy so I figured converting a Swift string and passing a char*  would be slow. It was so slow that I reduced the number of function calls I was timing to 1,000,000. Making that many calls it was around 12 times slower to convert a Swift String to a char*, pass the char* to C, and convert the resultant char* back to a Swift String.

So what conclusions do I draw? The compiler is currently optimizing C calls requiring number conversions slightly more effectively than the Swift calls. Because of this, if all I’m passing are simple things like Ints and Doubles I can go ahead and use C libraries without much concern. If I’m passing more complex things like Strings or Structs, I would avoid using them in C calls when possible.

Here is the code for the Swift and the C echo functions.

    //Swift
    func doSwiftIntStuff(anInt:Int) -> (Int){
        return anInt
    }
    func doSwiftDoubleStuff(aDouble:Double) -> (Double){
        return aDouble
    }
    func doSwiftStringStuff(aString:String) -> (String){
        return aString
    }
    //C
    int doIntStuff(int anInt){
        return anInt;
    }

    char* doStringStuff(char* aStr){
        return aStr;
    }

    double doDoubleStuff(double aDouble){
        return aDouble;
    }

Here is an example of converting and passing a Swift Int

    var initialTime = NSDate()
    let aNum = 3
    for index in 0..100_000_000 {
        let aResult = Int(doIntStuff(Int32(aNum)))
    }
    println("Swift result C int: \(initialTime.timeIntervalSinceNow)")

Here is an example of converting and passing a Swift String. Notice that this example will only handle ASCII strings.

initialTime = NSDate()
for index in 0..1_000_000 {
    var ascii = aString.dataUsingEncoding(NSASCIIStringEncoding, 
                allowLossyConversion:true)
    var stringAsChars = CChar[](count:ascii.length, repeatedValue:CChar(0))
    ascii.getBytes(&stringAsChars, length:ascii.length)
    stringAsChars.append(CChar(0))
    let aResult:String = String.fromCString(doStringStuff(&stringAsChars))
}
println("Swift result C string: \(initialTime.timeIntervalSinceNow)")

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: