⛏️ index : haiku.git

/*
 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */


#include "BasicProfileResult.h"

#if __GNUC__ > 2
#include <cxxabi.h>
#endif
#include <stdio.h>

#include <algorithm>
#include <new>
#include <StackOrHeapArray.h>

#include "Options.h"
#include "ProfiledEntity.h"


struct HitSymbol {
	int64		hits;
	Symbol*		symbol;
	image_id	imageID;

	inline bool operator<(const HitSymbol& other) const
	{
		return hits > other.hits;
	}
};


// #pragma mark - BasicImageProfileResult


BasicImageProfileResult::BasicImageProfileResult(SharedImage* image,
	image_id id)
	:
	ImageProfileResult(image, id),
	fSymbolHits(NULL),
	fUnknownHits(0)
{
}


BasicImageProfileResult::~BasicImageProfileResult()
{
}


status_t
BasicImageProfileResult::Init()
{
	int32 symbolCount = fImage->SymbolCount();
	fSymbolHits = new(std::nothrow) int64[symbolCount];
	if (fSymbolHits == NULL)
		return B_NO_MEMORY;

	memset(fSymbolHits, 0, 8 * symbolCount);

	return B_OK;
}


bool
BasicImageProfileResult::AddHit(addr_t address)
{
	int32 symbolIndex = fImage->FindSymbol(address);
	if (symbolIndex < 0)
		return false;

	fSymbolHits[symbolIndex]++;
	fTotalHits++;

	return true;
}


void
BasicImageProfileResult::AddUnknownHit()
{
	fUnknownHits++;
	fTotalHits++;
}


void
BasicImageProfileResult::AddSymbolHit(int32 symbolIndex)
{
	fSymbolHits[symbolIndex]++;
}


void
BasicImageProfileResult::AddImageHit()
{
	fTotalHits++;
}


const int64*
BasicImageProfileResult::SymbolHits() const
{
	return fSymbolHits;
}


int64
BasicImageProfileResult::UnknownHits() const
{
	return fUnknownHits;
}


// #pragma mark - BasicProfileResult


BasicProfileResult::BasicProfileResult()
	:
	fTotalTicks(0),
	fUnkownTicks(0),
	fExpectedTicks(0),
	fDroppedTicks(0),
	fTotalSampleCount(0)
{
}


void
BasicProfileResult::AddExpectedTicks(int32 expected)
{
	fExpectedTicks += expected;
}


void
BasicProfileResult::AddDroppedTicks(int32 dropped)
{
	fDroppedTicks += dropped;
}


void
BasicProfileResult::PrintResults(ImageProfileResultContainer* container)
{
	// get hit images
	BStackOrHeapArray<BasicImageProfileResult*, 128> images(container->CountImages());
	int32 imageCount = GetHitImages(container, &*images);

	// count symbols
	int32 symbolCount = 0;
	for (int32 k = 0; k < imageCount; k++) {
		BasicImageProfileResult* image = images[k];
		if (image->TotalHits() > image->UnknownHits())
			symbolCount += image->GetImage()->SymbolCount();
	}

	// find and sort the hit symbols
	BStackOrHeapArray<HitSymbol, 128> hitSymbols(symbolCount);
	int32 hitSymbolCount = 0;

	for (int32 k = 0; k < imageCount; k++) {
		BasicImageProfileResult* image = images[k];
		if (image->TotalHits() > image->UnknownHits()) {
			Symbol** symbols = image->GetImage()->Symbols();
			const int64* symbolHits = image->SymbolHits();
			int32 imageSymbolCount = image->GetImage()->SymbolCount();
			for (int32 i = 0; i < imageSymbolCount; i++) {
				if (symbolHits[i] > 0) {
					HitSymbol& hitSymbol = hitSymbols[hitSymbolCount++];
					hitSymbol.hits = symbolHits[i];
					hitSymbol.symbol = symbols[i];
					hitSymbol.imageID = image->ID();
				}
			}
		}
	}

	if (hitSymbolCount > 1)
		std::sort(&*hitSymbols, hitSymbols + hitSymbolCount);

	int64 totalTicks = fTotalTicks;
	const int64 missedTicks = fExpectedTicks - fTotalTicks;

	fprintf(gOptions.output, "\nprofiling results for %s \"%s\" "
		"(%" B_PRId32 "):\n", fEntity->EntityType(), fEntity->EntityName(),
		fEntity->EntityID());
	fprintf(gOptions.output, "  tick interval:  %" B_PRIdBIGTIME " us\n",
		fInterval);
	fprintf(gOptions.output,
		"  total ticks:    %" B_PRId64 " (%" B_PRId64 " us)\n",
		totalTicks, totalTicks * fInterval);
	if (fExpectedTicks != 0) {
		fprintf(gOptions.output,
			"  expected ticks: %" B_PRId64 " (missed %" B_PRId64 ")\n",
			fExpectedTicks, missedTicks);
	}
	if (totalTicks == 0)
		totalTicks = 1;

	fprintf(gOptions.output,
		"  unknown ticks:  %" B_PRId64 " (%" B_PRId64 " us, %6.2f%%)\n",
		fUnkownTicks, fUnkownTicks * fInterval,
		100.0 * fUnkownTicks / totalTicks);
	fprintf(gOptions.output,
		"  dropped ticks:  %" B_PRId64 " (%" B_PRId64 " us, %6.2f%%)\n",
		fDroppedTicks, fDroppedTicks * fInterval,
		100.0 * fDroppedTicks / totalTicks);
	if (gOptions.analyze_full_stack) {
		fprintf(gOptions.output, "  samples/tick:   %.1f\n",
			(double)fTotalSampleCount / totalTicks);
	}

	if (imageCount > 0) {
		fprintf(gOptions.output, "\n");
		fprintf(gOptions.output, "        hits     unknown    image\n");
		fprintf(gOptions.output, "  ---------------------------------------"
			"---------------------------------------\n");
		for (int32 k = 0; k < imageCount; k++) {
			BasicImageProfileResult* image = images[k];
			fprintf(gOptions.output,
				"  %10" B_PRId64 "  %10" B_PRId64 "  %7" B_PRId32 " %s\n",
				image->TotalHits(), image->UnknownHits(),
				image->ID(), image->GetImage()->Name());
		}
	}

	if (hitSymbolCount > 0) {
		fprintf(gOptions.output, "\n");
		fprintf(gOptions.output, "        hits       in us    in %%   "
			"image  function\n");
		fprintf(gOptions.output, "  ---------------------------------------"
			"---------------------------------------\n");
		for (int32 i = 0; i < hitSymbolCount; i++) {
			const HitSymbol& hitSymbol = hitSymbols[i];
			const Symbol* symbol = hitSymbol.symbol;
#if __GNUC__ > 2
			int status;
			const char* symbolName = __cxxabiv1::__cxa_demangle(symbol->Name(),
				NULL, NULL, &status);
			if (symbolName == NULL)
				symbolName = symbol->Name();
#else
			const char* symbolName = symbol->Name();
#endif
			fprintf(gOptions.output,
				"  %10" B_PRId64 "  %10" B_PRId64 "  %6.2f  %6" B_PRId32
				"  %s\n", hitSymbol.hits, hitSymbol.hits * fInterval,
				100.0 * hitSymbol.hits / totalTicks, hitSymbol.imageID,
				symbolName);
#if __GNUC__ > 2
			if (status == 0)
				free(const_cast<char*>(symbolName));
#endif
		}
	} else
		fprintf(gOptions.output, "  no functions were hit\n");
}


status_t
BasicProfileResult::GetImageProfileResult(SharedImage* image, image_id id,
	ImageProfileResult*& _imageResult)
{
	BasicImageProfileResult* result
		= new(std::nothrow) BasicImageProfileResult(image, id);
	if (result == NULL)
		return B_NO_MEMORY;

	status_t error = result->Init();
	if (error != B_OK) {
		delete result;
		return error;
	}

	_imageResult = result;
	return B_OK;
}


// #pragma mark - InclusiveProfileResult


void
InclusiveProfileResult::AddSamples(ImageProfileResultContainer* container,
	addr_t* samples, int32 sampleCount)
{
	// Sort the samples. This way hits of the same symbol are
	// successive and we can avoid incrementing the hit count of the
	// same symbol twice. Same for images.
	std::sort(samples, samples + sampleCount);

	int32 unknownSamples = 0;
	BasicImageProfileResult* previousImage = NULL;
	int32 previousSymbol = -1;

	for (int32 i = 0; i < sampleCount; i++) {
		addr_t address = samples[i];
		addr_t loadDelta;
		BasicImageProfileResult* image = static_cast<BasicImageProfileResult*>(
			container->FindImage(address, loadDelta));
		int32 symbol = -1;
		if (image != NULL) {
			symbol = image->GetImage()->FindSymbol(address - loadDelta);
			if (image != previousImage || symbol != previousSymbol) {
				if (symbol < 0)
					image->AddUnknownHit();
				else
					image->AddSymbolHit(symbol);
			}

			if (image != previousImage)
				image->AddImageHit();
		} else
			unknownSamples++;

		previousImage = image;
		previousSymbol = symbol;
	}

	if (unknownSamples == sampleCount)
		fUnkownTicks++;

	fTotalTicks++;
	fTotalSampleCount += sampleCount;
}


// #pragma mark - ExclusiveProfileResult


void
ExclusiveProfileResult::AddSamples(ImageProfileResultContainer* container,
	addr_t* samples, int32 sampleCount)
{
	BasicImageProfileResult* image = NULL;
		// the image in which we hit a symbol
	BasicImageProfileResult* firstImage = NULL;
		// the first image we hit, != image if no symbol was hit

	for (int32 k = 0; k < sampleCount; k++) {
		addr_t address = samples[k];
		addr_t loadDelta;
		image = static_cast<BasicImageProfileResult*>(
			container->FindImage(address, loadDelta));
		if (image != NULL) {
			if (image->AddHit(address - loadDelta))
				break;
			if (firstImage == NULL)
				firstImage = image;
			image = NULL;
		}
	}

	if (image == NULL) {
		if (firstImage != NULL)
			firstImage->AddUnknownHit();
		else
			fUnkownTicks++;
	}

	fTotalTicks++;
	fTotalSampleCount += sampleCount;
}