Skip to content
This repository has been archived by the owner on Aug 10, 2021. It is now read-only.

Commit

Permalink
Improve memory manager stats. (#2368)
Browse files Browse the repository at this point in the history
  • Loading branch information
olonho authored and vvlevchenko committed Nov 27, 2018
1 parent e644635 commit df576e3
Showing 1 changed file with 68 additions and 18 deletions.
86 changes: 68 additions & 18 deletions runtime/src/main/cpp/Memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ struct FrameOverlay {
// A little hack that allows to enable -O2 optimizations
// Prevents clang from replacing FrameOverlay struct
// with single pointer.
// Can be removed when FrameOverlay will become more complex
// Can be removed when FrameOverlay will become more complex.
FrameOverlay exportFrameOverlay;

// Current number of allocated containers.
Expand All @@ -98,20 +98,31 @@ void FreeContainer(ContainerHeader* header);
class MemoryStatistic {
public:
// UpdateRef per-object type counters.
uint64_t updateCounters[4][4];
uint64_t updateCounters[5][5];
// Alloc per container type counters.
uint64_t containerAllocs[4][2];
uint64_t containerAllocs[5][2];
// Free per container type counters.
uint64_t objectAllocs[4][2];
uint64_t objectAllocs[5][2];
// Histogram of allocation size distribution.
KStdUnorderedMap<int, int>* allocationHistogram;
// Number of allocation cache hits.
int allocCacheHit;
// Number of allocation cache misses.
int allocCacheMiss;
// Number of regular reference increments.
uint64_t addRefs;
// Number of atomic reference increments.
uint64_t atomicAddRefs;
// Number of regular reference decrements.
uint64_t releaseRefs;
// Number of atomic reference decrements.
uint64_t atomicReleaseRefs;
// Number of potential cycle candidates.
uint64_t releaseCyclicRefs;

// Map of array index to human readable name.
static constexpr const char* indexToName[] = { "normal", "stack ", "perm ", "null " };
static constexpr const char* indexToName[] = {
"normal", "stack ", "perm ", "frozen", "null " };

void init() {
memset(containerAllocs, 0, sizeof(containerAllocs));
Expand All @@ -127,6 +138,19 @@ class MemoryStatistic {
allocationHistogram = nullptr;
}

void incAddRef(const ContainerHeader* header, bool atomic) {
if (atomic) atomicAddRefs++; else addRefs++;
}

void incReleaseRef(const ContainerHeader* header, bool atomic, bool cyclic) {
if (atomic) {
RuntimeAssert(!cyclic, "Atomic updates cannot be cyclic yet");
atomicReleaseRefs++;
} else {
if (cyclic) releaseCyclicRefs++; else releaseRefs++;
}
}

void incUpdateRef(const ObjHeader* objOld, const ObjHeader* objNew) {
updateCounters[toIndex(objOld)][toIndex(objNew)]++;
}
Expand All @@ -149,20 +173,27 @@ class MemoryStatistic {
}

static int toIndex(const ObjHeader* obj) {
if (obj == nullptr) return 3;
return toIndex(obj->container());
if (reinterpret_cast<uintptr_t>(obj) > 1)
return toIndex(obj->container());
else
return 4;
}

static int toIndex(const ContainerHeader* header) {
switch (header->tag()) {
case CONTAINER_TAG_NORMAL : return 0;
case CONTAINER_TAG_STACK : return 1;
case CONTAINER_TAG_PERMANENT: return 2;
case CONTAINER_TAG_FROZEN: return 3;
}
RuntimeAssert(false, "unknown container type");
return -1;
}

static double percents(uint64_t value, uint64_t all) {
return ((double)value / (double)all) * 100.0;
}

void printStatistic() {
konan::consolePrintf("\nMemory manager statistic:\n\n");
for (int i = 0; i < 2; i++) {
Expand All @@ -177,8 +208,8 @@ class MemoryStatistic {
}

konan::consolePrintf("\n");
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
konan::consolePrintf("UpdateRef[%s -> %s]: %lld\n",
indexToName[i], indexToName[j], updateCounters[i][j]);
}
Expand All @@ -197,10 +228,14 @@ class MemoryStatistic {
"%d bytes -> %d times\n", it, (*allocationHistogram)[it]);
}

#if USE_GC
konan::consolePrintf(
"alloc cache: %d hits/%d misses\n", allocCacheHit, allocCacheMiss);
#endif // USE_GC
uint64_t allAddRefs = addRefs + atomicAddRefs;
uint64_t allReleases = releaseRefs + atomicReleaseRefs + releaseCyclicRefs;
konan::consolePrintf("AddRefs:\t%lld/%lld (%lf%% of atomic)\n"
"Releases:\t%lld/%lld (%lf%% of atomic)\n"
"ReleaseRefs for cycle collector : %lld (%lf%% of cyclic)\n",
addRefs, atomicAddRefs, percents(atomicAddRefs, allAddRefs),
releaseRefs, atomicReleaseRefs, percents(atomicAddRefs, allReleases),
releaseCyclicRefs, percents(releaseCyclicRefs, allReleases));
}
};

Expand Down Expand Up @@ -251,8 +286,12 @@ struct MemoryState {
state->statistic.incAlloc(size, object);
#define OBJECT_FREE_STAT(state, size, object) \
state->statistic.incFree(object);
#define UPDATE_REF_STAT(state, oldRef, newRef, slot) \
#define UPDATE_REF_STAT(state, oldRef, newRef, slot) \
state->statistic.incUpdateRef(oldRef, newRef);
#define UPDATE_ADDREF_STAT(state, obj, atomic) \
state->statistic.incAddRef(obj, atomic);
#define UPDATE_RELEASEREF_STAT(state, obj, atomic, cyclic) \
state->statistic.incReleaseRef(obj, atomic, cyclic);
#define INIT_STAT(state) \
state->statistic.init();
#define DEINIT_STAT(state) \
Expand All @@ -267,6 +306,8 @@ struct MemoryState {
#define OBJECT_ALLOC_STAT(state, size, object)
#define OBJECT_FREE_STAT(state, object)
#define UPDATE_REF_STAT(state, oldRef, newRef, slot)
#define UPDATE_ADDREF_STAT(state, obj, atomic)
#define UPDATE_RELEASEREF_STAT(state, obj, atomic, cyclic)
#define INIT_STAT(state)
#define DEINIT_STAT(state)
#define PRINT_STAT(state)
Expand Down Expand Up @@ -531,13 +572,15 @@ inline void scheduleDestroyContainer(MemoryState* state, ContainerHeader* contai
template <bool Atomic>
inline void IncrementRC(ContainerHeader* container) {
container->incRefCount<Atomic>();
UPDATE_ADDREF_STAT(memoryState, container, Atomic);
}

template <bool Atomic, bool UseCycleCollector>
inline void DecrementRC(ContainerHeader* container) {
if (container->decRefCount<Atomic>() == 0) {
FreeContainer(container);
}
UPDATE_RELEASEREF_STAT(memoryState, container, Atomic, false);
}

#else // USE_GC
Expand All @@ -550,19 +593,24 @@ template <bool Atomic>
inline void IncrementRC(ContainerHeader* container) {
container->incRefCount<Atomic>();
container->setColorUnlessGreen(CONTAINER_TAG_GC_BLACK);
UPDATE_ADDREF_STAT(memoryState, container, Atomic);
}

template <bool Atomic, bool UseCycleCollector>
inline void DecrementRC(ContainerHeader* container) {
if (container->decRefCount<Atomic>() == 0) {
UPDATE_RELEASEREF_STAT(memoryState, container, Atomic, false);
FreeContainer(container);
} else if (UseCycleCollector) { // Possible root.
RuntimeAssert(!Atomic, "Cycle collector shalln't be used with shared objects yet");
RuntimeAssert(container->objectCount() == 1,
"Cycle collector shall only work with single object containers");
// We do not use cycle collector for frozen objects, as we already detected
// possible cycles during freezing.
// Also do not use cycle collector for provable acyclic objects.
int color = container->color();
if (color != CONTAINER_TAG_GC_PURPLE && color != CONTAINER_TAG_GC_GREEN) {
UPDATE_RELEASEREF_STAT(memoryState, container, Atomic, true);
container->setColorAssertIfGreen(CONTAINER_TAG_GC_PURPLE);
if (!container->buffered()) {
container->setBuffered();
Expand All @@ -572,6 +620,8 @@ inline void DecrementRC(ContainerHeader* container) {
GarbageCollect();
}
}
} else {
UPDATE_RELEASEREF_STAT(memoryState, container, Atomic, false);
}
}
}
Expand Down Expand Up @@ -802,10 +852,10 @@ inline void AddRef(ContainerHeader* header) {
}
}

inline void Release(ContainerHeader* header) {
// Looking at container type we may want to skip Release() totally
inline void ReleaseRef(ContainerHeader* header) {
// Looking at container type we may want to skip ReleaseRef() totally
// (non-escaping stack objects, constant objects).
switch (header->refCount_ & CONTAINER_TAG_MASK) {
switch (header->tag()) {
case CONTAINER_TAG_PERMANENT:
case CONTAINER_TAG_STACK:
break;
Expand Down Expand Up @@ -1094,7 +1144,7 @@ inline void AddRef(const ObjHeader* object) {

inline void ReleaseRef(const ObjHeader* object) {
MEMORY_LOG("ReleaseRef on %p in %p\n", object, object->container())
Release(object->container());
ReleaseRef(object->container());
}

void AddRefFromAssociatedObject(const ObjHeader* object) {
Expand Down

0 comments on commit df576e3

Please sign in to comment.