Avoid String::printf on a hot path.
Generating unique names is expensive! The inliner does it a lot. There are two pain points: - Assemble a candidate name with String::printf - Use SymbolTable::lookup to make sure that name isn't taken already Previously, these steps took roughly the same amount of time on my machine. Afterwards, SymbolTable::lookup takes the vast majority of the time spent in uniqueName. (Further optimizing symbol lookup is a Hard Problem--trying to design something better than the current implementation in the general case is not easy.) This change gives nanobench a 1-3% win on my Macbook Pro. median mean 192µs 196µs sksl_medium (before) 185µs 189µs sksl_medium (after) 414µs 424µs sksl_large (before) 406µs 413µs sksl_large (after) Change-Id: I8e0f7f053d124827a4d50a5006129e541a20c70d Reviewed-on: https://skia-review.googlesource.com/c/skia/+/534520 Commit-Queue: John Stiles <johnstiles@google.com> Reviewed-by: Brian Osman <brianosman@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
This commit is contained in:
parent
240c55f97b
commit
c4eedcf76d
@ -641,8 +641,8 @@ generated_cc_atom(
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
":SkSLMangler_hdr",
|
||||
"//include/core:SkString_hdr",
|
||||
"//include/core:SkTypes_hdr",
|
||||
"//include/private:SkSLString_hdr",
|
||||
"//include/private:SkStringView_hdr",
|
||||
"//src/sksl/ir:SkSLSymbolTable_hdr",
|
||||
],
|
||||
|
@ -7,11 +7,12 @@
|
||||
|
||||
#include "src/sksl/SkSLMangler.h"
|
||||
|
||||
#include "include/core/SkString.h"
|
||||
#include "include/core/SkTypes.h"
|
||||
#include "include/private/SkSLString.h"
|
||||
#include "include/private/SkStringView.h"
|
||||
#include "src/sksl/ir/SkSLSymbolTable.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <ctype.h>
|
||||
|
||||
namespace SkSL {
|
||||
@ -47,16 +48,28 @@ std::string Mangler::uniqueName(std::string_view baseName, SymbolTable* symbolTa
|
||||
// Append a unique numeric prefix to avoid name overlap. Check the symbol table to make sure
|
||||
// we're not reusing an existing name. (Note that within a single compilation pass, this check
|
||||
// isn't fully comprehensive, as code isn't always generated in top-to-bottom order.)
|
||||
std::string uniqueName;
|
||||
for (;;) {
|
||||
uniqueName = SkSL::String::printf("_%d_%.*s", fCounter++,
|
||||
(int)baseName.size(), baseName.data());
|
||||
if ((*symbolTable)[uniqueName] == nullptr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return uniqueName;
|
||||
// This code is a performance hotspot. Assemble the string manually to save a few cycles.
|
||||
char uniqueName[256];
|
||||
uniqueName[0] = '_';
|
||||
char* uniqueNameEnd = uniqueName + SK_ARRAY_COUNT(uniqueName);
|
||||
for (;;) {
|
||||
// _123
|
||||
char* endPtr = SkStrAppendS32(uniqueName + 1, fCounter++);
|
||||
|
||||
// _123_
|
||||
*endPtr++ = '_';
|
||||
|
||||
// _123_baseNameTruncatedToFit (no null terminator, because string_view doesn't require one)
|
||||
int baseNameCopyLength = std::min<int>(baseName.size(), uniqueNameEnd - endPtr);
|
||||
memcpy(endPtr, baseName.data(), baseNameCopyLength);
|
||||
endPtr += baseNameCopyLength;
|
||||
|
||||
std::string_view uniqueNameView(uniqueName, endPtr - uniqueName);
|
||||
if ((*symbolTable)[uniqueNameView] == nullptr) {
|
||||
return std::string(uniqueNameView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace SkSL
|
||||
|
Loading…
Reference in New Issue
Block a user