Yes, I'm talking about this site. As a comparison of computer languages, the numbers posted there are pretty useless. The example code varies wildly—for example the
code for one language will use simple non-parallel code and another will be manually parallelize across cores, use SIMD, or inline assembly. It actually makes me mad, though, because people draw conclusions from the numbers. And even well-informed people who are not experts in Swift draw incorrect conclusions about it. Swift fares really poorly on many of these marks, and it's costing Swift users.
So while I generally loathe the benchmarks game, I'm floating the idea of some people in the Swift community participating in making the Swift benchmarks better. Aside from counteracting Swift's bad rep, we'd get better information about how to optimize Swift code and learn what could be improved in the Swift backend.
There's surely a lot of low-hanging fruit here. For example, there's this program which makes Swift look 56x slower than C if you take a naïve view.
The explicit call to the needless clear() accounts for a lot of the slowdown, and the needless use of reference-semantic class also accounts for a lot. Just say no to reference semantics. This gist shows you can easily cut the time by a factor of .458 which would put Swift's performance at 25.14s in their table, 25.6x slower than C.
Of course if you write the Swift code just like the C code, with unsafe pointers, it's faster than the C, which is part of why I find the whole thing frustrating.
While that website was once popular a while back, I think a lot of PL devs got frustrated with it over the years and ignore it. The best approach to that site is to tell people to ignore it and point them at other, better benchmarks.
I believe this was tried back in the early Swift 5 days, but any improved benchmarks were rejected for using performant Swift constructs rather than blind literal translations from C.
It's a little bothering that the intuitive way to write Swift code produces non-performant code. When I look how performant code is implemented in Swift, there seems to be always unsafe pointers behind the scenes :/
It doesn't matter what PL devs think. The problem is that potential users believe it, even ones who should know better. What better benchmarks are out there to point people to?
That would be inconsistent with the Swift program I pointed at, which uses classes rather than malloc/free (and which as I said performs better than C if you do that). Only the #8 programs (like the one I posted) are supposed to be transliterated from C and as you can see, they accept other implementations. In fact it may be that my colleague just seized on this one example where Swift looks really slow
It's a little bothering that the intuitive way to write Swift code produces non-performant code. When I look how performant code is implemented in Swift, there seems to be always unsafe pointers behind the scenes.
I'm hopeful that Span and friends will start to change that
I find it a bin unconscionable that Span is being introduced without Swift ever having fixed the mutating slice CoW problem, especially because we know how to do it. The most intuitive way to get a view onto a portion of a collection is always going to be to slice it, and while—across resilience boundaries—there are always going to be overheads associated with slices that don't exist for Span, it's reasonable to assume that those overheads could be optimized away for many common uses of slices. The use of Span means either bifurcating generic code into that which can handle contiguous storage, or switching dynamically to different implementations, neither of which I would call “intuitive” or natural. Those kinds of gymnastics are fine for standard library jocks and experts who want to squeeze the last cycle out of their code, but simple, naturally-written code should be performant in Swift, and requiring a special facility—that you have to know to apply, and that only applies sometimes—in order to get performance fails to deliver on Swift's promise. It's in the name, people.
Yeah, I confused this for a different set of benchmarks.
I think the expectation is that when we get a non-copyable collection protocol, that protocol's slice associated type will be fulfilled by Span for contiguous collections, and a non-escapable (mutable) borrowing slice type for others. Therefore, any bifurcation, while unfortunate, will be temporary.
At the top of the homepage, for those who want to see, there's a URL — " Un-optimised single-thread #8 programs transliterated lowest-common-denominator style into different programming languages from the same original."
Really? Where exactly? (Which page URL.)
Code varies wildly.
At the top of the homepage — There's more than one "right" answer.
"[C]omparison of computer languages" is under-specified.
Then it seems to me “old style” slices and the natural slicing syntax will become a vestigial artifact that nobody's supposed to use except under very special circumstances, because Array is going to satisfy both protocols, and its Slice type cant change without breaking code. The problem exists even for non-generic code, you see.
Even if you could change Array's slice type, you'd likely need separate methods to return differently mutable non-escaping slices. But this is all just a best effort guess on my part, I'm not privy to any inside knowledge here.
I read everything on that page carefully, and know how to interpret the results. The problem is that other people don't.
Where exactly? (Which page URL.)
Sorry, that was from my faulty memory. No asm in those programs as far as I can tell.
Also, the Swift program there is far from being a transliteration of the C, since it uses class es instead of raw pointers. That's roughly like putting Rc (and probably at the time of the writing, Arc ) around all the instances in Rust, but with some special dynamic checks to uphold the law of exclusivity within a thread. In my experiments, a direct transliteration is slightly faster in Swift than in C for some reason.
If what's written here is true, a true transliteration was rejected for some reason.
They do not. This is a direct transliteration from C into Swift. And honestly, if using Swift's class is considered acceptable, the site should accept this use of Swift's enum, which cuts the runtime of the program to 25% of the example posted and at least according to what you just posted, would beat C by a factor of ~2, since IIUC you're saying Swift is only a little more than 2x as slow as gcc.
My understanding of #8 is that it should be an unoptimized transliteration using best practices of the target language. @dabrahams's enum version better meets this criteria than the current Swift #8 because usage of classes is generally discouraged.
@dabrahams's transliteration using unsafe would be an interesting additional entry to have as it illustrates both that a one-for-one transliteration is possible and that its performance exceeds the C version.
I'm not sure why that matters. Maybe the site needs to explain all that. Is Dart the standard from which examples are transliterated? If so, what does “lowest common denominator style” really mean? My assumption was that lowest-common-denominator meant the lowest level of abstraction that the language can provide, with the the idea being to measure the inherent overheads of a language, but maybe there's some other intent.
Anyway, the point of this thread is not to contest the fairness of your procedures; it's to encourage the Swift community to participate in your game a bit more, despite what I perceive as unfairness—which I thought you might want to encourage. But if in fact you're set on the idea that the Swift code posted there is a transliteration of the C, I can see why perhaps nobody here wants to take me up on it.
You could use swift-system. The first example in the README.md shows how to write to a file descriptor. This wraps the system calls, and not the C standard library's FILE *, though.