* Renamed *ProfileResultImage to *ImageProfileResult.
* Separated the image result management from the *ProfileResult classes:
- The general per-thread image management functionality does now live in
Thread.
- Introduced interface ImageProfileResultContainer which is implemented by
Thread. An instance is passed to ProfileResult::AddSamples()/PrintResult().
* Made *ProfileResultImage independent of Image. The dependency is now to
SharedImage only.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35556 a95241bf-73f2-0310-859d-f6bbb57e9c96
311 lines
7.1 KiB
C++
311 lines
7.1 KiB
C++
/*
|
|
* Copyright 2008-2010, Ingo Weinhold, [email protected].
|
|
* Distributed under the terms of the MIT License.
|
|
*/
|
|
|
|
|
|
#include "BasicProfileResult.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <algorithm>
|
|
#include <new>
|
|
|
|
#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),
|
|
fDroppedTicks(0),
|
|
fTotalSampleCount(0)
|
|
{
|
|
}
|
|
|
|
|
|
void
|
|
BasicProfileResult::AddDroppedTicks(int32 dropped)
|
|
{
|
|
fDroppedTicks += dropped;
|
|
}
|
|
|
|
|
|
void
|
|
BasicProfileResult::PrintResults(ImageProfileResultContainer* container)
|
|
{
|
|
// get hit images
|
|
BasicImageProfileResult* 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
|
|
HitSymbol 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;
|
|
fprintf(gOptions.output, "\nprofiling results for %s \"%s\" "
|
|
"(%" B_PRId32 "):\n", fEntity->EntityType(), fEntity->EntityName(),
|
|
fEntity->EntityID());
|
|
fprintf(gOptions.output, " tick interval: %lld us\n", fInterval);
|
|
fprintf(gOptions.output, " total ticks: %lld (%lld us)\n",
|
|
totalTicks, totalTicks * fInterval);
|
|
if (totalTicks == 0)
|
|
totalTicks = 1;
|
|
fprintf(gOptions.output, " unknown ticks: %lld (%lld us, %6.2f%%)\n",
|
|
fUnkownTicks, fUnkownTicks * fInterval,
|
|
100.0 * fUnkownTicks / totalTicks);
|
|
fprintf(gOptions.output, " dropped ticks: %lld (%lld 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, " %10lld %10lld %7ld %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;
|
|
fprintf(gOptions.output, " %10lld %10lld %6.2f %6ld %s\n",
|
|
hitSymbol.hits, hitSymbol.hits * fInterval,
|
|
100.0 * hitSymbol.hits / totalTicks, hitSymbol.imageID,
|
|
symbol->Name());
|
|
}
|
|
} else
|
|
fprintf(gOptions.output, " no functions were hit\n");
|
|
}
|
|
|
|
|
|
ImageProfileResult*
|
|
BasicProfileResult::CreateImageProfileResult(SharedImage* image, image_id id)
|
|
{
|
|
return new(std::nothrow) BasicImageProfileResult(image, id);
|
|
}
|
|
|
|
|
|
// #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 (symbol < 0) {
|
|
// TODO: Count unknown image hits?
|
|
} else if (image != previousImage || symbol != previousSymbol)
|
|
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;
|
|
}
|
|
}
|
|
|
|
if (image == NULL) {
|
|
if (firstImage != NULL)
|
|
firstImage->AddUnknownHit();
|
|
else
|
|
fUnkownTicks++;
|
|
}
|
|
|
|
fTotalTicks++;
|
|
fTotalSampleCount += sampleCount;
|
|
}
|