3 ms·
Because the performance hit of extraneous strlen() calls is generally negligible. This in turn is because strlen() maps to "repne scasb" assembly instructions,
by huhtenberg 11y ago
Because the performance hit of extraneous strlen() calls is generally negligible. This in turn is because strlen() maps to "repne scasb" assembly instructions, which run in 4 cycles per byte + 8 cycles of fixed cost. That's cheap as dirt.
You will indeed have a problem if you strcat() excessively, but then it will be a marginal case, so you will optimize for it in your own code rather than dragging it into the standard.
- vardump 11y ago> which run in 4 cycles per byte + 8 cycles of fixed cost. That's cheap as dirt. Cheap? 12 precious clock cycles is enough for up to 384 floating point operations (FMA). Not sure how fast or slow rep sca/mov is these days. Regardless, strlen that is not scanning at least 4 bytes per clock is hopelessly slow. I think you can do at least about ~16 bytes per clock. Anyways, the problem with strlen is unnecessary extra (potentially mispredicted) branches and memory accesses. I have seen enough cases where strlen has dominated cost in the profile. Of course this depends entirely what you are doing, there are plenty of workloads where strlen just doesn't occur.
- asgfoi 11y agoIsn't a modern strlen optimized into vector operations if possible anyway?
- vardump 11y agoYes. Though you still pay for the memory/branch prediction stalls.
- giggi89 11y agoso...are we trying to micro-optimize the standard library? There will be bottlenecks narrower (is that the right term?) than string operation in any project not dealing exclusively with strings. In the latter case, rolling your own string utilities may make sense
- vardump 11y agoOf course you shouldn't optimize unless it's the biggest bottleneck and more performance (or battery life) is desired. C string operations might have been elegant 40 years ago, but nowadays they're like rerouting a 747 to check if office lights are on. Strlen is doing a lot of work for little benefit. It does slow and power hungry memory accesses. Because it's scanning for terminating 0x00 byte, it needs to contain a branch -- and loop terminating branch must be a costly mis-predicted one. C printf and friends are even more insane. It scans "bytecode" instructions from a string and does dynamic formatting. You can do format options like this: printf("% 0#*.*f\n", 15, 5, 1.234); Or say print five chars of an unterminated string, left padded to total length of 10: printf("%10.5s\n", unterminated_str); It won't (at least it shouldn't) crash even if 6th character is on an unreadable memory page.
- asgfoi 11y agoI don't think they are insane. It is safe if you follow some rules. Flag -Wformat=2 catches every mistake at compile time. (It wont guard against overflow of course, but this is C) The last example is explicitly defined in the Standard.
- vardump 11y agoThe performance cost is crazy when format string is parsed at runtime. Implementing all that subtle functionality correctly takes up a lot of CPU time. According to my quick test, on Visual Studio 2012, even simplest sprintf with just one parameter seemed to take about 1 microsecond to execute. Of course clang and gcc seem to sometimes compile whole format parser away. At least... printf ("Hello World!\n"); ... is optimized into a simple "puts("Hello World!");". Of course iostream << operator runtime performance is also pretty horrible. Each << invocation seem to call streambuf::sputn (or sputc) separately. On VS2012, simplest stringstream test... ss << "value: " << intVal << endl; ... outputting one variable into it and turning the result into a std::string took about 3 microseconds. (Although it was a very quick test, a number of things might be suboptimal in the test code.)