I'm implementing what is essentially a cache using a Dictionary
in Swift. The performance is well short of what I would expect. I've read some of the other questions, for example this one about array sorting that seem to suggest that -Ofast
is the answer (if you're prepared to accept the changes it brings with it). However, even when compiled -Ofast
, performance compares poorly to other languages. I'm using Swift version 1.0 (swift-600.0.34.4.8).
The following is a boiled-down example which illustrates the problem:
import Foundation
class Holder {
var dictionary = Dictionary<Int, Int>()
func store(#key: Int, value: Int) {
dictionary[key] = value
}
}
let holder = Holder()
let items = 5000
for (var i: Int = 0; i < 5000; i++) {
holder.store(key: i, value: i)
}
Compiled with -O3
it takes more than two seconds to run:
xcrun swift -sdk $(xcrun --show-sdk-path --sdk macosx) -O3 Test.swift && time ./Test
real 0m2.295s
user 0m2.176s
sys 0m0.117s
Compiling with -Ofast
yields a 3-4x improvement:
xcrun swift -sdk $(xcrun --show-sdk-path --sdk macosx) -Ofast Test.swift && time ./Test
real 0m0.602s
user 0m0.484s
sys 0m0.117s
By comparison, this Java implementation:
import java.util.Map;
import java.util.HashMap;
public class Test {
public static void main(String[] args) {
Holder holder = new Holder();
int items = 5000;
for (int i = 0; i < items; i++) {
holder.store(i, i);
}
}
}
class Holder {
private final Map<Integer, Integer> map = new HashMap<Integer, Integer>();
public void store(Integer key, Integer value) {
map.put(key, value);
}
}
is ~6x faster again:
javac Test.java && time java Test
real 0m0.096s
user 0m0.088s
sys 0m0.021s
Is it simply the cost of copying the Dictionary
as it's mutated and stored in the Holder
instance that's causing Swift to fare so badly? Removing Holder
and accessing the Dictionary
directly would suggest that it is.
This code:
import Foundation
var dictionary = Dictionary<Int, Int>()
let items = 5000
for (var i: Int = 0; i < 5000; i++) {
dictionary[i] = i
}
is significantly faster:
$ xcrun swift -sdk $(xcrun --show-sdk-path --sdk macosx) -O3 NoHolder.swift && time ./NoHolder
real 0m0.011s
user 0m0.009s
sys 0m0.002s
$ xcrun swift -sdk $(xcrun --show-sdk-path --sdk macosx) -Ofast NoHolder.swift && time ./NoHolder
real 0m0.011s
user 0m0.007s
sys 0m0.003s
While it provides a (hopefully) interesting data point, accessing the Dictionary directly isn't possible in my situation. Is there anything else I can do to get closer to this level of performance with Swift in its current form?