Exemple #1
0
int CHugePageManager::Open(hugepage_t ** ptable)
{
    bool ok;
    
    int uid = getuid();
    if (uid != 0)
    {
        printf("root privilige is a must to operate huge page\n");
        return -1;
    }
	
    // Mount the huge page filesystem to be used and config the big page numbers in the 
    // system.
    Mount();
	
    // Double check if file system mounted and big page configured.
    ok = InitCheck();
    if (!ok)
    {
        printf("Failed to init huge page system\n");
        return -1;
    }
    
    int ret = MapAllPages();
    if (ret != 0)
    {
        return -1;
    }
    
    GetAllPagePhyAddr();
    PrintPageInfo();
    SortByPhyAddr();
    printf("after sort................\n");
    PrintPageInfo();
    ret = RemapAllPages();
    if (ret != 0)
    {
        return -1;
    }    
    PrintPageInfo();
    // better to check if sucessfully opened
    *ptable = m_ptable;
    
    Opened = true;
    return 0;	
}
/////////////////////////////////////////////////////////////////////
// The core functions
/////////////////////////////////////////////////////////////////////
static void PrintHeapProfile(const char* ipLogFileName)
{
	// Open file and mmap it into process
	MmapFile lMmapHeapFile(ipLogFileName);

	if(lMmapHeapFile.InitSucceed() == false)
		return;

	// Process log file header
	HeapHeader* lpHeader = (HeapHeader*)lMmapHeapFile.GetStartAddr();
	if (false == PrintHeapHeader(lpHeader))
		return;

	HeapInfo* lpHeapInfo = (HeapInfo*)(lpHeader+1);

	//if (!gbPrintDetail)
	//{
	//	printf("UserSize\tMaxFreeBlock\tTotalFree\tFragmentation\n");
	//}

	unsigned long lNumHeapSnapShot = 0;

	unsigned long lTotalPage = 0;
	unsigned long lDupPage   = 0;
	unsigned long lEndPage   = 0;
	// For each snap shot of heap
	while((char*)lpHeapInfo < lMmapHeapFile.GetEndAddr())
	{
		// First structure is HeapInfo
		if(PrintHeapInfo(lpHeapInfo, lNumHeapSnapShot) == false)
		{
			break;
		}

		// Catagorize request by size
		BLOCK_SIZE_CLASS lRequestBlockClass;
		if (lpHeapInfo->mUserRequestSize <= lpHeader->mSmallBlockThreshold)
			lRequestBlockClass = SMALL_BLOCK;
		else if (lpHeapInfo->mUserRequestSize <= lpHeader->mMaxSubAlloc)
			lRequestBlockClass = MEDIUM_BLOCK;
		else if (lpHeapInfo->mUserRequestSize < lpHeader->mLargeBlockThreshold)
			lRequestBlockClass = EXTERNAL_BLOCK;
		else
			lRequestBlockClass = LARGE_BLOCK;

		// Then there are variable number of page info structures
		PAGESET lPageSet;
		PageInfo* lpPageInfo;
		int lMaxPoolNo    = 0;
		int lMaxSubPoolNo = 0;
		unsigned int lMaxFreeBlock = 0;
		for (lpPageInfo = (PageInfo*)(lpHeapInfo+1);
			 (char*)lpPageInfo < lMmapHeapFile.GetEndAddr();
			 lpPageInfo++)
		{
			lTotalPage++;
			// Check if page type is valid, and beware of end page mark
			if(lpPageInfo->mPageType == PAGE_TYPES)
			{
				lEndPage++;
				break;
			}
			else if(lpPageInfo->mPageType > PAGE_TYPES)
			{
				fprintf(stderr, "Invalid page type %d\n", lpPageInfo->mPageType);
				return;
			}

			//PrintPageInfo(lpPageInfo, lpHeader);

			// Find the range of all pools and their subpools
			if(lMaxPoolNo < lpPageInfo->mPool)
			{
				lMaxPoolNo = lpPageInfo->mPool;
			}
			if(lMaxSubPoolNo < lpPageInfo->mSubPool)
			{
				lMaxSubPoolNo = lpPageInfo->mSubPool;
			}

			// Sort the pages in a set container
			if((lPageSet.insert(lpPageInfo)).second == false)
			{
				lDupPage++;
				// there is a page that has the same address. something is not right.
				// The heap logger can't fully lock all pages simultaneously due to cost 
				/*
				PAGESET::iterator it2 = lPageSet.find(lpPageInfo);
				PageInfo* lpPrevPage = *it2;
				fprintf(stderr, "Failed to insert into page info set\n");
				fprintf(stderr, "PageInfo1 [0x%lx - 0x%lx] type=%s pool=%d,%d inUse=%d free=%d maxFree=%d\n", 
					lpPrevPage->mPageStart, lpPrevPage->mPageEnd, 
					PageTypeNames[lpPrevPage->mPageType], lpPrevPage->mPool, lpPrevPage->mSubPool,
					lpPrevPage->mInUseBytes, lpPrevPage->mFreeBytes, lpPrevPage->mMaxFreeBlockSize);
				fprintf(stderr, "PageInfo2 [0x%lx - 0x%lx] type=%s pool=%d,%d inUse=%d free=%d maxFree=%d\n",
					lpPageInfo->mPageStart, lpPageInfo->mPageEnd, 
					PageTypeNames[lpPageInfo->mPageType], lpPageInfo->mPool, lpPageInfo->mSubPool,
					lpPageInfo->mInUseBytes, lpPageInfo->mFreeBytes, lpPageInfo->mMaxFreeBlockSize);
				*/
				continue;
			}

			if (lMaxFreeBlock < lpPageInfo->mMaxFreeBlockSize)
			{
				lMaxFreeBlock = lpPageInfo->mMaxFreeBlockSize;
			}
		}
		lNumHeapSnapShot++;

		// We get a complete set of pages sorted by address for one snap shot of heap, output it now
		// Sample various measures to reflect different views of the heap profile
		size_t lTotalFromOS = 0;
		size_t lTotalFree   = 0;

		size_t lLargeBlockBytes = 0;
		size_t lSmallPageBytes = 0;
		size_t lFixedPageBytes = 0;
		size_t lExternalPageBytes = 0;
		size_t lFreeRegionBytes = 0;

		size_t* lBytesMainHeapSubPool = new size_t[(lMaxPoolNo+1)*(lMaxSubPoolNo+1)];
		::memset(lBytesMainHeapSubPool, 0, sizeof(size_t)*(lMaxPoolNo+1)*(lMaxSubPoolNo+1));

		// Find the cause of heap growth
		unsigned int lBucketInMyContext = 0;
		unsigned int lBucketInOtherContext = 0;

		unsigned int lMaxFreeBlockInMyContext = 0;
		unsigned int lMaxFreeBlockInOtherContext = 0;

		unsigned int lMaxFreeRegion = 0;

		size_t lGapTotalKBytes = 0;

		// Print out addr-sorted page info structures
		PAGESET::iterator it;
		char* lpPrevPageEndAddr = NULL;
		for(it=lPageSet.begin(); it!=lPageSet.end(); it++)
		{
			PageInfo* lpPage = *it;

			size_t lPageSize = (lpPage->mPageEnd - lpPage->mPageStart);

			///////////////////////////////////////////////////////////////////
			// Statistics
			///////////////////////////////////////////////////////////////////
			lTotalFree += lpPage->mFreeBytes;
			lTotalFromOS += lPageSize;

			// Large_block is directly allocated from OS mmap/VirtualAlloc
			if(lpPage->mPageType == PT_External && lPageSize >= lpHeader->mLargeBlockThreshold)
			{
				lLargeBlockBytes += lPageSize;
			}
			// Others are from main heap (except Windows) sbrk/VirtualAlloc
			else
			{
				int lIndex = lpPage->mPool*(lMaxSubPoolNo+1) + lpPage->mSubPool;
				lBytesMainHeapSubPool[lIndex] += lPageSize;
				// Bytes beloings to different pages on main heap
				if(lpPage->mPageType == PT_Small2 || lpPage->mPageType == PT_Free)
				{
					lSmallPageBytes += lPageSize;
				}
				else if(lpPage->mPageType == PT_Fixed)
				{
					lFixedPageBytes += lPageSize;
				}
				else if(lpPage->mPageType == PT_External)
				{
					lExternalPageBytes += lPageSize;
				}
				else if (lpPage->mPageType == PT_FreeRegion)
				{
					lFreeRegionBytes += lPageSize;
				}
			}

			///////////////////////////////////////////////////////////////////
			// Seek the cause of heap growth
			///////////////////////////////////////////////////////////////////
			if (lRequestBlockClass == SMALL_BLOCK && lpPage->mPageType == PT_Small2)
			{
				if (lpHeapInfo->mUserRequestSize <= lpPage->mMaxFreeBlockSize
					&& lpHeapInfo->mUserRequestSize > lpPage->mMaxFreeBlockSize - 8)
				{
					if (lpHeapInfo->mPool == lpPage->mPool && lpHeapInfo->mSubPool == lpPage->mSubPool)
						lBucketInMyContext++;
					else
						lBucketInOtherContext++;
				}
			}
			else if (lRequestBlockClass == MEDIUM_BLOCK && lpPage->mPageType == PT_Fixed)
			{
				if (lpHeapInfo->mPool == lpPage->mPool && lpHeapInfo->mSubPool == lpPage->mSubPool)
				{
					if (lMaxFreeBlockInMyContext < lpPage->mMaxFreeBlockSize)
						lMaxFreeBlockInMyContext = lpPage->mMaxFreeBlockSize;
				}
				else
				{
					if (lMaxFreeBlockInOtherContext < lpPage->mMaxFreeBlockSize)
						lMaxFreeBlockInOtherContext = lpPage->mMaxFreeBlockSize;
				}
			}
			else if (lRequestBlockClass == EXTERNAL_BLOCK && lpPage->mPageType == PT_FreeRegion)
			{
				if (lMaxFreeRegion < lpPage->mMaxFreeBlockSize)
					lMaxFreeRegion = lpPage->mMaxFreeBlockSize;
			}

			// check contiguousness of this page with the previous one
			if(gbPrintDetail && lpPrevPageEndAddr && lpPage->mPageStart != lpPrevPageEndAddr)
			{
				size_t lGapKBytes = ((long)lpPage->mPageStart-(long)lpPrevPageEndAddr)/1024;
				// Ignore gap between main heap and mmap arena
				if (lpPrevPageEndAddr <= lpHeapInfo->mHeapTop)
				{
					if (lGapKBytes < 4 * 1024 * 1024)
					{
						lGapTotalKBytes += lGapKBytes;
						printf(" ==> Gap(%ld KB) [0x%lx = 0x%lx]\n",
								lGapKBytes, lpPrevPageEndAddr, lpPage->mPageStart);
					}
					else
					{
						printf(" ==> Large Gap <== [0x%lx = 0x%lx]\n",
								lpPrevPageEndAddr, lpPage->mPageStart);
					}
				}
			}
			lpPrevPageEndAddr = lpPage->mPageEnd;

			if(PrintPageInfo(*it, lpHeader) == false)
			{
				return;
			}
		}
		// win32 can't fit big number like lTotalFree*100
		int lFragPercent = (int) ((double)lTotalFree*100/lTotalFromOS);

		if (gbPrintDetail)
		{
			// overall statistics
			printf("TOTAL_FROM_OS[%ld MB]=MainHeap[%ld MB]+mmap[%ld MB], TOTAL_FREE=[%ld MB], FRAGMENTATION=[%ld%%]\n", 
					lTotalFromOS/MB, (lTotalFromOS-lLargeBlockBytes)/MB, lLargeBlockBytes/MB,
					lTotalFree/MB, lFragPercent);
			// temperary debug info
			printf("Total_Gap: %ld MB\n", lGapTotalKBytes/1024);
			// memory distribution in various types
			printf("FreeRegion=[%ld MB], SmallPage=[%ld MB], FixedPage=[%ld MB], ExternalPage(excluding Large)=[%ld MB], LargePage=[%ld MB]\n",
				lFreeRegionBytes/MB, lSmallPageBytes/MB, lFixedPageBytes/MB,
				lExternalPageBytes/MB, lLargeBlockBytes/MB);
			for(int i=0; i<=lMaxPoolNo; i++)
			{
				for(int j=0; j<=lMaxSubPoolNo; j++)
				{
					size_t lSubPoolSize = lBytesMainHeapSubPool[i*(lMaxSubPoolNo+1)+j];
					if(lSubPoolSize > 0)
					{
						printf("\t[%d,%d]: %ld KB\n", i, j, lSubPoolSize/KB);
					}
				}
			}
		}

		// Print the fragmentation reaosn
		if (lRequestBlockClass == SMALL_BLOCK)
		{
			printf("[Small_Block(Request=%d) %d buckets in chosen context %d buckets in other contexts]",
				lpHeapInfo->mUserRequestSize,
				lBucketInMyContext, lBucketInOtherContext);
		}
		else if (lRequestBlockClass == MEDIUM_BLOCK)
		{
			printf("[Medium_Block(Request=%d) max_free_block %d in chosen context %d in other contexts]",
				lpHeapInfo->mUserRequestSize, 
				lMaxFreeBlockInMyContext, lMaxFreeBlockInOtherContext);
		}
		else if (lRequestBlockClass == EXTERNAL_BLOCK)
		{
			printf("[External_Block(Request=%d) max_free_region %d]",
				lpHeapInfo->mUserRequestSize, lMaxFreeRegion);
		}
		else
			printf("[Large_Block(Request=%d)]", lpHeapInfo->mUserRequestSize);

		printf(" MaxFreeBlock=%d\tTotalFree=%ld\tTotalFromOS=%ld\tFragmentation=%d%%%s\n", 
			lMaxFreeBlock, lTotalFree, lTotalFromOS, lFragPercent,
			(lpHeapInfo->mUserRequestSize <= lMaxFreeBlock) ? " <===" : "");
		printf("\n");

		// Generate a image file
		/*if(gGenHeapImages)
		{
			char lImageName[64];
			sprintf(lImageName, "t%03ld", lNumHeapSnapShot);
			if(lPageSet.size()>0 && false == GenHeapBar(lImageName, lpHeapInfo, &lPageSet))
			{
				// something wrong, abort the mission
				break;
			}
		}*/

		delete lBytesMainHeapSubPool;
		// Move to next heap snap shot
		lpHeapInfo = (HeapInfo*)(lpPageInfo+1);
	}

	// Debug only
#ifdef _DEBUG
	printf("TotalPage=%ld EndPage=%ld DupPage=%ld\n", lTotalPage, lEndPage, lDupPage);
#endif
}