Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terribly Slow migrated Objc to swift code

In an application I've written I have a process that parses a large amount of data from Core-Data and displays it to a graph. While doing this processing I also end up writing the data out to a CSV File. I created a separate class called CSVLine which assists with the creation of the CSV file.
For my test case of 140k recorded my Objective-C code takes aprox 12 seconds to run. After "migrating" the class over to swift It now takes somewhere between 280-360 seconds to run. Obviously I've done something terrible.

Using Instruments I was able to identify the "slow" method and I was wondering if I've done something clear in SWIFT to cause the issue.

Objc

- (void)newLine {
//    NSLog(@"Appending %@", self.csvString);

    [outData appendData:[self csvData] ];
    [self clear];
}

- (void)clear {

    // Erase every single value

    for (NSUInteger i = 0; i < [values count]; i ++) {
        values[i] = @"";
    }
}

Swift

func newLine() {
    outData.appendData(csvData())
    clear()
}


// Clear out the Array
func clear() {
    for (var i = 0; i < values.count; i++) {
        values[i] = ""
    }
}

I'm working with various types of data that are all being written to a single CSV file so there are many blank lines. To accommodate for this I designed this class so that it has an array of keys and an array of values. The keys store the "column" names for the CSV file and values will store either a blank or a value for the index of the key for that data element.

Example:

Keys = [speed,heading,lat,lon]

values might be [200,300,"",""]

or ["","","38.553","25.2256"]

Once I'm done with a line i will write a comma joined list of the values into an internal data structure and clear out the line (erase all the items in the values array). This seems to be where the slowdown is with the swift class. Is there something blatantly "slow" i'm doing when i zero out my array?

Full Swift Class

@objc class CSVLineSwift : NSObject {
    
    // Define Arrays
    var keys: [String] = [String]()
    var values: [String] = [String]()
    
    var outData : NSMutableData = NSMutableData()
    
    override init() {
        
    }
    
    // Singelton Operator - Thread Safe :: http://code.martinrue.com/posts/the-singleton-pattern-in-swift
    class var instance : CSVLineSwift {
    
        // Computed Property
        struct Static {
            static var instance : CSVLineSwift?
            static var token: dispatch_once_t = 0
            }
    
        dispatch_once(&Static.token) {
            Static.instance = CSVLineSwift();
        }
        
        return Static.instance!
    }
    
    // Erase existing Data
    func newFile() {
        outData = NSMutableData();
        outData.appendData(headerData())
    }
    
    func csvString() -> String {
        return ",".join(values)
    }
    
    func csvData() -> NSData {
        let string = csvString()
        let data = string.dataUsingEncoding(NSUTF8StringEncoding)
        return data!
    }
    
    
    func addField(field : String) {
        keys.append(field)
        values.append("")
    }
    
    func setValueForKey(value:String, key:String) {

        if let index = find(keys, key) {
            values[index] = value
        } else {
            print( "ERROR -- There was no key: \(key) in the header Array")
        }
    }
    
    func headerString() -> String {
        return ",".join(keys)
    }
    
    func headerData() -> NSData {
       return headerString().dataUsingEncoding(NSUTF8StringEncoding)!
    }
    
 
    func newLine() {
        outData.appendData(csvData())
        clear()
    }
    
    
    // Clear out the Array
    func clear() {
        for (var i = 0; i < values.count; i++) {
            values[i] = ""
        }
    }
    
    func writeToFile(fileName : String) {
        outData.writeToFile(fileName, atomically: true)
    }
   
}
like image 657
Jeef Avatar asked Apr 24 '26 18:04

Jeef


2 Answers

Be sure that Swift's optimization level in Build Settings is not -Onone. In my experience, it is orders of magnitude slower than -O. (-O is also the default for 'release', so alternatively you could simply build for release, as already suggested.) As for 'zeroing out' the array, it might be faster (although I do not know) to simply re-initialize the array with a repeated value:

values = [String](count: values.count, repeatedValue: "")

Or if you know you will be appending the new values as you go along, and are not bound to using the indices, you could call:

values.removeAll(keepCapacity: true)

And add the new values with values.append() rather than at indices.

like image 109
Ideasthete Avatar answered Apr 27 '26 09:04

Ideasthete


It appears my issues were due to a debug build. In debug build there is no optimization. Once you do a run build the optimization kicks in and things run MUCH MUCH faster....

Similar to the answer posted here: Is Swift really slow at dealing with numbers?

like image 23
Jeef Avatar answered Apr 27 '26 07:04

Jeef



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!