Is simple but frequent use of std :: stringstream premature pessimization?

I have a simple script. I need to combine two C-strings together in std::string . I decided to do this in one of two ways:

Solution 1

 void ProcessEvent(char const* pName) { std::string fullName; fullName.reserve(50); // Ensure minimal reallocations for small event names (50 is an arbitrary limit). fullName += "com.domain.events."; fullName += pName; // Use fullName as needed } 

Decision 2

 void ProcessEvent(char const* pName) { std::ostringstream ss; ss << "com.domain.events." << pName; std::string fullName{ss.str()}; // Use fullName as needed } 

I like solution 2 better because the code is more natural. Solution 1 seems to be the answer to a measurable bottleneck in performance testing. However, solution 1 exists for two reasons:

  • This is an easy optimization to reduce distributions. Event management in this application is used quite often, so there may be advantages (but no measurements have been made).
  • I have heard criticism regarding the performance of WRT STR streams. Some of them recommended using a string stream only when building strings intensively, especially with regard to number conversions and / or the use of manipulators.

Is premature pessimization the preferred solution 2 for its simplicity? Or is it a premature optimization for choosing solution 1? I am wondering if I am too worried about STL streams.

+5
source share
2 answers

Let him measure

Quick test with the following features:

 void func1(const char* text) { std::string s; s.reserve(50); s += "com.domain.event."; s += text; } void func2(const char* text) { std::ostringstream oss; oss << "com.domain.event." << text; std::string s = oss.str(); } 

Running each 100,000 times in a loop gives average results on my computer (using gcc-4.9.1):

func1: 37 milliseconds

func2: 87 milliseconds

That is, func1 more than twice as fast.

Speaking of which, I would recommend using the most readable syntax until you need performance. Run the test program first, then optimize it too slowly.

Edit:

As suggested by @Ken P :

 void func3(const char* text) { std::string s = "com.domain.event" + std::string{text}; } 

func3: 27 milliseconds

The simplest solution is often the fastest.

+11
source

You did not mention the 3rd alternative to not pre-distributing anything at all in the string and just let the optimizer do what is best.

Given these two functions, func1 and func3 :

 void func1(const char* text) { std::string s; s.reserve(50); s += "com.domain.event."; s += text; std::cout << s; } void func3(const char* text) { std::string s; s += "com.domain.event."; s += text; std::cout << s; } 

The example on http://goo.gl/m8h2Ks shows that the gcc assembly for func1 will only add an extra 3 to reserve space for 50 characters compared to when pre-allocation is not performed in func3. One of the calls is the row add call, which in turn will give some overhead:

 leaq 16(%rsp), %rdi movl $50, %esi call std::basic_string<char>::append(char const*, unsigned long) 

Looking only at the code, this does not guarantee that func3 is faster than func1, though, because it has fewer instructions. Cache and other things also contribute to actual performance, which can only be measured by measuring, as others have pointed out.

0
source

Source: https://habr.com/ru/post/1205125/


All Articles