Why we didn't use a bloom filter
dr-josiah.blogspot.com
dr-josiah.blogspot.com
This fragment made me WTF, so either I missed something in the C++ development of last few years, or...
a) How can you make standard-OOP-like method dispatch faster than vtables?
b) Since when STL uses so much of virtual functions anyway? Last time I checked, it avoided any kind of polymorphism at all, for speed reasons. (and it doesn't really need to use much; C++ templates are nice tools that can make a pointer to function and a function object work in the same place just because you can stick "()" to the right of the passed parameter and it will compile, no run-time work needed).
c) (it seems to be implied, though not explicitly stated). Going faster than STL... in Python?
[1] http://morepypy.blogspot.com/2011/08/pypy-is-faster-than-c-a...
a) How can you make standard-OOP-like method dispatch
faster than vtables?
He doesn't claim you can: he just points out that it still adds overhead.If you don't use polymorphism, you don't need virtual member functions, in which case you don't pay the cost of a vtable.
This is one of the key tenets of C++: You pay for what you use, and only what you use.
STL is anything but object-oriented; Stepanov is one of the greatest critics of OO. Also, STL goes to great lengths to resolve everything at compile-time through, e.g., tag dispatch. No indirect calls are involved unless you introduce them yourself. Bounds-checking may be enabled in debug-mode in some implementations, but it can always be disabled, and ways of doing so are well-documented.
The JVM optimizes this by using (P)ICs, which are faster than regular vtables.
Well, he said he's used the STL for professionally 6 months, so he's a raw beginner by his own admission.
And no, the article does not say that Python was performing faster than the STL. In the first sentence in the "What I Built" section, "Using C, I wrote a handful of lines of C code that took a sorted sequence of 4-byte integers that represented a Twitter user's followers, and I intersected that sequence against thousands of other similar sequences for other Twitter users." I mention C twice, despite it being awful grammar. I wanted to make it clear up front that this wasn't a "Python vs. X" post.
With his custom software he's solving a completely different problem with a different algorithm that was only possible based on observations unique to his dataset:
I originally started with code very similar to the C++ STL set intersection code and was dissatisfied with the results. By observing that the longer sequences will skip more items than the shorter sequences, I wrote a 2-level loop that skips over items in the longer sequence before performing comparisons with the shorter sequence. That got me roughly a 2x performance advantage over the STL variant.
Let's call this apples. Then he talks about how using C++ STL wouldn't do the trick since he doesn't care about the data, only the count (oranges). And how bloom filters applied naïvely to the raw data would still take longer (zebras).
He's solving a completely different problem, and lambasting perfectly viable technologies for taking longer to solve a completely different problem.
Now obviously there's a good blog post and moral in there: don't solve the wrong problem. Generic algorithms can't be both generic and special at once - they're not always going to give you what you're looking for and only what you're looking for, and that's a cost to be taken into consideration at any time that you're trying to choose a solution. But don't criticize them for being slow, and then in a postscript say "and I don't need the actual results of this algorithm, anyway."
Also, keeping cache friendliness in mind in the design and choice of datastructures and algorithms is a good idea, which is the main point of his article.
What he says about vtables is fluffy though. The STL doesn't use polymorphism much.
But don't criticize them for being slow, and then in a
postscript say "and I don't need the actual results of
this algorithm, anyway."
I don't see him criticising any solution for 'being slow' in general. Only for 'being too slow for this specific problem'.It's very common to use a (already available) algorithm to calculate a result related to what you actually want and then infer the answer from that result. E.g. calculate the intersection of two sets and then count the members, instead of intersecting and counting simultaneously and never having the intersection available. It's usually a wise decision to use such the first approach: the performance penalty is acceptable and the advantage of code reuse (and not having to write and test a new algorithm) is larger. His point was that in this case, it wasn't.
If I have been using a screwdriver deck screws to attach things to my project, and some guy says "hey why don't you just use duct tape", and I explain that duct tape is very useful, but in this case its ugly and doesn't hold stuff on right, am I being unfair to duct tape? What about some guy saying "just use a hammer and nails?" and again, I mention that nails are a decent solution, but screws solve a problem introduced by the nails, am I being unfair to the hammers?
In both cases, the answer is "No". When explaining technical choices, there must be some discussion of why solutions are better or worse. When one of the criteria is speed, calling a rejected solution too slow is not unfair, just fact. It doesn't even speak to other applicability of the solution. Heck, in this case he even explicitly states he likes those tools, meaning that pointing to specific case where they aren't good is probably the opposite of "unfair".
People then come by later and say, "you should use A", or "B is better in that case", or even "C solves everything".
The article was pointing out why A, B, or C would not solve problem X as well as solution Z. A, B, and C are generic solutions for similar problems, but Z was purpose built for X.
Also, at no point did I say that the algorithms were slow, only not as fast as what we needed.
However, both articles mention that a C++/STL solution would bring in a vtable runtime penalty. This is just not true - quite the opposite: using C functions a la qsort(3) require you to explicitely pass in a pointer to the comparison function. Now: this is the vtable approach, but in plain sight. A C++ version would quite likely not call any functions via pointers.
I prepared a small test which shows that in simple cases C++ can actually be faster than C by a factor of up to 3: http://radiospiel.org/sorting-in-c-3-times-faster-than-c
Also, if speed is so important, why use qsort? It requires an indirect function call for every comparison; C++ sort or any inline implementation is faster.
Also, I would have just used the C++ set_intersection function. It seems unlikely that the 2x speedup matters since they already got it down from 7 seconds to 6ms.
The performance can be improved even further by for example using a compressed integer list with an embedded skip list or by using compressed bitmaps. Using sorted int32 lists is the naive solution :-)
"Have you ever used the STL? I did for about 6 months professionally, and I'm glad that I could go back to C and Python. More seriously, object orientation in C++ doesn't come for free. Aside from the pain of the syntax of using C++ templates (and difficult to parse error messages), all of that object orientation hides the complexity of method dispatch in what are known as vtables."
Seriously?
1. Python is faster than C++?
2. All OO features (method invocations) in C++ use the vtable?
IMHO, just using the right iterator abstraction and using the STL algorithms should be within performance limits.
In this case, a custom C algorithm is very fast. I didn't implement the C++ version, but I theorized that the C++ version would be slower because I'd already implemented the C++ algorithm first, and it was slower than what I ended up with.
I've also updated the article to remove the vtable stuff.
Of course there is a tention between fast intersections (that require a sorted data structure) and O(1) existence test of elements. It depends on what you are trying to accomplish.
I don't believe that small sets are an issue for performance.
For me, the real question is whether there are ways of getting good performance and lower memory overhead across the entire range of object sizes in Redis.