userver-framework / userver

Production-ready C++ Asynchronous Framework with rich functionality
https://userver.tech
Apache License 2.0
2.41k stars 282 forks source link

Reduce allocation count in PostgreSQL #93

Open kelbon opened 2 years ago

kelbon commented 2 years ago

https://github.com/userver-framework/userver/blob/e37c78fb0112e7befa08ef078c4de8f0fb7de607/postgresql/src/storages/postgres/options.cpp#L23

Why this global variables are not constexpr ? Seems like std::string_view may be used here without any problems.

What about unordred_map, do it constexpr may be tricky, but there are not many values and constexpr flat map can be easialy created with standard algorithms

apolukhin commented 2 years ago

Unfortunately, the problem is deeper than it looks like. Queries from this map are used to do PQ requests and the driver requires zero terminated strings at the moment.

In this ticket const char* overloads should be added to the driver first, after that the proposed optimization would be possible.

kelbon commented 1 year ago

I have tested many variations such as compile time flat maps with various implementations.

Surprising as it may seem, but I came to the conclusion that, firstly, the naive std::map of std::string_view's is not so slow(may be compiler handles this situation as special). And the second - nothing can be done faster than llvm-like string switch. So i propose to use StringSwitch here, it is very well optimized, even no strings in binary(they are in instructions cash!): godbolt link+%7B+%7D%0A%0A++StringSwitch+%26Case(StringLiteral+S,+T+Value)+%7B%0A++++if+(!!Result+%26%26+Str+%3D%3D+S)+%7B%0A++++++Result+%3D+std::move(Value)%3B%0A++++%7D%0A++++return+this%3B%0A++%7D%0A++R+Default(T+Value)+%7B%0A++++if+(Result)%0A++++++return+std::move(Result)%3B%0A++++return+Value%3B%0A++%7D%0A%7D%3B%0A%0A%0Aauto+search(const+std::string%26+s)+%7B%0A++++return+StringSwitch%3Cint%3E%7Bs%7D%0A++++.Case(%22abc%22,+4)%0A++++.Case(%22float%22,+16)%0A++++.Case(%22string%22,+-204)%0A++++.Default(-1)%3B%0A%7D'),l:'5',n:'0',o:main.cpp,t:'0')),header:(),k:61.332928620953545,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:clang1500,deviceViewOpen:'1',filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'0',intel:'0',libraryCode:'0',trim:'1'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!(),options:'-std%3Dc%2B%2B2a+-O3',selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:2),l:'5',n:'0',o:'+x86-64+clang+15.0.0+(Editor+%232)',t:'0')),header:(),k:31.392418967056386,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:output,i:(compilerName:'x86-64+clang+15.0.0',editorid:2,fontScale:14,fontUsePx:'0',j:1,wrap:'1'),l:'5',n:'0',o:'Output+of+x86-64+clang+15.0.0+(Compiler+%231)',t:'0')),k:7.274652411990104,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4) (Possibly with some improvements like optional->pointer(if it dsn't break optimizations) and interface with deduction guides from C++17)

kelbon commented 1 year ago

Oh, sorry, i forget it is map <T, strng> not <string, T> So just string->string_view will be helpfull... Or it can be array of arrays of string views... (But it can be inflexibly(possible bad bugs after enums modiying and tricky because kDeferrable is not 2 here)

enum Mode {
    kReadWrite = 0,
    kReadOnly = 1,
    kDeferrable = 3  //!< Deferrable transaction is read only
  };

Best way of course is to replace enums with tagged_enums (where type assotiated with value) and just make a visit (auto generated switch enum case)