5 ms·
While you can write very fast code in C, that doesn't imply that if you spend the same amount of effort solving the same problem in C and in Rust, the C version
by the_why_of_y 10y ago
While you can write very fast code in C, that doesn't imply that if you spend the same amount of effort solving the same problem in C and in Rust, the C version will be faster, because Rust's type system lets you write programs that exploit traditionally error-prone things like unique ownership and multi-threading in much less development and debugging time than C.
- Const-me 10y agoVery fast code in C often means manually vectorized code, written in SSE/AVX/Neon intrinsics. Rust type system prevents same for Rust. Those __m128 values are just raw bytes, different SIMD instructions view them as different types, and Rust's type system ain't OK with that.
- burntsushi 10y agoRust's regex library uses manually vectorized code to speed up its search algorithms, so it follows that Rust's type system is more than OK with such things.
- Const-me 10y agoThey were lucky. Those regexps were OK only using a single register representation, u8x16. That’s not always the case. To write efficient SSE code, you need to understand __m128i is a just a hardware register, and use whatever representation you need for particular instruction. Example: http://stackoverflow.com/a/17355341/126995 http://stackoverflow.com/a/17355341/126995 The SSE2 code is impossible to translate to Rust, because _mm_sub_epi8 views the registers as std::simd::i8x16, while the subsequent _mm_srli_epi64 views the same registers as std::simd::i64x2
- burntsushi 10y agoIt's not impossible at all. You can use the raw intrinsics in Rust just like you'd use them in C if you want to. > The SSE2 code is impossible to translate to Rust, because _mm_sub_epi8 views the registers as std::simd::i8x16, while the subsequent _mm_srli_epi64 views the same registers as std::simd::i64x2 That's false. It might be impossible to implement that code safely using the current simd crate as is (which is not in the standard library), but the simd crate is an abstraction over the raw intrinsics and isn't blessed by the language. You can reach in and use the raw intrinsics (or unsafely cast between SIMD types). If you look more closely at the SIMD algorithm in the regex crate I wrote, you can see that I'm already doing this (to convert from an `&[u8]` to an `u8x16` without bounds checks). Popping up a level, I can understand why this is not obvious from an outside observer. The SIMD story on Rust is very much still evolving, and we don't have it all completely worked out yet. When we do, I predict it will be awesome. :-) I have a whole bunch of ideas on how to use it to improve text search even more!
- steveklabnik 10y agoLLVM already auto-vectorizes sometimes, and you can still drop down to `unsafe` to write explicit SIMD (though it's not yet stable).
- the_why_of_y 10y agoSo very fast code in C is not actually C code, but written in a non-standard extended C dialect that is also platform specific - thanks for clarifying. I'm curious if there is a way to limit the entries in the Benchmark Game to just those that actually use only the language standards, where those exist...
- burntsushi 10y agoTo be clear, using SIMD doesn't require some "non-standard extended C dialect." We very much want a better SIMD story on Rust, and the benchmark game entries should definitely be allowed to use SIMD. SIMD will get you into platform specific woes unfortunately, but that shouldn't stop us. :-)
- Const-me 10y agoWhat are you talking about? Intrinsics are perfectly valid C99 code. __int64i is a union with 8 different arrays in it, and intrinsics are library functions.
- the_why_of_y 10y agoThe words "SIMD", "intrinsic", "__m64", "__m128" do not occur in the C11 draft text; the word "vector" occurs once in example code for an array-with-length struct. http://www.iso-9899.info/n1570.html http://www.iso-9899.info/n1570.html Intrinsics are not library functions - they would hardly provide the desired performance benefit if they were. Intrinsics are "magic" functions that the compiler has built-in support for, and thus I would call them language extensions. For example from GCC header avxintrin.h: extern __inline __m256d __attribute__((__gnu_inline__, __always_inline__, __artificial__)) _mm256_permute2f128_pd (__m256d __X, __m256d __Y, const int __C) { return (__m256d) __builtin_ia32_vperm2f128_pd256 ((__v4df)__X, (__v4df)__Y, __C); } Over here the word "__builtin_ia32_vperm2f128_pd256" occurs in the "cc1" and "cc1plus" binaries and "avxintrin.h", but nowhere else. Notably there is no externally visible definition.
- Const-me 10y ago