Skip to content

Commit

Permalink
Add gc name to CrashManager output
Browse files Browse the repository at this point in the history
Summary:
In case we see a crash in production, we'd like to know which
GC is being used. This can help diagnose potential causes of the
problem.
This is especially helpful for Hades, which operates in two different
modes, depending on the build parameters. Now there's no need to
guess based on the device type.

Reviewed By: neildhar

Differential Revision: D24452623

fbshipit-source-id: a41f230c1aa09b6328961c46caa8c8bbd786bb45
  • Loading branch information
Riley Dulin authored and facebook-github-bot committed Oct 23, 2020
1 parent 293cc1f commit d0ffc80
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 16 deletions.
7 changes: 5 additions & 2 deletions lib/VM/gcs/GenGCNC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ using std::chrono::steady_clock;
namespace hermes {
namespace vm {

static const char *kGCName = "gengc";

GenGC::Size::Size(const GCConfig &gcConfig)
: Size(gcConfig.getMinHeapSize(), gcConfig.getMaxHeapSize()) {}

Expand Down Expand Up @@ -113,6 +115,7 @@ GenGC::GenGC(
occupancyTarget_(gcConfig.getOccupancyTarget()),
oomThreshold_(gcConfig.getEffectiveOOMThreshold()),
weightedUsed_(static_cast<double>(gcConfig.getInitHeapSize())) {
crashMgr_->setCustomData("HermesGC", kGCName);
growTo(gcConfig.getInitHeapSize());
claimAllocContext();
updateCrashManagerHeapExtents();
Expand Down Expand Up @@ -1413,7 +1416,7 @@ void GenGC::printStats(JSONEmitter &json) {
GCBase::printStats(json);
json.emitKey("specific");
json.openDict();
json.emitKeyValue("collector", "noncontig-generational");
json.emitKeyValue("collector", kGCName);

json.emitKey("stats");
json.openDict();
Expand Down Expand Up @@ -1550,7 +1553,7 @@ void GenGC::CollectionSection::recordGCStats(
// Record as an overall collection.
GCAnalyticsEvent event{
gc_->getName(),
"gengc",
kGCName,
cycle_.extraInfo(),
std::move(cause_),
std::chrono::duration_cast<std::chrono::milliseconds>(
Expand Down
8 changes: 6 additions & 2 deletions lib/VM/gcs/HadesGC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
namespace hermes {
namespace vm {

static const char *kGCName =
kConcurrentGC ? "hades (concurrent)" : "hades (incremental)";

// A free list cell is always variable-sized.
const VTable HadesGC::OldGen::FreelistCell::vt{CellKind::FreelistKind,
/*variableSize*/ 0};
Expand Down Expand Up @@ -251,7 +254,7 @@ class HadesGC::CollectionStats final {
HadesGC::CollectionStats::~CollectionStats() {
gc_->recordGCStats(GCAnalyticsEvent{
gc_->getName(),
kConcurrentGC ? "hades (concurrent)" : "hades (incremental)",
kGCName,
extraInfo_,
std::move(cause_),
std::chrono::duration_cast<std::chrono::milliseconds>(
Expand Down Expand Up @@ -801,6 +804,7 @@ HadesGC::HadesGC(
occupancyTarget_(gcConfig.getOccupancyTarget()),
// Assume about 30% of the YG will survive initially.
ygAverageSurvivalRatio_{/*weight*/ 0.5, /*init*/ 0.3} {
crashMgr_->setCustomData("HermesGC", kGCName);
// createSegment relies on member variables and should not be called until
// they are initialised.
if (!(youngGen_ = createSegment(/*isYoungGen*/ true))) {
Expand Down Expand Up @@ -888,7 +892,7 @@ void HadesGC::printStats(JSONEmitter &json) {
GCBase::printStats(json);
json.emitKey("specific");
json.openDict();
json.emitKeyValue("collector", "hades");
json.emitKeyValue("collector", kGCName);
json.emitKey("stats");
json.openDict();
json.closeDict();
Expand Down
10 changes: 7 additions & 3 deletions lib/VM/gcs/MallocGC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
namespace hermes {
namespace vm {

static const char *kGCName = "malloc";

struct MallocGC::MarkingAcceptor final : public SlotAcceptorDefault,
public WeakRootAcceptorDefault {
std::vector<CellHeader *> worklist_;
Expand Down Expand Up @@ -186,7 +188,9 @@ MallocGC::MallocGC(
pointers_(),
weakPointers_(),
maxSize_(Size(gcConfig).max()),
sizeLimit_(gcConfig.getInitHeapSize()) {}
sizeLimit_(gcConfig.getInitHeapSize()) {
crashMgr_->setCustomData("HermesGC", kGCName);
}

MallocGC::~MallocGC() {
for (CellHeader *header : pointers_) {
Expand Down Expand Up @@ -365,7 +369,7 @@ void MallocGC::collect(std::string cause) {

GCAnalyticsEvent event{
getName(),
"malloc",
kGCName,
"full",
std::move(cause),
std::chrono::duration_cast<std::chrono::milliseconds>(
Expand Down Expand Up @@ -441,7 +445,7 @@ void MallocGC::printStats(JSONEmitter &json) {
GCBase::printStats(json);
json.emitKey("specific");
json.openDict();
json.emitKeyValue("collector", "malloc");
json.emitKeyValue("collector", kGCName);
json.emitKey("stats");
json.openDict();
json.closeDict();
Expand Down
2 changes: 1 addition & 1 deletion unittests/VMRuntime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ set(RTSources
CastingTest.cpp
CodeCoverageProfilerTest.cpp
CopyableVectorTest.cpp
CrashManagerTest.cpp
DateUtilTest.cpp
DecoratedObjectTest.cpp
DictPropertyMapTest.cpp
Expand All @@ -29,7 +30,6 @@ set(RTSources
GCGuardPageNCTest.cpp
GCInitTest.cpp
GCLazySegmentNCTest.cpp
GCHeapExtentsInCrashManagerTest.cpp
GCMarkWeakTest.cpp
GCObjectIterationTest.cpp
GCOOMTest.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
* LICENSE file in the root directory of this source tree.
*/

#if defined(HERMESVM_GC_NONCONTIG_GENERATIONAL) || defined(HERMESVM_GC_HADES)

/// Parts of regex, at least as used by gmock, appear to be unsupported on
/// Windows. So we'll exempt this test on Windows.
#ifndef _WINDOWS
Expand Down Expand Up @@ -79,7 +77,7 @@ class TestCrashManager : public CrashManager {
};

/// We are able to materialize every segment.
TEST(GCHeapExtentsInCrashManagerTest, HeapExtentsCorrect) {
TEST(CrashManagerTest, HeapExtentsCorrect) {
/// We need a max heap that's bigger than normal
GCConfig gcConfig = GCConfig::Builder(kTestGCConfigBuilder)
.withName("XYZ")
Expand All @@ -104,7 +102,7 @@ TEST(GCHeapExtentsInCrashManagerTest, HeapExtentsCorrect) {
rt.pointerRoots.push_back(&roots.back());
}
#ifdef HERMESVM_GC_NONCONTIG_GENERATIONAL
EXPECT_EQ(4, testCrashMgr->customData().size());
EXPECT_EQ(5, testCrashMgr->customData().size());

const std::string expectedYgKeyStr = "XYZ:HeapSegments_YG";
const std::string oneExtent =
Expand Down Expand Up @@ -183,7 +181,7 @@ TEST(GCHeapExtentsInCrashManagerTest, HeapExtentsCorrect) {
}
rt.collect();

EXPECT_EQ(2, testCrashMgr->customData().size());
EXPECT_EQ(3, testCrashMgr->customData().size());

EXPECT_NE(
testCrashMgr->customData().end(),
Expand Down Expand Up @@ -218,7 +216,7 @@ TEST(GCHeapExtentsInCrashManagerTest, HeapExtentsCorrect) {
}

#ifdef HERMESVM_GC_HADES
TEST(GCHeapExtentsInCrashManagerTest, PromotedYGHasCorrectName) {
TEST(CrashManagerTest, PromotedYGHasCorrectName) {
// Turn on the "direct to OG" allocation feature.
GCConfig gcConfig = GCConfig::Builder(kTestGCConfigBuilder)
.withName("XYZ")
Expand Down Expand Up @@ -258,8 +256,25 @@ TEST(GCHeapExtentsInCrashManagerTest, PromotedYGHasCorrectName) {
}
#endif

TEST(CrashManagerTest, GCNameIncluded) {
GCConfig gcConfig =
GCConfig::Builder(kTestGCConfigBuilder).withName("XYZ").build();
auto testCrashMgr = std::make_shared<TestCrashManager>();
auto runtime = DummyRuntime::create(
getMetadataTable(),
gcConfig,
DummyRuntime::defaultProvider(),
testCrashMgr);

const auto &crashData = testCrashMgr->customData();
auto gcName = crashData.find("HermesGC");
// Each GC can set its name as it likes, the only real requirement is that
// it exists and is distinct. Since we can test more than one GC per build,
// we'll just test the "exists" part.
ASSERT_NE(gcName, crashData.end()) << "HermesGC key not found in crash data";
EXPECT_NE(gcName->second, "") << "HermesGC value is empty";
}

} // namespace

#endif // _WINDOWS

#endif // HERMESVM_GC_NONCONTIG_GENERATIONAL || HERMESVM_GC_HADES

0 comments on commit d0ffc80

Please sign in to comment.