forked from OSchip/llvm-project
[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 llvm-svn: 355643
This commit is contained in:
parent
ed77926f99
commit
16d9a3a4b6
|
@ -46,6 +46,7 @@ set(SCUDO_HEADERS
|
|||
list.h
|
||||
mutex.h
|
||||
platform.h
|
||||
stats.h
|
||||
vector.h)
|
||||
|
||||
if(COMPILER_RT_HAS_SCUDO_STANDALONE)
|
||||
|
|
|
@ -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_
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue