[tor-commits] [tor/master] Memoize summarize_protover_flags()
nickm at torproject.org
nickm at torproject.org
Wed Nov 7 15:47:50 UTC 2018
commit 6d93820499a8bfb19128759893b18c1437f99c6b
Author: Nick Mathewson <nickm at torproject.org>
Date: Fri Oct 19 15:04:45 2018 -0400
Memoize summarize_protover_flags()
Our tests showed that this function is responsible for a huge number
of our malloc/free() calls. It's a prime candidate for being
memoized.
Closes ticket 27225.
---
changes/ticket27225 | 5 +++
src/app/main/main.c | 2 ++
src/core/or/versions.c | 82 +++++++++++++++++++++++++++++++++++++++++---------
src/core/or/versions.h | 2 ++
4 files changed, 76 insertions(+), 15 deletions(-)
diff --git a/changes/ticket27225 b/changes/ticket27225
new file mode 100644
index 000000000..4c05a269d
--- /dev/null
+++ b/changes/ticket27225
@@ -0,0 +1,5 @@
+ o Minor features (performance):
+ - Avoid parsing the same protocol-versions string over and over
+ in summarize_protover_flags(). This should save us a huge number
+ of malloc calls on startup, and may reduce memory fragmentation with
+ some allocators. Closes ticket 27225.
diff --git a/src/app/main/main.c b/src/app/main/main.c
index ae87add67..04bbfadcb 100644
--- a/src/app/main/main.c
+++ b/src/app/main/main.c
@@ -33,6 +33,7 @@
#include "core/or/relay.h"
#include "core/or/scheduler.h"
#include "core/or/status.h"
+#include "core/or/versions.h"
#include "feature/api/tor_api.h"
#include "feature/api/tor_api_internal.h"
#include "feature/client/addressmap.h"
@@ -791,6 +792,7 @@ tor_free_all(int postfork)
dos_free_all();
circuitmux_ewma_free_all();
accounting_free_all();
+ protover_summary_cache_free_all();
if (!postfork) {
config_free_all();
diff --git a/src/core/or/versions.c b/src/core/or/versions.c
index 06274996a..6f8eea7a6 100644
--- a/src/core/or/versions.c
+++ b/src/core/or/versions.c
@@ -377,6 +377,62 @@ sort_version_list(smartlist_t *versions, int remove_duplicates)
smartlist_uniq(versions, compare_tor_version_str_ptr_, tor_free_);
}
+/** If there are more than this many entries, we're probably under
+ * some kind of weird DoS. */
+static const int MAX_PROTOVER_SUMMARY_MAP_LEN = 1024;
+
+/**
+ * Map from protover string to protover_summary_flags_t.
+ */
+static strmap_t *protover_summary_map = NULL;
+
+/**
+ * Helper. Given a non-NULL protover string <b>protocols</b>, set <b>out</b>
+ * to its summary, and memoize the result in <b>protover_summary_map</b>.
+ */
+static void
+memoize_protover_summary(protover_summary_flags_t *out,
+ const char *protocols)
+{
+ if (!protover_summary_map)
+ protover_summary_map = strmap_new();
+
+ if (strmap_size(protover_summary_map) >= MAX_PROTOVER_SUMMARY_MAP_LEN) {
+ protover_summary_cache_free_all();
+ }
+
+ const protover_summary_flags_t *cached =
+ strmap_get(protover_summary_map, protocols);
+
+ if (cached != NULL) {
+ /* We found a cached entry; no need to parse this one. */
+ memcpy(out, cached, sizeof(protover_summary_flags_t));
+ tor_assert(out->protocols_known);
+ return;
+ }
+
+ memset(out, 0, sizeof(*out));
+ out->protocols_known = 1;
+ out->supports_extend2_cells =
+ protocol_list_supports_protocol(protocols, PRT_RELAY, 2);
+ out->supports_ed25519_link_handshake_compat =
+ protocol_list_supports_protocol(protocols, PRT_LINKAUTH, 3);
+ out->supports_ed25519_link_handshake_any =
+ protocol_list_supports_protocol_or_later(protocols, PRT_LINKAUTH, 3);
+ out->supports_ed25519_hs_intro =
+ protocol_list_supports_protocol(protocols, PRT_HSINTRO, 4);
+ out->supports_v3_hsdir =
+ protocol_list_supports_protocol(protocols, PRT_HSDIR,
+ PROTOVER_HSDIR_V3);
+ out->supports_v3_rendezvous_point =
+ protocol_list_supports_protocol(protocols, PRT_HSREND,
+ PROTOVER_HS_RENDEZVOUS_POINT_V3);
+
+ protover_summary_flags_t *new_cached = tor_memdup(out, sizeof(*out));
+ cached = strmap_set(protover_summary_map, protocols, new_cached);
+ tor_assert(!cached);
+}
+
/** Summarize the protocols listed in <b>protocols</b> into <b>out</b>,
* falling back or correcting them based on <b>version</b> as appropriate.
*/
@@ -388,21 +444,7 @@ summarize_protover_flags(protover_summary_flags_t *out,
tor_assert(out);
memset(out, 0, sizeof(*out));
if (protocols) {
- out->protocols_known = 1;
- out->supports_extend2_cells =
- protocol_list_supports_protocol(protocols, PRT_RELAY, 2);
- out->supports_ed25519_link_handshake_compat =
- protocol_list_supports_protocol(protocols, PRT_LINKAUTH, 3);
- out->supports_ed25519_link_handshake_any =
- protocol_list_supports_protocol_or_later(protocols, PRT_LINKAUTH, 3);
- out->supports_ed25519_hs_intro =
- protocol_list_supports_protocol(protocols, PRT_HSINTRO, 4);
- out->supports_v3_hsdir =
- protocol_list_supports_protocol(protocols, PRT_HSDIR,
- PROTOVER_HSDIR_V3);
- out->supports_v3_rendezvous_point =
- protocol_list_supports_protocol(protocols, PRT_HSREND,
- PROTOVER_HS_RENDEZVOUS_POINT_V3);
+ memoize_protover_summary(out, protocols);
}
if (version && !strcmpstart(version, "Tor ")) {
if (!out->protocols_known) {
@@ -420,3 +462,13 @@ summarize_protover_flags(protover_summary_flags_t *out,
}
}
}
+
+/**
+ * Free all space held in the protover_summary_map.
+ */
+void
+protover_summary_cache_free_all(void)
+{
+ strmap_free(protover_summary_map, tor_free_);
+ protover_summary_map = NULL;
+}
diff --git a/src/core/or/versions.h b/src/core/or/versions.h
index 0c773f3f4..4fc50a001 100644
--- a/src/core/or/versions.h
+++ b/src/core/or/versions.h
@@ -41,4 +41,6 @@ void summarize_protover_flags(protover_summary_flags_t *out,
const char *protocols,
const char *version);
+void protover_summary_cache_free_all(void);
+
#endif /* !defined(TOR_VERSIONS_H) */
More information about the tor-commits
mailing list