Is Prefix of String in Table? a Journey into SIMD String Processing
11–20 of 61 posts
Re: Is Prefix of String in Table? a Journey into SIMD String Processing
#12Side note: people have been inquiring how I made the diagrams and whatnot. I'll put a little section like that on the next article. For now though: The two main diagrams, depicting struct layout and then the 5-pane register walk through, were done in Visio, then saved as SVG, with fonts edited directly in Vim (took a few cycles to figure out which fonts looked best across all devices). The charts were done in Excel,…
I admire your attention to detail and keen sense of aesthetics. Well done.
[1]: https://twitter.com/joewalnes/status/567495778349113345 [2]: http://websocketd.com/ [3]: http://pyparallel.org/
Re: Is Prefix of String in Table? a Journey into SIMD String Processing
#13Curious if GPU is suitable for similar tasks? Any successful GPU based json or http parser.
The overhead of dispatching a kernel to the GPU (and subsequent memory copy of the search string) would take tens of thousands (if not hundreds of thousands) of CPU cycles, so, it's not really applicable in this single-shot prefix lookup case.
Where it would be interesting: much larger prefix data sets (say, the name of all known cities, states, countries etc) and identifying where they occur in an even larger text corpus (like a wikipedia dump).
In that approach, you'd obviously compare against a multi-threaded CPU implementation... but, it'd be interesting to see the comparison.
Re: Is Prefix of String in Table? a Journey into SIMD String Processing
#14Re: Is Prefix of String in Table? a Journey into SIMD String Processing
#15Have you done some comparison with a trie implementation (known for good performance on prefix matching, see: https://en.wikipedia.org/wiki/Trie )
However, they inevitably involve pointer chasing, are quite branchy, and not really amenable to SIMD optimizations. They also do not have any means in place for doing a fast-path negative match, which was important for me.
I think you'd really struggle to get anything based on pointer chasing and binary search to compete with the CPU cycle counts I was seeing toward the end for the assembly versions (e.g. 6 cycles for negative match, 14 for prefix match, 21 for worst-case false-positive negative match).
I comment a little bit about it here: http://trent.me/is-prefix-of-string-in-table/#other-applicat...
> The other nice side-effect is that it forces you to pick which table a given string should go in. I made this decision by looking at which types occurred most frequently, and simply put those in the first table. Less frequent types go in subsequent tables.
> I have a hunch there's a lot of mileage in that approach; that is, linear scanning an array of string tables until a match is found. There will be an inflection point where some form of a log(n) binary tree search will perform better overall, but it would be very interesting to see how many strings you need to potentially match against before that point is hit.
> Unless the likelihood of matching any given string in your set is completely random, by ordering the strings in your tables by how frequently they occur, the amortized cost of parsing a chunk of text would be very competitive using this approach, I would think.
> A fun experiment for next time, perhaps!
Re: Is Prefix of String in Table? a Journey into SIMD String Processing
#16This seems like a complicated way to speed up a linear scan. What's the advantage of this approach over just sorting the strings and doing a binary search, which is log N? (Not a naive binary search using strcmp, but the trick where you find the lower and upper bounds given index 0, refine it using index 1, etc. until your input is exhausted.)
He was only searching 16 strings. The overhead of a binary search on such a small N would likely overwhelm the algorithmic improvements of moving from an O(N) to O(log N) implementation.
Re: Is Prefix of String in Table? a Journey into SIMD String Processing
#17This seems like a complicated way to speed up a linear scan. What's the advantage of this approach over just sorting the strings and doing a binary search, which is log N? (Not a naive binary search using strcmp, but the trick where you find the lower and upper bounds given index 0, refine it using index 1, etc. until your input is exhausted.)
Sorting the strings by length, or lexicographical? Length sort wouldn't work for the prefix-oriented nature of the comparisons. Lexicographical sorting and a binary search involves pointer chasing, and doesn't provide any way to fast-path the negative match lookup. If I'm getting called a trillion times on a hot-path, but only a million of those times I'm receiving a module name (search string) I'm interested in, the…
Some constructive feedback: move that information up to the "Goal" section, maybe with a motivating example. The fact that the set size is <= 16 is important to know before discussing cycle counts.
Re: Is Prefix of String in Table? a Journey into SIMD String Processing
#18SIMD-units of the x86-64 CPU are not discussed enough IMO. And every time they are discussed, I'm always blown away by their efficiency in solving some tasks.
---------------
Full disclosure: I don't understand what you've done yet. I've just skimmed the article really quick, but I already have some questions. Hopefully you didn't answer them already elsewhere, lol.
* Any reason to highly-optimize "strings of length 16" instead of "strings of length 32" ?? The vast majority of your code uses "xmm" registers (16-bytes), but it would seem like it'd be straightforward to target ymm registers (32-bytes) instead.
Were there any particular reason why you chose 16-bytes instead of 32-bytes? Like maybe targeting AVX but not AVX2?? (Then again, I see a rare ymm register here and there... sooo... I guess I'm just a bit confused with the design decision)
* SSE4.2 has string-specific instructions. Did you look into any of the SSE4.2 string instructions to see if they'd help in your case? (Ironically, forcing you back down to xmm registers, since its SSE only. So kind of a contradiction with my first question, lol) I fully admit that I don't actually know how to use the SSE4.2 string instructions, so don't look into my question too hard.
------------
I'll have to spend some time studying your code and explanation. Thank you very much for the writeup! It will be helpful for my SIMD-studies. There really isn't enough material out there on AVX / SSE optimizations.
Re: Is Prefix of String in Table? a Journey into SIMD String Processing
#19Absolutely excellent! SIMD-units of the x86-64 CPU are not discussed enough IMO. And every time they are discussed, I'm always blown away by their efficiency in solving some tasks. --------------- Full disclosure: I don't understand what you've done yet. I've just skimmed the article really quick, but I already have some questions. Hopefully you didn't answer them already elsewhere, lol. * Any reason to highly-optimi…
Yeah, my target use case rarely had strings longer than 16 (which is quite common for prefix matching problems in the real world), so, 16 made the most sense. I'll probably do an AVX2 and AVX-512 version down the track; as I'll have 32-byte and 64-byte registers to play with, it will allow me to do some more interesting things (either longer prefix strings, or more comparisons).
> * SSE4.2 has string-specific instructions. Did you look into any of the SSE4.2 string instructions to see if they'd help in your case? (Ironically, forcing you back down to xmm registers, since its SSE only. So kind of a contradiction with my first question, lol) I fully admit that I don't actually know how to use the SSE4.2 string instructions, so don't look into my question too hard.
The instructions like pcmpistri were considered and explicitly rejected :-) They are surprisingly slow, and they only process 16 characters at a time, so you don't get the implicit benefits on longer strings that you would expect if you could do like a `rep pcmpistri` or something (like the accelerated `rep stosq` etc).
The first twelve instructions for the negative match logic execute in about 6 CPU cycles. A pcmpistri-type instruction will often clock in around 7-14 cycles. So, with my approach, using the "basically free" instructions like vpcmpeqb, vpcmpgtb etc, I can detect if my input string doesn't have any prefix matches in a table of 16 prefixes in ~6 cycles, which is pretty neat.
Re: Is Prefix of String in Table? a Journey into SIMD String Processing
#20Find a 128-bit mask that will be used to select bits of the input string. You want to minimize the number of 1 bits in the mask, since the table size is 2^(number of 1 bits). On the other hand, you need to pick enough 1 bits so that there is only one string per table entry.
AND this mask with the input string. COMPRESS these bits using the mask. The result is the index into the table. Each entry has a string to compare and thermometer coded mask (number of 1 bits equals length of string in bits). AND the input string with the thermometer coded mask and compare it with the string. If they match, you have a hit.
COMPRESS (or generalized extract) means to move selected bits to the right so that they are all next to each other and adjacent to the LSB. There is a clever algorithm for this, see section 7-4 of Hacker's Delight: