Skip to content

Commit

Permalink
runtime: avoid memory allocations in checkTransitiveCompleteness
Browse files Browse the repository at this point in the history
Use SmallVector instead of std::vector and a SmallPtrSet-like implementation for the set.
  • Loading branch information
eeckstein committed Mar 13, 2019
1 parent 0528d8a commit 3c73685
Showing 1 changed file with 27 additions and 7 deletions.
34 changes: 27 additions & 7 deletions stdlib/public/runtime/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4740,20 +4740,38 @@ areAllTransitiveMetadataComplete_cheap(const Metadata *type) {
/// dependencies actually hold, and we can keep going.
static MetadataDependency
checkTransitiveCompleteness(const Metadata *initialType) {
// TODO: it would nice to avoid allocating memory in common cases here.
// In particular, we don't usually add *anything* to the worklist, and we
// usually only add a handful of types to the map.
std::vector<const Metadata *> worklist;
std::unordered_set<const Metadata *> presumedCompleteTypes;
llvm::SmallVector<const Metadata *, 8> worklist;

// An efficient hash-set implementation in the spirit of llvm's SmallPtrSet:
// The first 8 elements are stored in an inline-allocated array to avoid
// malloc calls in the common case. Lookup is still reasonable fast because
// there are max 8 elements in the array.
const int InlineCapacity = 8;
const Metadata *inlinedPresumedCompleteTypes[InlineCapacity];
int numInlinedTypes = 0;
std::unordered_set<const Metadata *> overflowPresumedCompleteTypes;

MetadataDependency dependency;
auto isIncomplete = [&](const Metadata *type) -> bool {
// Add the type to the presumed-complete-types set. If this doesn't
// succeed, we've already inserted it, which means we must have already
// decided it was complete.
if (!presumedCompleteTypes.insert(type).second)
// First, try to find the type in the inline-storage of the set.
const Metadata **end = inlinedPresumedCompleteTypes + numInlinedTypes;
if (std::find(inlinedPresumedCompleteTypes, end, type) != end)
return false;

// We didn't find the type in the inline-storage.
if (numInlinedTypes < InlineCapacity) {
assert(overflowPresumedCompleteTypes.size() == 0);
inlinedPresumedCompleteTypes[numInlinedTypes++] = type;
} else {
// The inline-storage is full. So try to insert the type into the
// overflow set.
if (!overflowPresumedCompleteTypes.insert(type).second)
return false;
}

// Check the metadata's current state with a non-blocking request.
auto request = MetadataRequest(MetadataState::Complete,
/*non-blocking*/ true);
Expand All @@ -4780,7 +4798,9 @@ checkTransitiveCompleteness(const Metadata *initialType) {

// Consider the type itself to be presumed-complete. We're looking for
// a greatest fixed point.
presumedCompleteTypes.insert(initialType);
assert(numInlinedTypes == 0 && overflowPresumedCompleteTypes.size() == 0);
inlinedPresumedCompleteTypes[0] = initialType;
numInlinedTypes = 1;
if (findAnyTransitiveMetadata(initialType, isIncomplete))
return dependency;

Expand Down

0 comments on commit 3c73685

Please sign in to comment.