This is an archive of the discontinued LLVM Phabricator instance.

[ADT] Pass string_view via copy in twine
AcceptedPublic

Authored by prehistoric-penguin on Jul 11 2022, 7:12 PM.

Details

Summary

Take the cheap object std::string_view by copy is the preferred way:

They have performance differences, pass by reference has one more level
of indirection, so we need one more instruction when compared with the
copy way For such code snippet(https://godbolt.org/z/19rWfd96W):

void TakesStringViewByValue(std::string_view s)
{
benchmark::DoNotOptimize(s.data());
}
void TakesStringViewByRef(const std::string_view& s)
{
benchmark::DoNotOptimize(s.data());
}

When getting the disassembly after build with -O3, pass by value will save us
one instruction:

TakesStringViewByValue(std::basic_string_view<char, std::char_traits<char> >):
movq %rsi, -8(%rsp)
retq
TakesStringViewByRef(std::basic_string_view<char, std::char_traits<char> > const&):
movq 8(%rdi), %rax
movq %rax, -8(%rsp)
retq
_GLOBAL__sub_I_example.cpp: # @_GLOBAL__sub_I_example.cpp
jmp benchmark::internal::InitializeStreams()@PLT # TAILCALL

And according to the abseil c++ tips week 1(https://abseil.io/tips/1),
they also recommend us to pass std::string_view by copy:

Unlike other string types, you should pass string_view by value just
like you would an int or a double because string_view is a small value.

Diff Detail

Event Timeline

Herald added a project: Restricted Project. · View Herald TranscriptJul 11 2022, 7:12 PM
prehistoric-penguin requested review of this revision.Jul 11 2022, 7:12 PM
Herald added a project: Restricted Project. · View Herald TranscriptJul 11 2022, 7:12 PM

Could you please review this minor change?

Why should these be different than the other constructors which don't take copies?

prehistoric-penguin added a comment.EditedJul 11 2022, 11:52 PM

Why should these be different than the other constructors which don't take copies?

Thanks, take the cheap object std::string_view by copy is the preferred way:

  • They have performance differences, pass by reference has one more level of indirection, so we need one more instruction when compared with the copy way

For such code snippet:

#include <string>
#include <benchmark/benchmark.h>
void TakesStringViewByValue(std::string_view s)
{
    benchmark::DoNotOptimize(s.data());
}
void TakesStringViewByRef(const std::string_view& s)
{
    benchmark::DoNotOptimize(s.data());
}

We get the disassembly after build with -O3:

TakesStringViewByValue(std::basic_string_view<char, std::char_traits<char> >): # @TakesStringViewByValue(std::basic_string_view<char, std::char_traits<char> >)
  movq %rsi, -8(%rsp)
  retq
TakesStringViewByRef(std::basic_string_view<char, std::char_traits<char> > const&): # @TakesStringViewByRef(std::basic_string_view<char, std::char_traits<char> > const&)
  movq 8(%rdi), %rax
  movq %rax, -8(%rsp)
  retq
_GLOBAL__sub_I_example.cpp: # @_GLOBAL__sub_I_example.cpp
  jmp benchmark::internal::InitializeStreams()@PLT # TAILCALL

And according to the abseil c++ tips week 1, they also recommend us to pass std::string_view by copy:

Unlike other string types, you should pass string_view by value just like you would an int or a double because string_view is a small value.

Remind me - can we forward declare string_view or is it a bulky header dependent nightmare like std::string ?

llvm/include/llvm/ADT/Twine.h
304

This probably should be done seperately and part of a larger refactor away from const StringRef & args IF we can confirm that its beneficial - it will probably need an update in the coding guidelines as well.

prehistoric-penguin marked an inline comment as done.Jul 12 2022, 8:56 PM
prehistoric-penguin added inline comments.
llvm/include/llvm/ADT/Twine.h
304

Thanks! Could you please elaborate more on larger refactor? I am interested in this.

prehistoric-penguin marked an inline comment as done.Jul 13 2022, 12:14 AM
RKSimon added inline comments.Jul 14 2022, 3:45 AM
llvm/include/llvm/ADT/Twine.h
304

We have hundreds of uses of "const StringRef &" as function arguments - and the trade off will be to determine whether we get improvement in performance vs the additional cost of having to define StringRef in more headers.

<string> is already one of the most costly headers to include in llvm and making that worse (via including StringRef.h) doesn't sounds like a good idea: https://commondatastorage.googleapis.com/chromium-browser-clang/llvm-include-analysis.html

RKSimon added inline comments.Jul 18 2022, 2:11 AM
llvm/include/llvm/ADT/Twine.h
293–294

Please can you add to the comment that passing string_view by value is preferred.

[ADT] Pass string_view via copy in twine

prehistoric-penguin marked an inline comment as done.Jul 18 2022, 7:26 PM
prehistoric-penguin marked an inline comment as done.Jul 18 2022, 7:31 PM
This comment was removed by prehistoric-penguin.
llvm/include/llvm/ADT/Twine.h
304

Thanks for the comment, I'm going to do some experiments and update the results of my research later.

The string_view only patch looks almost ready and can be handled separately from any StringRef changes you make - please can you add a better subject description next?

prehistoric-penguin retitled this revision from [ADT] Pass string_view via copy to [ADT] Pass string_view via copy in twine.Jul 20 2022, 3:57 AM

The string_view only patch looks almost ready and can be handled separately from any StringRef changes you make - please can you add a better subject description next?

Thanks! Could you please explain better subject description next? I guess I need to change the title here. Or to make a better description in the features patcher?

Explain why the patch passes the string_view via copy

Update commit message

RKSimon requested changes to this revision.Jul 21 2022, 3:54 AM

You're still missing a patch description explaining why pass by value is preferred

This revision now requires changes to proceed.Jul 21 2022, 3:54 AM

Take the cheap object std::string_view by copy is the preferred way:

They have performance differences, pass by reference has one more level
of indirection, so we need one more instruction when compared with the
copy way For such code snippet(https://godbolt.org/z/19rWfd96W):

void TakesStringViewByValue(std::string_view s)
{
benchmark::DoNotOptimize(s.data());
}
void TakesStringViewByRef(const std::string_view& s)
{
benchmark::DoNotOptimize(s.data());
}

When get the disassembly after build with -O3, pass by value will save us
one instruction:

TakesStringViewByValue(std::basic_string_view<char, std::char_traits<char> >):
movq %rsi, -8(%rsp)
retq
TakesStringViewByRef(std::basic_string_view<char, std::char_traits<char> > const&):
movq 8(%rdi), %rax
movq %rax, -8(%rsp)
retq
_GLOBAL__sub_I_example.cpp: # @_GLOBAL__sub_I_example.cpp
jmp benchmark::internal::InitializeStreams()@PLT # TAILCALL

And according to the abseil c++ tips week 1(https://abseil.io/tips/1),
they also recommend us to pass std::string_view by copy:

 Unlike other string types, you should pass string_view by value just
like you would an int or a double because string_view is a small value.
prehistoric-penguin edited the summary of this revision. (Show Details)Jul 21 2022, 8:16 PM
prehistoric-penguin edited the summary of this revision. (Show Details)

You're still missing a patch description explaining why pass by value is preferred

Thanks, finally I realize maybe you're referring to the summary part!

RKSimon accepted this revision.Jul 22 2022, 12:34 AM

LGTM cheers

This revision is now accepted and ready to land.Jul 22 2022, 12:34 AM