C++ 10 Feb 2011 18:24:56
C++ String Compare Performance
A performance comparison of the speed of various ways to compare strings in C++. In this test, all comparisons are of not-equal strings.
Idea from #C++ on QuakeNet, where we always advocate using std::string over various char* functions. I wondered what, if any, the penalty for doing so was.
Sources
- Ticks counted via cycle.h (local mirror)
- Source: speed-string-compare.cpp
Things Tested
- a hand-written naive comparator loop; used as baseline
- string == string
- string == const char*
- strcmp(const char*, const char*) == 0
- strcmp(const char*, string.c_str()) == 0
- strcmp(string.c_str(), string.c_str()) == 0
- string.compare(string)
- string.compare(const char*)
- …and then the whole thing with different offsets.
Observations
- clang++ beats or is on par with g++
- The penalty for using wide strings on Windows is not nearly as bad as on Linux (and in some cases faster). I speculate two reasons for this: Windows wchar_t is 16 bit versus Linux’ 32bit, and Windows uses wchar_t all over so operations on it have been greatly optimized.
Linux: GNU g++ 4.4.1
- Compiler: GNU g++ 4.4.1 -O3
- Arch: Linux 2.6.27 x86_64, 2.66GHz Xeon, 8 GiB RAM
g++ 4.4.1 [i-1] | string | relative | wide string | wide relative | wstring / string |
---|---|---|---|---|---|
naive(char*,char*) | 70548864 | 1.00 | 146879256 | 1.00 | 2.08 |
naive(string,string) | 70636792 | 1.00 | 149769000 | 1.02 | 2.12 |
string == string | 109208408 | 1.55 | 163296216 | 1.11 | 1.50 |
string == char* | 161205608 | 2.29 | 192304248 | 1.31 | 1.19 |
strcmp(char*,char*) == 0 | 70108464 | 0.99 | 104691032 | 0.71 | 1.49 |
strcmp(char*,string.c_str()) == 0 | 74368264 | 1.05 | 111933208 | 0.76 | 1.51 |
strcmp(string.c_str(),string.c_str()) == 0 | 70073112 | 0.99 | 106740088 | 0.73 | 1.52 |
string.compare(string) == 0 | 111522848 | 1.58 | 167334560 | 1.14 | 1.50 |
string.compare(char*) == 0 | 161281296 | 2.29 | 192390056 | 1.31 | 1.19 |
g++ 4.4.1 [N-i-1] | string | relative | wide string | wide relative | wstring / string |
---|---|---|---|---|---|
naive(char*,char*) | 102476928 | 1.00 | 106252416 | 1.00 | 1.04 |
naive(string,string) | 109658456 | 1.07 | 108334648 | 1.02 | 0.99 |
string == string | 128663336 | 1.26 | 128678336 | 1.21 | 1.00 |
string == char* | 156694352 | 1.53 | 208949376 | 1.97 | 1.33 |
strcmp(char*,char*) == 0 | 107413264 | 1.05 | 120358048 | 1.13 | 1.12 |
strcmp(char*,string.c_str()) == 0 | 110694952 | 1.08 | 121847008 | 1.15 | 1.10 |
strcmp(string.c_str(),string.c_str()) == 0 | 107861776 | 1.05 | 120091104 | 1.13 | 1.11 |
string.compare(string) == 0 | 140036832 | 1.37 | 133472904 | 1.26 | 0.95 |
string.compare(char*) == 0 | 155777000 | 1.52 | 209426888 | 1.97 | 1.34 |
Linux: LLVM clang++
- Compiler: clang++ 2.9 (trunk 124900) -O3
- Arch: Linux 2.6.27 x86_64, 2.66GHz Xeon, 8 GiB RAM
clang++ 2.9 (trunk 124900) [i-1] | string | relative | wide string | wide relative | wstring / string |
---|---|---|---|---|---|
naive(char*,char*) | 72880624 | 1.00 | 109667048 | 1.00 | 1.50 |
naive(string,string) | 75298816 | 1.03 | 166426672 | 1.52 | 2.21 |
string == string | 74753856 | 1.03 | 165788096 | 1.51 | 2.22 |
string == char* | 151095984 | 2.07 | 191100448 | 1.74 | 1.26 |
strcmp(char*,char*) == 0 | 69906104 | 0.96 | 103962024 | 0.95 | 1.49 |
strcmp(char*,string.c_str()) == 0 | 74283328 | 1.02 | 110578160 | 1.01 | 1.49 |
strcmp(string.c_str(),string.c_str()) == 0 | 69853048 | 0.96 | 106018768 | 0.97 | 1.52 |
string.compare(string) == 0 | 74832728 | 1.03 | 174381552 | 1.59 | 2.33 |
string.compare(char*) == 0 | 150102304 | 2.06 | 191108288 | 1.74 | 1.27 |
clang++ 2.9 (trunk 124900) [N-i-1] | string | relative | wide string | wide relative | wstring / string |
---|---|---|---|---|---|
naive(char*,char*) | 105543384 | 1.00 | 107651712 | 1.00 | 1.02 |
naive(string,string) | 110611440 | 1.05 | 109601080 | 1.02 | 0.99 |
string == string | 117346096 | 1.11 | 128253464 | 1.19 | 1.09 |
string == char* | 157304968 | 1.49 | 208092704 | 1.93 | 1.32 |
strcmp(char*,char*) == 0 | 107381600 | 1.02 | 120288216 | 1.12 | 1.12 |
strcmp(char*,string.c_str()) == 0 | 109043136 | 1.03 | 122077384 | 1.13 | 1.12 |
strcmp(string.c_str(),string.c_str()) == 0 | 107894424 | 1.02 | 120137216 | 1.12 | 1.11 |
string.compare(string) == 0 | 120340256 | 1.14 | 158334328 | 1.47 | 1.32 |
string.compare(char*) == 0 | 157230368 | 1.49 | 208066296 | 1.93 | 1.32 |
Windows: MSVC++ 2010
- Compiler: MSVC++ 2010 _SECURE_SCL=0
- Arch: Windows 7 64 bit, 1.60GHz Core i7 Q720, 8 GiB RAM
VC++ 2010 [i-1] | string | relative | wide string | wide relative | wstring / string |
---|---|---|---|---|---|
naive(char*,char*) | 17310162 | 1.00 | 18617962 | 1.00 | 1.08 |
naive(string,string) | 21068922 | 1.22 | 20266569 | 1.09 | 0.96 |
string == string | 12752892 | 0.74 | 18509380 | 0.99 | 1.45 |
string == char* | 21625936 | 1.25 | 25560502 | 1.37 | 1.18 |
strcmp(char*,char*) == 0 | 11405072 | 0.66 | 11890458 | 0.64 | 1.04 |
strcmp(char*,string.c_str()) == 0 | 14100970 | 0.81 | 15177488 | 0.82 | 1.08 |
strcmp(string.c_str(),string.c_str()) == 0 | 12042238 | 0.70 | 11107050 | 0.60 | 0.92 |
string.compare(string) == 0 | 12976402 | 0.75 | 20846298 | 1.12 | 1.61 |
string.compare(char*) == 0 | 20911296 | 1.21 | 27934932 | 1.50 | 1.34 |
VC++ 2010 [N-i-1] | string | relative | wide string | wide relative | wstring / string |
---|---|---|---|---|---|
naive(char*,char*) | 9619966 | 1.00 | 11694950 | 1.00 | 1.22 |
naive(string,string) | 9563098 | 0.99 | 9893101 | 0.85 | 1.03 |
string == string | 15224800 | 1.58 | 13599312 | 1.16 | 0.89 |
string == char* | 19673570 | 2.05 | 17800532 | 1.52 | 0.90 |
strcmp(char*,char*) == 0 | 9737620 | 1.01 | 12487770 | 1.07 | 1.28 |
strcmp(char*,string.c_str()) == 0 | 11324082 | 1.18 | 12206146 | 1.04 | 1.08 |
strcmp(string.c_str(),string.c_str()) == 0 | 10110578 | 1.05 | 9315770 | 0.80 | 0.92 |
string.compare(string) == 0 | 14627048 | 1.52 | 14993790 | 1.28 | 1.03 |
string.compare(char*) == 0 | 20797856 | 2.16 | 20710484 | 1.77 | 1.00 |
on 13 Sep 2011 at 18:51:09 1.Ayyappa said …
Hai,
Recently I also done an performance test on the same aspect.But your Performance check range(based on different envi) is relatively high.Can you please finalize the results in brief synopsis.(something like strcmp()-> which might use memcmp func is faster…).Please finalize a summary on this test.
on 14 Sep 2011 at 09:50:49 2.Tino Didriksen said …
Well, I am not very happy with this test. I can reliably reproduce the results, but the results are not what I would expect.
string op== is horrendous. There is no way in my head that a sane implementation of that should be slower than strcmp(), yet it is. And the fact that it’s even slower when comparing to char* tells me they just let the buffer get silently converted to a string, then compare…which is crazy (but it is standard compliant).
on 22 Sep 2011 at 01:51:15 3.Rodrigo said …
I personally dislike not only the operator== overloading, but the C++ operator overloading in general. To me they hide way too much what is being done, and it’s easy to neglect optimizations.