summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKostya Kortchinsky <kostyak@google.com>2019-03-07 21:44:35 +0000
committerKostya Kortchinsky <kostyak@google.com>2019-03-07 21:44:35 +0000
commit766a852fa5be0996303e3195ef0d655f3ce21bdb (patch)
treec711f6d1cf8157739b84a0301da393561864891b
parent890c1a29f53156b27d906ea33eb1a27cbe8cd3f3 (diff)
downloadcompiler-rt-766a852fa5be0996303e3195ef0d655f3ce21bdb.tar.gz
[scudo][standalone] Adding a stats class
Summary: This adds simple local & global stats classes to be used by the Primary and Secondary, and associated test. Note that we don't need the strict atomicity of the addition & subtraction (as is in sanitizer_common) so we just use load & store. Reviewers: morehouse, vitalybuka, eugenis, flowerhack, dmmoore415 Reviewed By: morehouse, vitalybuka Subscribers: mgorny, delcypher, jfb, #sanitizers, llvm-commits Tags: #llvm, #sanitizers Differential Revision: https://reviews.llvm.org/D59031 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@355643 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/scudo/standalone/CMakeLists.txt1
-rw-r--r--lib/scudo/standalone/stats.h105
-rw-r--r--lib/scudo/standalone/tests/CMakeLists.txt1
-rw-r--r--lib/scudo/standalone/tests/stats_test.cc45
4 files changed, 152 insertions, 0 deletions
diff --git a/lib/scudo/standalone/CMakeLists.txt b/lib/scudo/standalone/CMakeLists.txt
index 993bb9499..12461c6fb 100644
--- a/lib/scudo/standalone/CMakeLists.txt
+++ b/lib/scudo/standalone/CMakeLists.txt
@@ -46,6 +46,7 @@ set(SCUDO_HEADERS
list.h
mutex.h
platform.h
+ stats.h
vector.h)
if(COMPILER_RT_HAS_SCUDO_STANDALONE)
diff --git a/lib/scudo/standalone/stats.h b/lib/scudo/standalone/stats.h
new file mode 100644
index 000000000..7fb9c9ed6
--- /dev/null
+++ b/lib/scudo/standalone/stats.h
@@ -0,0 +1,105 @@
+//===-- stats.h -------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SCUDO_STATS_H_
+#define SCUDO_STATS_H_
+
+#include "atomic_helpers.h"
+#include "mutex.h"
+
+#include <string.h>
+
+namespace scudo {
+
+// Memory allocator statistics
+enum StatType { StatAllocated, StatMapped, StatCount };
+
+typedef uptr StatCounters[StatCount];
+
+// Per-thread stats, live in per-thread cache. We use atomics so that the
+// numbers themselves are consistent. But we don't use atomic_{add|sub} or a
+// lock, because those are expensive operations , and we only care for the stats
+// to be "somewhat" correct: eg. if we call GlobalStats::get while a thread is
+// LocalStats::add'ing, this is OK, we will still get a meaningful number.
+class LocalStats {
+public:
+ void initLinkerInitialized() {}
+ void init() { memset(this, 0, sizeof(*this)); }
+
+ void add(StatType I, uptr V) {
+ V += atomic_load_relaxed(&StatsArray[I]);
+ atomic_store_relaxed(&StatsArray[I], V);
+ }
+
+ void sub(StatType I, uptr V) {
+ V = atomic_load_relaxed(&StatsArray[I]) - V;
+ atomic_store_relaxed(&StatsArray[I], V);
+ }
+
+ void set(StatType I, uptr V) { atomic_store_relaxed(&StatsArray[I], V); }
+
+ uptr get(StatType I) const { return atomic_load_relaxed(&StatsArray[I]); }
+
+private:
+ friend class GlobalStats;
+ atomic_uptr StatsArray[StatCount];
+ LocalStats *Next;
+ LocalStats *Prev;
+};
+
+// Global stats, used for aggregation and querying.
+class GlobalStats : public LocalStats {
+public:
+ void initLinkerInitialized() {
+ Next = this;
+ Prev = this;
+ }
+ void init() {
+ memset(this, 0, sizeof(*this));
+ initLinkerInitialized();
+ }
+
+ void link(LocalStats *S) {
+ SpinMutexLock L(&Mutex);
+ S->Next = Next;
+ S->Prev = this;
+ Next->Prev = S;
+ Next = S;
+ }
+
+ void unlink(LocalStats *S) {
+ SpinMutexLock L(&Mutex);
+ S->Prev->Next = S->Next;
+ S->Next->Prev = S->Prev;
+ for (uptr I = 0; I < StatCount; I++)
+ add(static_cast<StatType>(I), S->get(static_cast<StatType>(I)));
+ }
+
+ void get(uptr *S) const {
+ memset(S, 0, StatCount * sizeof(uptr));
+ SpinMutexLock L(&Mutex);
+ const LocalStats *Stats = this;
+ for (;;) {
+ for (uptr I = 0; I < StatCount; I++)
+ S[I] += Stats->get(static_cast<StatType>(I));
+ Stats = Stats->Next;
+ if (Stats == this)
+ break;
+ }
+ // All stats must be non-negative.
+ for (uptr I = 0; I < StatCount; I++)
+ S[I] = static_cast<sptr>(S[I]) >= 0 ? S[I] : 0;
+ }
+
+private:
+ mutable StaticSpinMutex Mutex;
+};
+
+} // namespace scudo
+
+#endif // SCUDO_STATS_H_
diff --git a/lib/scudo/standalone/tests/CMakeLists.txt b/lib/scudo/standalone/tests/CMakeLists.txt
index 82fc923c5..908e51089 100644
--- a/lib/scudo/standalone/tests/CMakeLists.txt
+++ b/lib/scudo/standalone/tests/CMakeLists.txt
@@ -54,6 +54,7 @@ set(SCUDO_UNIT_TEST_SOURCES
list_test.cc
map_test.cc
mutex_test.cc
+ stats_test.cc
vector_test.cc
scudo_unit_test_main.cc)
diff --git a/lib/scudo/standalone/tests/stats_test.cc b/lib/scudo/standalone/tests/stats_test.cc
new file mode 100644
index 000000000..9ed105d3d
--- /dev/null
+++ b/lib/scudo/standalone/tests/stats_test.cc
@@ -0,0 +1,45 @@
+//===-- stats_test.cc -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "scudo/standalone/stats.h"
+#include "gtest/gtest.h"
+
+TEST(ScudoStatsTest, LocalStats) {
+ scudo::LocalStats LStats;
+ LStats.init();
+ for (scudo::uptr I = 0; I < scudo::StatCount; I++)
+ EXPECT_EQ(LStats.get(static_cast<scudo::StatType>(I)), 0U);
+ LStats.add(scudo::StatAllocated, 4096U);
+ EXPECT_EQ(LStats.get(scudo::StatAllocated), 4096U);
+ LStats.sub(scudo::StatAllocated, 4096U);
+ EXPECT_EQ(LStats.get(scudo::StatAllocated), 0U);
+ LStats.set(scudo::StatAllocated, 4096U);
+ EXPECT_EQ(LStats.get(scudo::StatAllocated), 4096U);
+}
+
+TEST(ScudoStatsTest, GlobalStats) {
+ scudo::GlobalStats GStats;
+ GStats.init();
+ scudo::uptr Counters[scudo::StatCount] = {};
+ GStats.get(Counters);
+ for (scudo::uptr I = 0; I < scudo::StatCount; I++)
+ EXPECT_EQ(Counters[I], 0U);
+ scudo::LocalStats LStats;
+ LStats.init();
+ GStats.link(&LStats);
+ for (scudo::uptr I = 0; I < scudo::StatCount; I++)
+ LStats.add(static_cast<scudo::StatType>(I), 4096U);
+ GStats.get(Counters);
+ for (scudo::uptr I = 0; I < scudo::StatCount; I++)
+ EXPECT_EQ(Counters[I], 4096U);
+ // Unlinking the local stats move numbers to the global stats.
+ GStats.unlink(&LStats);
+ GStats.get(Counters);
+ for (scudo::uptr I = 0; I < scudo::StatCount; I++)
+ EXPECT_EQ(Counters[I], 4096U);
+}