summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKostya Kortchinsky <kostyak@google.com>2019-10-09 15:09:28 +0000
committerKostya Kortchinsky <kostyak@google.com>2019-10-09 15:09:28 +0000
commite5d05814ac964a37eb336fb5a743227e55e85a41 (patch)
tree5f523fd7bc248b230732ec33ca41cd2679d36b2c
parentb185f4f2ef7c96095d31e09b041ffe81b4b24571 (diff)
downloadcompiler-rt-e5d05814ac964a37eb336fb5a743227e55e85a41.tar.gz
[scudo][standalone] Get statistics in a char buffer
Summary: Following up on D68471, this CL introduces some `getStats` APIs to gather statistics in char buffers (`ScopedString` really) instead of printing them out right away. Ultimately `printStats` will just output the buffer, but that allows us to potentially do some work on the intermediate buffer, and can be used for a `mallocz` type of functionality. This allows us to pretty much get rid of all the `Printf` calls around, but I am keeping the function in for debugging purposes. This changes the existing tests to use the new APIs when required. I will add new tests as suggested in D68471 in another CL. Reviewers: morehouse, hctim, vitalybuka, eugenis, cferris Reviewed By: morehouse Subscribers: delcypher, #sanitizers, llvm-commits Tags: #llvm, #sanitizers Differential Revision: https://reviews.llvm.org/D68653 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@374173 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/scudo/standalone/combined.h32
-rw-r--r--lib/scudo/standalone/crc32_hw.cpp2
-rw-r--r--lib/scudo/standalone/primary32.h22
-rw-r--r--lib/scudo/standalone/primary64.h37
-rw-r--r--lib/scudo/standalone/quarantine.h20
-rw-r--r--lib/scudo/standalone/secondary.cpp13
-rw-r--r--lib/scudo/standalone/secondary.h3
-rw-r--r--lib/scudo/standalone/size_class_map.h8
-rw-r--r--lib/scudo/standalone/string_utils.cpp17
-rw-r--r--lib/scudo/standalone/string_utils.h1
-rw-r--r--lib/scudo/standalone/tests/combined_test.cpp16
-rw-r--r--lib/scudo/standalone/tests/primary_test.cpp19
-rw-r--r--lib/scudo/standalone/tests/quarantine_test.cpp8
-rw-r--r--lib/scudo/standalone/tests/secondary_test.cpp16
14 files changed, 145 insertions, 69 deletions
diff --git a/lib/scudo/standalone/combined.h b/lib/scudo/standalone/combined.h
index b2dc25f78..60be1dd20 100644
--- a/lib/scudo/standalone/combined.h
+++ b/lib/scudo/standalone/combined.h
@@ -369,12 +369,31 @@ public:
Primary.enable();
}
+ // The function returns the amount of bytes required to store the statistics,
+ // which might be larger than the amount of bytes provided. Note that the
+ // statistics buffer is not necessarily constant between calls to this
+ // function. This can be called with a null buffer or zero size for buffer
+ // sizing purposes.
+ uptr getStats(char *Buffer, uptr Size) {
+ ScopedString Str(1024);
+ disable();
+ const uptr Length = getStats(&Str) + 1;
+ enable();
+ if (Length < Size)
+ Size = Length;
+ if (Buffer && Size) {
+ memcpy(Buffer, Str.data(), Size);
+ Buffer[Size - 1] = '\0';
+ }
+ return Length;
+ }
+
void printStats() {
+ ScopedString Str(1024);
disable();
- Primary.printStats();
- Secondary.printStats();
- Quarantine.printStats();
+ getStats(&Str);
enable();
+ Str.output();
}
void releaseToOS() { Primary.releaseToOS(); }
@@ -563,6 +582,13 @@ private:
*Size = getSize(Ptr, &Header);
return P;
}
+
+ uptr getStats(ScopedString *Str) {
+ Primary.getStats(Str);
+ Secondary.getStats(Str);
+ Quarantine.getStats(Str);
+ return Str->length();
+ }
};
} // namespace scudo
diff --git a/lib/scudo/standalone/crc32_hw.cpp b/lib/scudo/standalone/crc32_hw.cpp
index f4dae7b5f..62841ba51 100644
--- a/lib/scudo/standalone/crc32_hw.cpp
+++ b/lib/scudo/standalone/crc32_hw.cpp
@@ -1,4 +1,4 @@
-//===-- crc32_hw.h ----------------------------------------------*- C++ -*-===//
+//===-- crc32_hw.cpp --------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lib/scudo/standalone/primary32.h b/lib/scudo/standalone/primary32.h
index a9fbb70bc..9123d07b4 100644
--- a/lib/scudo/standalone/primary32.h
+++ b/lib/scudo/standalone/primary32.h
@@ -143,7 +143,7 @@ public:
}
}
- void printStats() {
+ void getStats(ScopedString *Str) {
// TODO(kostyak): get the RSS per region.
uptr TotalMapped = 0;
uptr PoppedBlocks = 0;
@@ -154,11 +154,11 @@ public:
PoppedBlocks += Sci->Stats.PoppedBlocks;
PushedBlocks += Sci->Stats.PushedBlocks;
}
- Printf("Stats: SizeClassAllocator32: %zuM mapped in %zu allocations; "
- "remains %zu\n",
- TotalMapped >> 20, PoppedBlocks, PoppedBlocks - PushedBlocks);
+ Str->append("Stats: SizeClassAllocator32: %zuM mapped in %zu allocations; "
+ "remains %zu\n",
+ TotalMapped >> 20, PoppedBlocks, PoppedBlocks - PushedBlocks);
for (uptr I = 0; I < NumClasses; I++)
- printStats(I, 0);
+ getStats(Str, I, 0);
}
uptr releaseToOS() {
@@ -328,17 +328,17 @@ private:
return B;
}
- void printStats(uptr ClassId, uptr Rss) {
+ void getStats(ScopedString *Str, uptr ClassId, uptr Rss) {
SizeClassInfo *Sci = getSizeClassInfo(ClassId);
if (Sci->AllocatedUser == 0)
return;
const uptr InUse = Sci->Stats.PoppedBlocks - Sci->Stats.PushedBlocks;
const uptr AvailableChunks = Sci->AllocatedUser / getSizeByClassId(ClassId);
- Printf(" %02zu (%6zu): mapped: %6zuK popped: %7zu pushed: %7zu inuse: %6zu"
- " avail: %6zu rss: %6zuK\n",
- ClassId, getSizeByClassId(ClassId), Sci->AllocatedUser >> 10,
- Sci->Stats.PoppedBlocks, Sci->Stats.PushedBlocks, InUse,
- AvailableChunks, Rss >> 10);
+ Str->append(" %02zu (%6zu): mapped: %6zuK popped: %7zu pushed: %7zu "
+ "inuse: %6zu avail: %6zu rss: %6zuK\n",
+ ClassId, getSizeByClassId(ClassId), Sci->AllocatedUser >> 10,
+ Sci->Stats.PoppedBlocks, Sci->Stats.PushedBlocks, InUse,
+ AvailableChunks, Rss >> 10);
}
NOINLINE uptr releaseToOSMaybe(SizeClassInfo *Sci, uptr ClassId,
diff --git a/lib/scudo/standalone/primary64.h b/lib/scudo/standalone/primary64.h
index f56387b05..8f443ea7f 100644
--- a/lib/scudo/standalone/primary64.h
+++ b/lib/scudo/standalone/primary64.h
@@ -147,7 +147,7 @@ public:
}
}
- void printStats() const {
+ void getStats(ScopedString *Str) const {
// TODO(kostyak): get the RSS per region.
uptr TotalMapped = 0;
uptr PoppedBlocks = 0;
@@ -159,12 +159,13 @@ public:
PoppedBlocks += Region->Stats.PoppedBlocks;
PushedBlocks += Region->Stats.PushedBlocks;
}
- Printf("Stats: Primary64: %zuM mapped (%zuM rss) in %zu allocations; "
- "remains %zu\n",
- TotalMapped >> 20, 0, PoppedBlocks, PoppedBlocks - PushedBlocks);
+ Str->append("Stats: SizeClassAllocator64: %zuM mapped (%zuM rss) in %zu "
+ "allocations; remains %zu\n",
+ TotalMapped >> 20, 0, PoppedBlocks,
+ PoppedBlocks - PushedBlocks);
for (uptr I = 0; I < NumClasses; I++)
- printStats(I, 0);
+ getStats(Str, I, 0);
}
uptr releaseToOS() {
@@ -269,10 +270,12 @@ private:
if (UNLIKELY(RegionBase + MappedUser + UserMapSize > RegionSize)) {
if (!Region->Exhausted) {
Region->Exhausted = true;
- printStats();
- Printf(
+ ScopedString Str(1024);
+ getStats(&Str);
+ Str.append(
"Scudo OOM: The process has Exhausted %zuM for size class %zu.\n",
RegionSize >> 20, Size);
+ Str.output();
}
return nullptr;
}
@@ -322,21 +325,21 @@ private:
return B;
}
- void printStats(uptr ClassId, uptr Rss) const {
+ void getStats(ScopedString *Str, uptr ClassId, uptr Rss) const {
RegionInfo *Region = getRegionInfo(ClassId);
if (Region->MappedUser == 0)
return;
const uptr InUse = Region->Stats.PoppedBlocks - Region->Stats.PushedBlocks;
const uptr TotalChunks = Region->AllocatedUser / getSizeByClassId(ClassId);
- Printf("%s %02zu (%6zu): mapped: %6zuK popped: %7zu pushed: %7zu inuse: "
- "%6zu total: %6zu rss: %6zuK releases: %6zu last released: %6zuK "
- "region: 0x%zx (0x%zx)\n",
- Region->Exhausted ? "F" : " ", ClassId, getSizeByClassId(ClassId),
- Region->MappedUser >> 10, Region->Stats.PoppedBlocks,
- Region->Stats.PushedBlocks, InUse, TotalChunks, Rss >> 10,
- Region->ReleaseInfo.RangesReleased,
- Region->ReleaseInfo.LastReleasedBytes >> 10, Region->RegionBeg,
- getRegionBaseByClassId(ClassId));
+ Str->append("%s %02zu (%6zu): mapped: %6zuK popped: %7zu pushed: %7zu "
+ "inuse: %6zu total: %6zu rss: %6zuK releases: %6zu last "
+ "released: %6zuK region: 0x%zx (0x%zx)\n",
+ Region->Exhausted ? "F" : " ", ClassId,
+ getSizeByClassId(ClassId), Region->MappedUser >> 10,
+ Region->Stats.PoppedBlocks, Region->Stats.PushedBlocks, InUse,
+ TotalChunks, Rss >> 10, Region->ReleaseInfo.RangesReleased,
+ Region->ReleaseInfo.LastReleasedBytes >> 10, Region->RegionBeg,
+ getRegionBaseByClassId(ClassId));
}
NOINLINE uptr releaseToOSMaybe(RegionInfo *Region, uptr ClassId,
diff --git a/lib/scudo/standalone/quarantine.h b/lib/scudo/standalone/quarantine.h
index 732373aba..35fd0bc19 100644
--- a/lib/scudo/standalone/quarantine.h
+++ b/lib/scudo/standalone/quarantine.h
@@ -130,7 +130,7 @@ public:
subFromSize(ExtractedSize);
}
- void printStats() const {
+ void getStats(ScopedString *Str) const {
uptr BatchCount = 0;
uptr TotalOverheadBytes = 0;
uptr TotalBytes = 0;
@@ -152,11 +152,11 @@ public:
(TotalQuarantinedBytes == 0)
? 0
: TotalOverheadBytes * 100 / TotalQuarantinedBytes;
- Printf("Global quarantine stats: batches: %zu; bytes: %zu (user: %zu); "
- "chunks: %zu (capacity: %zu); %zu%% chunks used; %zu%% memory "
- "overhead\n",
- BatchCount, TotalBytes, TotalQuarantinedBytes, TotalQuarantineChunks,
- QuarantineChunksCapacity, ChunksUsagePercent, MemoryOverheadPercent);
+ Str->append(
+ "Stats: Quarantine: batches: %zu; bytes: %zu (user: %zu); chunks: %zu "
+ "(capacity: %zu); %zu%% chunks used; %zu%% memory overhead\n",
+ BatchCount, TotalBytes, TotalQuarantinedBytes, TotalQuarantineChunks,
+ QuarantineChunksCapacity, ChunksUsagePercent, MemoryOverheadPercent);
}
private:
@@ -218,11 +218,11 @@ public:
recycle(0, Cb);
}
- void printStats() const {
+ void getStats(ScopedString *Str) const {
// It assumes that the world is stopped, just as the allocator's printStats.
- Printf("Quarantine limits: global: %zuM; thread local: %zuK\n",
- getMaxSize() >> 20, getCacheSize() >> 10);
- Cache.printStats();
+ Cache.getStats(Str);
+ Str->append("Quarantine limits: global: %zuK; thread local: %zuK\n",
+ getMaxSize() >> 10, getCacheSize() >> 10);
}
private:
diff --git a/lib/scudo/standalone/secondary.cpp b/lib/scudo/standalone/secondary.cpp
index d725034ee..db7361d71 100644
--- a/lib/scudo/standalone/secondary.cpp
+++ b/lib/scudo/standalone/secondary.cpp
@@ -123,12 +123,13 @@ void MapAllocator::deallocate(void *Ptr) {
unmap(Addr, Size, UNMAP_ALL, &Data);
}
-void MapAllocator::printStats() const {
- Printf("Stats: MapAllocator: allocated %zu times (%zuK), freed %zu times "
- "(%zuK), remains %zu (%zuK) max %zuM\n",
- NumberOfAllocs, AllocatedBytes >> 10, NumberOfFrees, FreedBytes >> 10,
- NumberOfAllocs - NumberOfFrees, (AllocatedBytes - FreedBytes) >> 10,
- LargestSize >> 20);
+void MapAllocator::getStats(ScopedString *Str) const {
+ Str->append(
+ "Stats: MapAllocator: allocated %zu times (%zuK), freed %zu times "
+ "(%zuK), remains %zu (%zuK) max %zuM\n",
+ NumberOfAllocs, AllocatedBytes >> 10, NumberOfFrees, FreedBytes >> 10,
+ NumberOfAllocs - NumberOfFrees, (AllocatedBytes - FreedBytes) >> 10,
+ LargestSize >> 20);
}
} // namespace scudo
diff --git a/lib/scudo/standalone/secondary.h b/lib/scudo/standalone/secondary.h
index 80cae9fd2..9d074a57c 100644
--- a/lib/scudo/standalone/secondary.h
+++ b/lib/scudo/standalone/secondary.h
@@ -12,6 +12,7 @@
#include "common.h"
#include "mutex.h"
#include "stats.h"
+#include "string_utils.h"
namespace scudo {
@@ -70,7 +71,7 @@ public:
return getBlockEnd(Ptr) - reinterpret_cast<uptr>(Ptr);
}
- void printStats() const;
+ void getStats(ScopedString *Str) const;
void disable() { Mutex.lock(); }
diff --git a/lib/scudo/standalone/size_class_map.h b/lib/scudo/standalone/size_class_map.h
index 3b494afb3..dfef0865b 100644
--- a/lib/scudo/standalone/size_class_map.h
+++ b/lib/scudo/standalone/size_class_map.h
@@ -86,6 +86,7 @@ public:
}
static void print() {
+ ScopedString Buffer(1024);
uptr PrevS = 0;
uptr TotalCached = 0;
for (uptr I = 0; I < NumClasses; I++) {
@@ -93,19 +94,20 @@ public:
continue;
const uptr S = getSizeByClassId(I);
if (S >= MidSize / 2 && (S & (S - 1)) == 0)
- Printf("\n");
+ Buffer.append("\n");
const uptr D = S - PrevS;
const uptr P = PrevS ? (D * 100 / PrevS) : 0;
const uptr L = S ? getMostSignificantSetBitIndex(S) : 0;
const uptr Cached = getMaxCachedHint(S) * S;
- Printf(
+ Buffer.append(
"C%02zu => S: %zu diff: +%zu %02zu%% L %zu Cached: %zu %zu; id %zu\n",
I, getSizeByClassId(I), D, P, L, getMaxCachedHint(S), Cached,
getClassIdBySize(S));
TotalCached += Cached;
PrevS = S;
}
- Printf("Total Cached: %zu\n", TotalCached);
+ Buffer.append("Total Cached: %zu\n", TotalCached);
+ Buffer.output();
}
static void validate() {
diff --git a/lib/scudo/standalone/string_utils.cpp b/lib/scudo/standalone/string_utils.cpp
index 22b4fbd74..5de8b57bf 100644
--- a/lib/scudo/standalone/string_utils.cpp
+++ b/lib/scudo/standalone/string_utils.cpp
@@ -208,9 +208,18 @@ int formatString(char *Buffer, uptr BufferLength, const char *Format,
}
void ScopedString::append(const char *Format, va_list Args) {
- CHECK_LT(Length, String.size());
- formatString(String.data() + Length, String.size() - Length, Format, Args);
- Length += strlen(String.data() + Length);
+ DCHECK_LT(Length, String.size());
+ va_list ArgsCopy;
+ va_copy(ArgsCopy, Args);
+ // formatString doesn't currently support a null buffer or zero buffer length,
+ // so in order to get the resulting formatted string length, we use a one-char
+ // buffer.
+ char C[1];
+ const uptr AdditionalLength =
+ static_cast<uptr>(formatString(C, sizeof(C), Format, Args)) + 1;
+ String.resize(Length + AdditionalLength);
+ formatString(String.data() + Length, AdditionalLength, Format, ArgsCopy);
+ Length = strlen(String.data());
CHECK_LT(Length, String.size());
}
@@ -226,7 +235,7 @@ FORMAT(1, 2)
void Printf(const char *Format, ...) {
va_list Args;
va_start(Args, Format);
- ScopedString Msg(512);
+ ScopedString Msg(1024);
Msg.append(Format, Args);
outputRaw(Msg.data());
va_end(Args);
diff --git a/lib/scudo/standalone/string_utils.h b/lib/scudo/standalone/string_utils.h
index aea7b3ffd..acd60bda9 100644
--- a/lib/scudo/standalone/string_utils.h
+++ b/lib/scudo/standalone/string_utils.h
@@ -29,6 +29,7 @@ public:
}
void append(const char *Format, va_list Args);
void append(const char *Format, ...);
+ void output() const { outputRaw(String.data()); }
private:
Vector<char> String;
diff --git a/lib/scudo/standalone/tests/combined_test.cpp b/lib/scudo/standalone/tests/combined_test.cpp
index 3f971a304..d74c07e84 100644
--- a/lib/scudo/standalone/tests/combined_test.cpp
+++ b/lib/scudo/standalone/tests/combined_test.cpp
@@ -136,7 +136,21 @@ template <class Config> static void testAllocator() {
}
Allocator->releaseToOS();
- Allocator->printStats();
+
+ scudo::uptr BufferSize = 8192;
+ std::vector<char> Buffer(BufferSize);
+ scudo::uptr ActualSize = Allocator->getStats(Buffer.data(), BufferSize);
+ while (ActualSize > BufferSize) {
+ BufferSize = ActualSize + 1024;
+ Buffer.resize(BufferSize);
+ ActualSize = Allocator->getStats(Buffer.data(), BufferSize);
+ }
+ std::string Stats(Buffer.begin(), Buffer.end());
+ // Basic checks on the contents of the statistics output, which also allows us
+ // to verify that we got it all.
+ EXPECT_NE(Stats.find("Stats: SizeClassAllocator"), std::string::npos);
+ EXPECT_NE(Stats.find("Stats: MapAllocator"), std::string::npos);
+ EXPECT_NE(Stats.find("Stats: Quarantine"), std::string::npos);
}
TEST(ScudoCombinedTest, BasicCombined) {
diff --git a/lib/scudo/standalone/tests/primary_test.cpp b/lib/scudo/standalone/tests/primary_test.cpp
index a6cfc6bdb..7da7b25ca 100644
--- a/lib/scudo/standalone/tests/primary_test.cpp
+++ b/lib/scudo/standalone/tests/primary_test.cpp
@@ -46,7 +46,9 @@ template <typename Primary> static void testPrimary() {
}
Cache.destroy(nullptr);
Allocator->releaseToOS();
- Allocator->printStats();
+ scudo::ScopedString Str(1024);
+ Allocator->getStats(&Str);
+ Str.output();
}
TEST(ScudoPrimaryTest, BasicPrimary) {
@@ -86,7 +88,9 @@ TEST(ScudoPrimaryTest, Primary64OOM) {
}
Cache.destroy(nullptr);
Allocator.releaseToOS();
- Allocator.printStats();
+ scudo::ScopedString Str(1024);
+ Allocator.getStats(&Str);
+ Str.output();
EXPECT_EQ(AllocationFailed, true);
Allocator.unmapTestOnly();
}
@@ -125,7 +129,9 @@ template <typename Primary> static void testIteratePrimary() {
}
Cache.destroy(nullptr);
Allocator->releaseToOS();
- Allocator->printStats();
+ scudo::ScopedString Str(1024);
+ Allocator->getStats(&Str);
+ Str.output();
}
TEST(ScudoPrimaryTest, PrimaryIterate) {
@@ -180,7 +186,9 @@ template <typename Primary> static void testPrimaryThreaded() {
for (auto &T : Threads)
T.join();
Allocator->releaseToOS();
- Allocator->printStats();
+ scudo::ScopedString Str(1024);
+ Allocator->getStats(&Str);
+ Str.output();
}
TEST(ScudoPrimaryTest, PrimaryThreaded) {
@@ -203,8 +211,7 @@ template <typename Primary> static void testReleaseToOS() {
Cache.init(nullptr, Allocator.get());
const scudo::uptr Size = scudo::getPageSizeCached() * 2;
EXPECT_TRUE(Primary::canAllocate(Size));
- const scudo::uptr ClassId =
- Primary::SizeClassMap::getClassIdBySize(Size);
+ const scudo::uptr ClassId = Primary::SizeClassMap::getClassIdBySize(Size);
void *P = Cache.allocate(ClassId);
EXPECT_NE(P, nullptr);
Cache.deallocate(ClassId, P);
diff --git a/lib/scudo/standalone/tests/quarantine_test.cpp b/lib/scudo/standalone/tests/quarantine_test.cpp
index d7453aa42..28baf8feb 100644
--- a/lib/scudo/standalone/tests/quarantine_test.cpp
+++ b/lib/scudo/standalone/tests/quarantine_test.cpp
@@ -213,7 +213,9 @@ TEST(ScudoQuarantineTest, GlobalQuarantine) {
Quarantine.drainAndRecycle(&Cache, Cb);
EXPECT_EQ(Cache.getSize(), 0UL);
- Quarantine.printStats();
+ scudo::ScopedString Str(1024);
+ Quarantine.getStats(&Str);
+ Str.output();
}
void *populateQuarantine(void *Param) {
@@ -236,5 +238,7 @@ TEST(ScudoQuarantineTest, ThreadedGlobalQuarantine) {
for (scudo::uptr I = 0; I < NumberOfThreads; I++)
pthread_join(T[I], 0);
- Quarantine.printStats();
+ scudo::ScopedString Str(1024);
+ Quarantine.getStats(&Str);
+ Str.output();
}
diff --git a/lib/scudo/standalone/tests/secondary_test.cpp b/lib/scudo/standalone/tests/secondary_test.cpp
index 84c375449..b602b8d63 100644
--- a/lib/scudo/standalone/tests/secondary_test.cpp
+++ b/lib/scudo/standalone/tests/secondary_test.cpp
@@ -45,7 +45,9 @@ TEST(ScudoSecondaryTest, SecondaryBasic) {
L->deallocate(V.back());
V.pop_back();
}
- L->printStats();
+ scudo::ScopedString Str(1024);
+ L->getStats(&Str);
+ Str.output();
}
// This exercises a variety of combinations of size and alignment for the
@@ -76,7 +78,9 @@ TEST(ScudoSecondaryTest, SecondaryCombinations) {
}
}
}
- L->printStats();
+ scudo::ScopedString Str(1024);
+ L->getStats(&Str);
+ Str.output();
}
TEST(ScudoSecondaryTest, SecondaryIterate) {
@@ -97,7 +101,9 @@ TEST(ScudoSecondaryTest, SecondaryIterate) {
L->deallocate(V.back());
V.pop_back();
}
- L->printStats();
+ scudo::ScopedString Str(1024);
+ L->getStats(&Str);
+ Str.output();
}
static std::mutex Mutex;
@@ -133,5 +139,7 @@ TEST(ScudoSecondaryTest, SecondaryThreadsRace) {
}
for (auto &T : Threads)
T.join();
- L->printStats();
+ scudo::ScopedString Str(1024);
+ L->getStats(&Str);
+ Str.output();
}