dimanche 1 mars 2015

Why '==' is slow on std::string?

While profiling my application I realized that a lot of time is spent on string comparisons. So I wrote a simple benchmark and I was surprised that '==' is much slower than string::compare and strcmp! here is the code, can anyone explain why is that? or what's wrong with my code? because according to the standard '==' is just an operator overload and simply returnes !lhs.compare(rhs).



#include <iostream>
#include <vector>
#include <string>
#include <stdint.h>
#include "Timer.h"
#include <random>
#include <time.h>
#include <string.h>
using namespace std;
uint64_t itr = 10000000000;//10 Billion
int len = 100;
int main() {
srand(time(0));
string s1(len,random()%128);
string s2(len,random()%128);

uint64_t a = 0;
Timer t;
t.begin();
for(uint64_t i =0;i<itr;i++){
if(s1 == s2)
a = i;
}
t.end();

cout<<"== took:"<<t.elapsedMillis()<<endl;

t.begin();
for(uint64_t i =0;i<itr;i++){
if(s1.compare(s2)==0)
a = i;
}
t.end();

cout<<".compare took:"<<t.elapsedMillis()<<endl;

t.begin();
for(uint64_t i =0;i<itr;i++){
if(strcmp(s1.c_str(),s2.c_str()))
a = i;
}
t.end();

cout<<"strcmp took:"<<t.elapsedMillis()<<endl;

return a;
}


And here is the result:



== took:5986.74
.compare took:0.000349
strcmp took:0.000778


And my compile flags:


CXXFLAGS = -O3 -Wall -fmessage-length=0 -std=c++1y


I use gcc 4.9 on a x86_64 linux machine.


Obviously using -o3 does some optimizations which I guess rolls out the last two loops totally; however, using -o2 still the results are weird:


for 1 billion iterations:



== took:19591
.compare took:8318.01
strcmp took:6480.35


P.S. Timer is just a wrapper class to measure spent time; I am absolutely sure about it :D


Code for Timer class:



#include <chrono>

#ifndef SRC_TIMER_H_
#define SRC_TIMER_H_


class Timer {
std::chrono::steady_clock::time_point start;
std::chrono::steady_clock::time_point stop;
public:
Timer(){
start = std::chrono::steady_clock::now();
stop = std::chrono::steady_clock::now();
}
virtual ~Timer() {}

inline void begin() {
start = std::chrono::steady_clock::now();
}

inline void end() {
stop = std::chrono::steady_clock::now();
}

inline double elapsedMillis() {
auto diff = stop - start;
return std::chrono::duration<double, std::milli> (diff).count();
}

inline double elapsedMicro() {
auto diff = stop - start;
return std::chrono::duration<double, std::micro> (diff).count();
}

inline double elapsedNano() {
auto diff = stop - start;
return std::chrono::duration<double, std::nano> (diff).count();
}

inline double elapsedSec() {
auto diff = stop - start;
return std::chrono::duration<double> (diff).count();
}
};

#endif /* SRC_TIMER_H_ */

Aucun commentaire:

Enregistrer un commentaire