* Completed image tracking using the image event counter sent with

various debugger messages. We do now correctly match all sampled
  addresses.
* Update the saved info of a team's main thread after exec*(), so we
  can print a more useful name.
* Improved the output: The images are listed in a table, now. The
  function table also includes the image IDs for the functions.
* Cleaned up debug output.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27657 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2008-09-20 20:44:19 +00:00
parent eba9a4c3ee
commit 1ecc0a33db
+221 -62
View File
@@ -80,11 +80,13 @@ struct HitSymbol {
class Image : public Referenceable {
public:
Image(const image_info& info)
Image(const image_info& info, int32 creationEvent)
:
fInfo(info),
fSymbols(NULL),
fSymbolCount(0)
fSymbolCount(0),
fCreationEvent(creationEvent),
fDeletionEvent(-1)
{
}
@@ -107,10 +109,25 @@ public:
return fInfo;
}
int32 CreationEvent() const
{
return fCreationEvent;
}
int32 DeletionEvent() const
{
return fDeletionEvent;
}
void SetDeletionEvent(int32 event)
{
fDeletionEvent = event;
}
status_t LoadSymbols(debug_symbol_lookup_context* lookupContext)
{
printf("Loading symbols of image \"%s\" (%ld)...\n", fInfo.name,
fInfo.id);
// printf("Loading symbols of image \"%s\" (%ld)...\n", fInfo.name,
// fInfo.id);
// create symbol iterator
debug_symbol_iterator* iterator;
@@ -203,6 +220,8 @@ private:
image_info fInfo;
Symbol** fSymbols;
int32 fSymbolCount;
int32 fCreationEvent;
int32 fDeletionEvent;
};
@@ -316,6 +335,13 @@ public:
addr_t* Samples() const { return fSamples; }
Team* GetTeam() const { return fTeam; }
void UpdateInfo()
{
thread_info info;
if (get_thread_info(ID(), &info) == B_OK)
fInfo = info;
}
void SetSampleArea(area_id area, addr_t* samples)
{
fSampleArea = area;
@@ -369,8 +395,21 @@ public:
return NULL;
}
void AddSamples(int32 count, int32 stackDepth)
void AddSamples(int32 count, int32 stackDepth, int32 event)
{
_RemoveObsoleteImages(event);
// Temporarily remove images that have been created after the given
// event.
ImageList newImages;
ImageList::Iterator it = fImages.GetIterator();
while (ThreadImage* image = it.Next()) {
if (image->GetImage()->CreationEvent() > event) {
it.Remove();
newImages.Add(image);
}
}
count = count / stackDepth * stackDepth;
for (int32 i = 0; i < count; i += stackDepth) {
@@ -389,37 +428,68 @@ public:
}
fTotalHits += count / stackDepth;
// re-add the new images
fImages.MoveFrom(&newImages);
_SynchronizeImages();
}
void PrintResults() const
{
printf("total hits: %lld, missed: %lld\n", fTotalHits, fMissedTicks);
// count images and symbols
int32 imageCount = 0;
int32 symbolCount = 0;
ImageList::ConstIterator it = fImages.GetIterator();
ImageList::ConstIterator it = fOldImages.GetIterator();
while (ThreadImage* image = it.Next()) {
const image_info& imageInfo = image->GetImage()->Info();
printf(" image: %s (%ld): %lld hits, %lld misses\n",
imageInfo.name, imageInfo.id, image->TotalHits(),
image->MissedHits());
symbolCount += image->GetImage()->SymbolCount();
if (image->TotalHits() > 0) {
imageCount++;
if (image->TotalHits() > image->MissedHits())
symbolCount += image->GetImage()->SymbolCount();
}
}
it = fImages.GetIterator();
while (ThreadImage* image = it.Next()) {
if (image->TotalHits() > 0) {
imageCount++;
if (image->TotalHits() > image->MissedHits())
symbolCount += image->GetImage()->SymbolCount();
}
}
ThreadImage* images[imageCount];
imageCount = 0;
it = fOldImages.GetIterator();
while (ThreadImage* image = it.Next()) {
if (image->TotalHits() > 0)
images[imageCount++] = image;
}
it = fImages.GetIterator();
while (ThreadImage* image = it.Next()) {
if (image->TotalHits() > 0)
images[imageCount++] = image;
}
// find and sort the hit symbols
HitSymbol hitSymbols[symbolCount];
int32 hitSymbolCount = 0;
it = fImages.GetIterator();
while (ThreadImage* image = it.Next()) {
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];
for (int32 k = 0; k < imageCount; k++) {
ThreadImage* image = images[k];
if (image->TotalHits() > image->MissedHits()) {
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];
}
}
}
}
@@ -438,18 +508,30 @@ public:
fMissedTicks, fMissedTicks * fInterval,
100.0 * fMissedTicks / totalTicks);
if (imageCount > 0) {
printf("\n");
printf(" hits unknown image\n");
printf(" -------------------------------------------------"
"-----------------------------\n");
for (int32 k = 0; k < imageCount; k++) {
ThreadImage* image = images[k];
const image_info& imageInfo = image->GetImage()->Info();
printf(" %10lld %10lld %7ld %s\n", image->TotalHits(),
image->MissedHits(), imageInfo.id, imageInfo.name);
}
}
if (hitSymbolCount > 0) {
printf("\n");
printf(" hits in us in %% function\n");
printf(" hits in us in %% image function\n");
printf(" -------------------------------------------------"
"-----------------------------\n");
for (int32 i = 0; i < hitSymbolCount; i++) {
const HitSymbol& hitSymbol = hitSymbols[i];
const Symbol* symbol = hitSymbol.symbol;
printf(" %10lld %10lld %6.2f %s\n", hitSymbol.hits,
printf(" %10lld %10lld %6.2f %6ld %s\n", hitSymbol.hits,
hitSymbol.hits * fInterval,
100.0 * hitSymbol.hits / totalTicks,
100.0 * hitSymbol.hits / totalTicks, symbol->image->ID(),
symbol->Name());
}
} else
@@ -457,9 +539,38 @@ public:
}
private:
typedef DoublyLinkedList<ThreadImage> ImageList;
void _SynchronizeImages();
void _RemoveObsoleteImages(int32 event)
{
// remove obsolete images
ImageList::Iterator it = fImages.GetIterator();
while (ThreadImage* image = it.Next()) {
int32 deleted = image->GetImage()->DeletionEvent();
if (deleted >= 0 && event >= deleted) {
it.Remove();
if (image->TotalHits() > 0)
fOldImages.Add(image);
else
delete image;
}
}
}
ThreadImage* _FindImageByID(image_id id) const
{
ImageList::ConstIterator it = fImages.GetIterator();
while (ThreadImage* image = it.Next()) {
if (image->ID() == id)
return image;
}
return NULL;
}
private:
typedef DoublyLinkedList<ThreadImage> ImageList;
thread_info fInfo;
::Team* fTeam;
area_id fSampleArea;
@@ -595,7 +706,6 @@ public:
}
thread->SetInterval(reply.interval);
//reply.profile_event
fThreads.Add(thread);
@@ -610,15 +720,24 @@ public:
fThreads.Remove(thread);
}
void Exec()
void Exec(int32 event)
{
// remove all images
int32 imageCount = fImages.CountItems();
for (int32 i = imageCount - 1; i >= 0; i--)
_RemoveImage(i);
_RemoveImage(i, event);
// update the main thread
ThreadList::Iterator it = fThreads.GetIterator();
while (Thread* thread = it.Next()) {
if (thread->ID() == ID()) {
thread->UpdateInfo();
break;
}
}
}
status_t AddImage(const image_info& imageInfo)
status_t AddImage(const image_info& imageInfo, int32 event)
{
// create symbol lookup context
debug_symbol_lookup_context* lookupContext;
@@ -631,24 +750,26 @@ public:
}
Image* image;
error = _LoadImageSymbols(lookupContext, imageInfo, &image);
error = _LoadImageSymbols(lookupContext, imageInfo, event, &image);
debug_delete_symbol_lookup_context(lookupContext);
// TODO: Remove! The threads must be updated lazily.
if (error == B_OK) {
ThreadList::Iterator it = fThreads.GetIterator();
while (Thread* thread = it.Next())
thread->AddImage(image);
}
// Although we generally synchronize the threads' images lazily, we have
// to add new images at least, since otherwise images could be added
// and removed again, and the hits inbetween could never be matched.
if (error == B_OK) {
ThreadList::Iterator it = fThreads.GetIterator();
while (Thread* thread = it.Next())
thread->AddImage(image);
}
return error;
}
status_t RemoveImage(const image_info& imageInfo)
status_t RemoveImage(const image_info& imageInfo, int32 event)
{
for (int32 i = 0; Image* image = fImages.ItemAt(i); i++) {
if (image->ID() == imageInfo.id) {
_RemoveImage(i);
_RemoveImage(i, event);
return B_OK;
}
}
@@ -656,6 +777,21 @@ if (error == B_OK) {
return B_ENTRY_NOT_FOUND;
}
const BObjectList<Image>& Images() const
{
return fImages;
}
Image* FindImage(image_id id) const
{
for (int32 i = 0; Image* image = fImages.ItemAt(i); i++) {
if (image->ID() == id)
return image;
}
return NULL;
}
team_id ID() const
{
return fInfo.team;
@@ -668,7 +804,7 @@ private:
image_info imageInfo;
int32 cookie = 0;
while (get_next_image_info(fInfo.team, &cookie, &imageInfo) == B_OK) {
status_t error = _LoadImageSymbols(lookupContext, imageInfo);
status_t error = _LoadImageSymbols(lookupContext, imageInfo, 0);
if (error == B_NO_MEMORY)
return error;
}
@@ -677,9 +813,9 @@ private:
}
status_t _LoadImageSymbols(debug_symbol_lookup_context* lookupContext,
const image_info& imageInfo, Image** _image = NULL)
const image_info& imageInfo, int32 event, Image** _image = NULL)
{
Image* image = new(std::nothrow) Image(imageInfo);
Image* image = new(std::nothrow) Image(imageInfo, event);
if (image == NULL)
return B_NO_MEMORY;
@@ -700,17 +836,18 @@ private:
return B_OK;
}
void _RemoveImage(int32 index)
void _RemoveImage(int32 index, int32 event)
{
Image* image = fImages.RemoveItemAt(index);
if (image == NULL)
return;
// notify all threads that the image has been removed
ThreadList::Iterator it = fThreads.GetIterator();
while (Thread* thread = it.Next())
thread->ImageRemoved(image);
// Note: We don't tell the threads that the image has been removed. They
// will be updated lazily when their next profiler update arrives. This
// is necessary, since the update might contain samples hitting that
// image.
image->SetDeletionEvent(event);
image->RemoveReference();
}
@@ -825,6 +962,31 @@ private:
};
void
Thread::_SynchronizeImages()
{
const BObjectList<Image>& teamImages = fTeam->Images();
// remove obsolete images
ImageList::Iterator it = fImages.GetIterator();
while (ThreadImage* image = it.Next()) {
if (fTeam->FindImage(image->ID()) == NULL) {
it.Remove();
if (image->TotalHits() > 0)
fOldImages.Add(image);
else
delete image;
}
}
// add new images
for (int32 i = 0; Image* image = teamImages.ItemAt(i); i++) {
if (_FindImageByID(image->ID()) == NULL)
AddImage(image);
}
}
// TODO: Adjust!
static const char* kUsage =
"Usage: %s [ <options> ] <command line>\n"
@@ -974,7 +1136,8 @@ main(int argc, const char* const* argv)
break;
thread->AddSamples(message.profiler_update.sample_count,
message.profiler_update.stack_depth);
message.profiler_update.stack_depth,
message.profiler_update.image_event);
if (message.profiler_update.stopped) {
thread->PrintResults();
@@ -995,7 +1158,7 @@ main(int argc, const char* const* argv)
break;
case B_DEBUGGER_MESSAGE_TEAM_EXEC:
if (Team* team = threadManager.FindTeam(message.origin.team))
team->Exec();
team->Exec(message.team_exec.image_event);
break;
case B_DEBUGGER_MESSAGE_THREAD_CREATED:
@@ -1006,21 +1169,17 @@ main(int argc, const char* const* argv)
break;
case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
{
const image_info& info = message.image_created.info;
printf("B_DEBUGGER_MESSAGE_IMAGE_CREATED: %s (%ld)\n", info.name, info.id);
if (Team* team = threadManager.FindTeam(message.origin.team))
team->AddImage(message.image_created.info);
if (Team* team = threadManager.FindTeam(message.origin.team)) {
team->AddImage(message.image_created.info,
message.image_created.image_event);
}
break;
}
case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
{
const image_info& info = message.image_deleted.info;
printf("B_DEBUGGER_MESSAGE_IMAGE_DELETED: %s (%ld)\n", info.name, info.id);
if (Team* team = threadManager.FindTeam(message.origin.team))
team->RemoveImage(message.image_deleted.info);
if (Team* team = threadManager.FindTeam(message.origin.team)) {
team->RemoveImage(message.image_deleted.info,
message.image_deleted.image_event);
}
break;
}
case B_DEBUGGER_MESSAGE_POST_SYSCALL:
case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: