blob: 4eaff53595260fbe087f3a0f8a4314f13fee9117 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
#include <iomanip>
#include <iostream>
#include <sstream>
NAHeap *ipcHeap;
const size_t numTotalBins = NAHeap::NSMALLBINS + NAHeap::NTREEBINS;
class State {
public:
NAHeap *executorHeap;
short summary;
short error;
State(NAHeap *executorHeapArg) : executorHeap(executorHeapArg), summary(false)
{}
};
// The LevelStats are the aggregate stats for each memory level
struct LevelStats
{
bool encountered_;
size_t blockCnt_;
size_t blockSum_;
size_t maxAllocSize_;
size_t allocSize_;
size_t derivedSize_;
size_t freeSize_;
static void resetLevelStats();
};
#define MAX_HEAP_LEVELS 8
static LevelStats heapLevel[MAX_HEAP_LEVELS];
static LevelStats spaceLevel[MAX_HEAP_LEVELS];
void LevelStats::resetLevelStats()
{
memset(heapLevel, 0, sizeof(heapLevel));
memset(spaceLevel, 0, sizeof(spaceLevel));
}
// Abstrace base class used to store statistics shared by Spaces and Heaps
class ExMemStats {
public:
// Constructor and destructor
ExMemStats(ExMemStats *parent, NAMemory *memory, Int32 level);
virtual ~ExMemStats();
// Function for gathering statistics
virtual void GetStatistics() = 0;
// Functions for displaying the statistics
void Display(ostream &os, State *state, size_t size);
virtual void DisplayLongMemStats(ostream &os, char *ind, size_t minSize) = 0;
void DisplayShortMemStats(ostream &os);
Int32 level_; // Number of levels of derived memory
size_t blockCnt_; // Number of blocks in this memory
size_t blockSum_; // Sum of the sizes of all blocks
size_t allocCnt_; // Number of in use allocations
size_t allocSum_; // Sum of all in use allocation sizes
size_t freeCnt_; // Number of not used allocations
size_t freeSum_; // Sum of all no used allocation sizes
size_t maxAllocSize_; // The reported high water mark for this memory
size_t derivedMemSum_; // The amount of derived memory in this memory
ExMemStats *parentStats_; // Pointer to the parent memory stats
ExMemStats *derivedStats_; // Pointer to the first derived stats
ExMemStats *nextDerivedStats_; // Pointer to the next derived stats at this level
NAMemory *thisMemory_; // Pointer ot NAMemory
void DisplayLevelStats(ostream &os, char *type, Int32 level, LevelStats &stats);
};
// Heap-specific statistics class
class ExHeapStats : public ExMemStats
{
public:
ExHeapStats(ExMemStats *parent, NAMemory *heap, Int32 level);
virtual void GetStatistics();
private:
virtual void DisplayLongMemStats(ostream &os, char *ind, size_t minSize);
size_t sizeBinCnt_[numTotalBins]; // The number of allocations for each bin
size_t sizeBinSum_[numTotalBins]; // Sum of sizes for each bin
};
// Space-specific statistics class
class ExSpaceStats : public ExMemStats
{
public:
ExSpaceStats(ExMemStats *parent, NAMemory *space, Int32 level);
virtual void GetStatistics();
private:
virtual void DisplayLongMemStats(ostream &os, char *ind, size_t minSize);
};
ExMemStats::ExMemStats(ExMemStats *parent, NAMemory *memory, Int32 level) :
level_(level),
blockCnt_(0),
blockSum_(0),
allocCnt_(0),
allocSum_(0),
freeCnt_(0),
freeSum_(0),
maxAllocSize_(0),
derivedMemSum_(0),
parentStats_(parent),
derivedStats_(NULL),
nextDerivedStats_(NULL),
thisMemory_(memory)
{}
ExMemStats::~ExMemStats()
{
// Recursivily delete all of the memory statistics
ExMemStats *p = derivedStats_;
while (p != NULL) {
ExMemStats *next = p->nextDerivedStats_;
delete p;
p = next;
}
}
ExHeapStats::ExHeapStats(ExMemStats *parent, NAMemory *heap, Int32 level)
: ExMemStats(parent, heap, level)
{
for (size_t i = 0; i < numTotalBins; i++) {
sizeBinCnt_[i] = 0;
sizeBinSum_[i] = 0;
}
}
ExSpaceStats::ExSpaceStats(ExMemStats *parent, NAMemory *space, Int32 level)
: ExMemStats(parent, space, level)
{
}
void ExHeapStats::GetStatistics()
{
// Increment NAHeap level stats
maxAllocSize_ = thisMemory_->highWaterMark_;
// Get the first NABlock for this NAHeap and return if there are
// no blocks
NABlock *block = thisMemory_->firstBlk_;
if (block == NULL)
return;
while (block != NULL) {
blockCnt_++;
blockSum_ += block->size_;
if (parentStats_ != NULL &&
block->segmentId_ == NABlock::DERIVED_SEGMENT_ID)
parentStats_->derivedMemSum_ += PAD_REQUEST(block->size_);
NAHeapFragment *fp = block->alignAsFragment();
while (!fp->isFencePost()) {
size_t fragSize = fp->fragmentSize();
if (fp->cinuse()) {
allocCnt_++;
allocSum_ += fragSize;
NAHeap::bindex_t binNum;
if (NAHeap::isSmall(fragSize))
binNum = NAHeap::smallIndex(fragSize);
else
binNum = NAHeap::NSMALLBINS + NAHeap::computeTreeIndex(fragSize);
sizeBinCnt_[binNum]++;
sizeBinSum_[binNum] += fragSize;
// SYSTEM_MEMORY and IPC_MEMORY NAMemory classes can be allocated
// within EXECUTOR_MEMORY, but not registered as derived memory.
// Try to pick up on that here. The ipcHeap will be analyzed later
// after share() maps in the proper segments.
if (fragSize == PAD_REQUEST(sizeof(NAHeap))) {
NAHeap *testHeap = (NAHeap*)fp->getMemory();
if (testHeap->type_ == NAMemory::SYSTEM_MEMORY ||
testHeap->type_ == NAMemory::IPC_MEMORY) {
ipcHeap = testHeap;
}
}
// ComSpace memories do not currently register themselves with
// their parent class. That could probably be fixed in the future.
// For now, we can determine whether this fragment contains a
// ComSpace object.
else if (fragSize == PAD_REQUEST(sizeof(ComSpace))) {
ComSpace *testSpace = (ComSpace*)fp->getMemory();
if (testSpace->ComSpace::parent_ == thisMemory_) {
ExSpaceStats *newDerivedStats = new ExSpaceStats(
this, testSpace, level_ + 1);
newDerivedStats->nextDerivedStats_ = derivedStats_;
derivedStats_ = newDerivedStats;
newDerivedStats->GetStatistics();
}
}
}
else {
freeCnt_++;
freeSum_ += fragSize;
}
fp = fp->nextFragment();
}
block = block->next_;
}
if (blockCnt_ != thisMemory_->blockCnt_)
/* cout << "Invalid block count (" << blockCnt_ << " != "
<< thisMemory_->blockCnt_ << ")." << endl*/;
// Loop over the child NAHeaps and read the statistics for them
NAMemory *derivedMem = thisMemory_->memoryList_;
while (derivedMem != NULL) {
ExMemStats *newDerivedStats = new ExHeapStats(
this, derivedMem, level_ + 1);
newDerivedStats->nextDerivedStats_ = derivedStats_;
derivedStats_ = newDerivedStats;
newDerivedStats->GetStatistics();
derivedMem = derivedMem->nextEntry_;
}
// Update the level stats. This has to be done after traversing
// the child memories to calculate the correct derivedSize_.
heapLevel[level_].encountered_ = true;
heapLevel[level_].blockCnt_ += blockCnt_;
heapLevel[level_].blockSum_ += blockSum_;
heapLevel[level_].maxAllocSize_ += thisMemory_->highWaterMark_;
heapLevel[level_].allocSize_ += allocSum_;
heapLevel[level_].derivedSize_ += derivedMemSum_;
heapLevel[level_].freeSize_ += freeSum_;
}
void ExSpaceStats::GetStatistics()
{
Block * block = ((Space*)thisMemory_)->firstBlock_;
while (block != NULL) {
blockCnt_++;
blockSum_ += block->getBlockSize();
parentStats_->derivedMemSum_ += PAD_REQUEST(block->getBlockSize());
allocSum_ += block->getAllocatedSize();
freeSum_ += block->getFreeSpace();
block = block->getNext();
}
maxAllocSize_ = allocSum_;
// Update the level stats
spaceLevel[level_].encountered_ = true;
spaceLevel[level_].blockCnt_ += blockCnt_;
spaceLevel[level_].blockSum_ += blockSum_;
spaceLevel[level_].maxAllocSize_ += allocSum_;
spaceLevel[level_].allocSize_ += allocSum_;
spaceLevel[level_].freeSize_ += freeSum_;
}
void ExHeapStats::DisplayLongMemStats(ostream &os, char *ind, size_t minSize)
{
if (blockSum_ < minSize)
return;
os << ind << "Type: ";
switch (thisMemory_->type_)
{
case NAMemory::NO_MEMORY_TYPE:
os << "NO_MEMORY_TYPE" << endl;
break;
case NAMemory::EXECUTOR_MEMORY:
os << "EXECUTOR_MEMORY" << endl;
break;
case NAMemory::SYSTEM_MEMORY:
os << "SYSTEM_MEMORY" << endl;
break;
case NAMemory::DERIVED_MEMORY:
os << "DERIVED_MEMORY" << endl;
break;
case NAMemory::DERIVED_FROM_SYS_HEAP:
os << "DERIVED_FROM_SYS_HEAP" << endl;
break;
case NAMemory::IPC_MEMORY:
os << "IPC_MEMORY" << endl;
break;
}
os << ind << "NAMemory address: " << thisMemory_ << endl;
if (thisMemory_->parent_)
os << ind << "Parent address: " << thisMemory_->parent_ << endl;
os << ind << "Number of blocks: " << blockCnt_ << endl;
switch (thisMemory_->type_)
{
case NAMemory::EXECUTOR_MEMORY:
case NAMemory::SYSTEM_MEMORY:
case NAMemory::IPC_MEMORY:
{
NABlock *block = thisMemory_->firstBlk_;
while (block != NULL) {
os << ind << /*" Seg Id " << block->segmentId_
<< */" NABlock@" << block
<< " (" << (block->size_ >> 10) << " Kbytes)" << endl;
block = block->next_;
}
}
break;
default:
break;
}
os << ind << "Total size of blocks: " << blockSum_ << endl;
os << ind << "Number of free fragments: " << freeCnt_ << endl;
os << ind << "Total size of free fragments: " << freeSum_ << endl;
os << ind << "Number of allocated fragments: " << allocCnt_ << endl;
os << ind << "Total size of allocated fragments: " << allocSum_ << endl;
os << ind << "Maximum size of allocated fragments: " << maxAllocSize_
<< endl;
os << ind << "Derived memory level: " << level_ << endl;
os << ind << "Total size of derived memory blocks: " << derivedMemSum_
<< endl;
os << ind << " Frag Min - Frag Max Num Allocs Total Frag Size" << endl;
size_t prevSize = 1;
for (size_t i = 0; i < numTotalBins; i++) {
size_t binSize;
if (i < NAHeap::NSMALLBINS) {
binSize = NAHeap::smallIndex2Size(i);
prevSize = binSize;
} else {
binSize = NAHeap::minsizeForTreeIndex(i - NAHeap::NSMALLBINS + 1);
}
if (sizeBinCnt_[i] != 0) {
os << ind << setw(9) << prevSize << " - " << setw(9)
<< setiosflags(ios::left) << binSize << resetiosflags(ios::left)
<< setw(11) << sizeBinCnt_[i]
<< setw(17) << sizeBinSum_[i] << endl;
}
prevSize = binSize + 1;
}
}
void ExSpaceStats::DisplayLongMemStats(ostream &os, char *ind, size_t minSize)
{
if (blockSum_ < minSize)
return;
Space * space = (Space*)thisMemory_;
os << ind << "Type: ";
switch (space->ComSpace::type_)
{
case ComSpace::EXECUTOR_SPACE:
os << "EXECUTOR_SPACE" << endl;
break;
case ComSpace::GENERATOR_SPACE:
os << "GENERATOR_SPACE" << endl;
break;
case ComSpace::SYSTEM_SPACE:
os << "SYSTEM_SPACE" << endl;
break;
case ComSpace::SINGLE_BLOCK_SPACE:
os << "SINGLE_BLOCK_SPACE" << endl;
break;
default:
os << "Unknown space type: "
<< space->ComSpace::type_ << endl;
break;
}
os << ind << "NAMemory address: " << thisMemory_ << endl;
os << ind << "Derived memory level: " << level_ << endl;
os << ind << "Number of blocks: " << blockCnt_ << endl;
os << ind << "Total size of blocks: " << blockSum_ << endl;
os << ind << "Used space memory: " << allocSum_ << endl;
os << ind << "Unused space memory: " << freeSum_ << endl;
}
void ExMemStats::DisplayLevelStats(ostream &os, char *type, Int32 level,
LevelStats &stats)
{
os << setw(5) << level << " "
<< setw(5) << type << " "
<< setw(6) << stats.blockCnt_ << " "
<< setw(10) << stats.blockSum_ << " "
<< setw(10) << stats.maxAllocSize_ << " "
<< setw(10) << stats.allocSize_ << " "
<< setw(10) << stats.derivedSize_ << " "
<< setw(10) << stats.freeSize_
<< endl;
}
void ExMemStats::DisplayShortMemStats(ostream &os)
{
// Display short memory stats header
os << "Level Type Blocks Size MaxAlloc AllocSize "
"DerivedSize FreeSize" << endl;
// Display the statistics for each level
for (Int32 i = 0; i < MAX_HEAP_LEVELS; i++)
{
if (heapLevel[i].encountered_)
DisplayLevelStats(os, (char *)"Heap", i, heapLevel[i]);
if (spaceLevel[i].encountered_)
DisplayLevelStats(os, (char *)"Space", i, spaceLevel[i]);
}
}
void ExMemStats::Display(ostream &os, State *state, size_t minSize)
{
// For short memory stats, just print a short summary of the top-most
// memory and return
if (level_ == 0) {
DisplayShortMemStats(os);
if (state->summary)
return;
os << endl;
}
if (blockSum_ < minSize)
return;
// Set the amount of indent
char ind[20];
size_t numSpaces = level_ << 1; // 2 spaces for each level
memset(ind, ' ', numSpaces);
ind[numSpaces] = '\0';
os << ind << "Name: " << thisMemory_->name_ << endl;
// Call virtual function to display information specific to NAHeap
// or ComSpace
DisplayLongMemStats(os, ind, minSize);
os << endl;
ExMemStats *derivedMemStats = derivedStats_;
while (derivedMemStats != NULL) {
derivedMemStats->Display(os, state, minSize);
derivedMemStats = derivedMemStats->nextDerivedStats_;
}
}
Int32 muse(NAHeap *heap, size_t minTotalSize, char *rspBuffer, size_t rspMaxSize, size_t *rspSize, bool *bufferFull) {
stringstream *ss = new stringstream(stringstream::in | stringstream::out);
streamsize ssSize;
char testBuf[1];
char truncatedMsg[] = "\n***Muse output has been truncated***";
State state(heap); //arg 1
memset(heapLevel, 0, sizeof(heapLevel));
memset(spaceLevel, 0, sizeof(spaceLevel));
ExHeapStats exHeapInfo(NULL, state.executorHeap, 0);
exHeapInfo.GetStatistics();
exHeapInfo.Display(*ss, &state, minTotalSize);
ss->read(rspBuffer, rspMaxSize);
ssSize = ss->gcount();
*rspSize = (size_t)ssSize;
ss->read(&testBuf[0], 1);
ssSize = ss->gcount();
if (ssSize > 0)
{
strcpy(rspBuffer + rspMaxSize - sizeof(truncatedMsg), truncatedMsg);
*bufferFull = true;
}
else
*bufferFull = false;
delete ss;
return 0;
}