stats: add mechanism to create dynamic tokens without locks or sharing#9355
stats: add mechanism to create dynamic tokens without locks or sharing#9355jmarantz merged 88 commits intoenvoyproxy:masterfrom
Conversation
Signed-off-by: Joshua Marantz <jmarantz@google.com>
…, or on the length of a fake-symbol table stat-name. Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
…es or symbols. it's bytes. Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
…ass. Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
…odel. Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
… into stats-fuzzer-not-too-long Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
jmarantz
left a comment
There was a problem hiding this comment.
Thanks for diving in. I know this is pretty hairy low-level stuff. Hopefully we've got the testing & fizzing covered.
I will follow up with more detail about the representation in stats.md.
|
|
||
| class StatNameDeathTest : public StatNameTest {}; | ||
|
|
||
| #if 0 |
There was a problem hiding this comment.
Good catch; forgot I had deferred reviving this test. Done.
|
|
||
| // When storing Symbol arrays, we disallow Symbol 0, which is the only Symbol | ||
| // that will decode into uint8_t array starting (and ending) with {0}. Thus we | ||
| // can use a leading 0 in in the first byte to indicate that what follows is |
|
|
||
| // payload_bytes is the total number of bytes needed to represent the characters | ||
| // in name, plus their encoded size, plus the literal indicator. | ||
| uint64_t payload_bytes = SymbolTableImpl::Encoding::totalSizeBytes(name.size()) + 1; |
| // So the layout is | ||
| // [ length-of-whole-StatName, LiteralStringIndicator, length-of-name, name ] | ||
| // So we need to figure out how many bytes we need to represent length-of-name and | ||
| // bytes |
| time_source_.monotonicTime() - start_decode_); | ||
|
|
||
| size_t group_index = DynamoStats::groupIndex(status); | ||
| Stats::StatNameDynamicPool dynamic(stats_->symbolTable()); |
There was a problem hiding this comment.
I think the perf implication is in the noise when there is no contention. Previously this code would construct some strings and look them up in a map, re-using a StatName on a hit. Now we construct the same strings and create an encoding of them unconditionally, skipping the map lookup and mutex acquisition. I would guess that the successful map lookup, which has to touch all the bytes of the string during the hash and again in the compare, is roughly on par with the cost of doing the unconditional encoding.
In the new scenario we'll have to do a memory allocation even for a symbol we've seen before, but in most of the cases we'll have to do a StrCat first anyway.
If you compare this to a scenario where we don't use symbol tables at all, there's some overhead because we need to re-encode the string into a block of memory that's roughly equivalent in size. But we'll still benefit when doing join() because the non-dynamic fragments (e.g. scope) that are being joined with will likely be 4 bytes or less.
Probably I should try to borrow or steal some of the infrastructure in common/http/codes.cc though so we don't have to make dynamic entries for upstream_req_total_XX and upstream_rq_time_XX, though I don't know if the XX codes are constrained the same way http codes are.
I'll try to summarize this for stats.md.
| if (downstream_cluster_.empty()) { | ||
| downstream_cluster_storage_.reset(); |
| tag_data.emplace_back(ip_tag.ip_tag_name(), cidr_set); | ||
| } | ||
| trie_ = std::make_unique<Network::LcTrie::LcTrie<std::string>>(tag_data); | ||
| // TODO(jmarantz): save stat-names for each remote address as stat_name_set builtins. |
There was a problem hiding this comment.
Not sure; I used 'address' here as trie is constructed from:
std::vector<std::string> tags =
config_->trie().getData(callbacks_->streamInfo().downstreamRemoteAddress());
but happy to use whatever terminology you think makes the most sense. Changed.
Signed-off-by: Joshua Marantz <jmarantz@google.com>
mattklein123
left a comment
There was a problem hiding this comment.
Thanks generally LGTM but will wait for the final updates to statsd.md for further review. Thank you!
/wait
source/docs/stats.md
Outdated
| as SSL ciphers or Redis commands. | ||
|
|
||
| ### Dynamic stat tokens | ||
| ### Dynnamic stat tokens |
There was a problem hiding this comment.
Done; also added a diagram showing memory layouts of a few scenarios, and a table of all the classes related to symbol tables.
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
|
@tonya11en this is the PR I mentioned to you. Can you help review the symbol table changes? Thank you. |
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
|
/retest |
|
🔨 rebuilding |
Signed-off-by: Joshua Marantz <jmarantz@google.com>
Signed-off-by: Joshua Marantz <jmarantz@google.com>
mattklein123
left a comment
There was a problem hiding this comment.
Thanks for the added docs and diagram. It's super clear to me now. This LGTM so I'm fine with merging, but I would still like @tonya11en to post review when he has time. Thank you!
| names.reserve(6); // 2 entries are added by chargeQueryStats(). | ||
| names.push_back(mongo_stats_->collection_); | ||
| names.push_back(mongo_stats_->getDynamic(active_query->query_info_.collection())); | ||
| Stats::StatNameDynamicPool dynamic(mongo_stats_->symbolTable()); |
There was a problem hiding this comment.
@jplevyak PTAL at this change even if you won't be able to review the entire PR. Note taht StatNameSet::getDynamic() is being removed in this PR in preference to this new model of making StatNames from dynamically changing strings that inline all the bytes and do not share or take locks (inspired by our discussion last month).
I imagine some of these sorts of changes will need to happen in the wasm fork.
| are scenarios where the names are newly discovered from data in requests. To | ||
| avoid taking locks in this case, tokens can be formed dynamically using | ||
| `StatNameDynamicStorage` or `StatNameDynamicPool`. In this case we lose | ||
| substring sharing but we avoid taking locks. Dynamically generaeted tokens can |
There was a problem hiding this comment.
thanks will do a quick follow-up for that so I can merge this in.
Description:
Solves the issue of lock contention for stat-name creation for names not known at compile-time.
This could be broken up into as many 3 PRs, but I think it's reviewable as is. If we did break it up we could have:
infrastructure from StatNameSet
In any case, a follow-up PR could remove the dynamics from ip_tagging_filter.cc which appears not to need them; I think all the possible tags are known at config-time. This is not included in this PR.
Risk Level: medium -- lots of bytes being messed with
Testing: //test/...
Docs Changes: n/a
Release Notes: n/a
Fixes: #7003