/*
* Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2013, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License.
*/
#include "Team.h"
#include <new>
#include <image.h>
#include <debug_support.h>
#include <system_profiler_defs.h>
#include "debug_utils.h"
#include "Image.h"
#include "Options.h"
//#define TRACE_PROFILE_TEAM
#ifdef TRACE_PROFILE_TEAM
# define TRACE(x...) printf(x)
#else
# define TRACE(x...) do {} while(false)
#endif
enum {
SAMPLE_AREA_SIZE = 128 * 1024,
};
Team::Team()
:
fID(-1),
fNubPort(-1),
fThreads(),
fImages(20, false)
{
fDebugContext.nub_port = -1;
}
Team::~Team()
{
if (fDebugContext.nub_port >= 0)
destroy_debug_context(&fDebugContext);
if (fNubPort >= 0)
remove_team_debugger(fID);
for (int32 i = 0; Image* image = fImages.ItemAt(i); i++)
image->ReleaseReference();
}
status_t
Team::Init(team_id teamID, port_id debuggerPort)
{
// get team info
team_info teamInfo;
status_t error = get_team_info(teamID, &teamInfo);
if (error != B_OK)
return error;
fID = teamID;
fArgs = teamInfo.args;
// install ourselves as the team debugger
fNubPort = install_team_debugger(teamID, debuggerPort);
if (fNubPort < 0) {
fprintf(stderr, "%s: Failed to install as debugger for team %ld: "
"%s\n", kCommandName, teamID, strerror(fNubPort));
return fNubPort;
}
// init debug context
error = init_debug_context(&fDebugContext, teamID, fNubPort);
if (error != B_OK) {
fprintf(stderr, "%s: Failed to init debug context for team %ld: "
"%s\n", kCommandName, teamID, strerror(error));
return error;
}
// set team debugging flags
int32 teamDebugFlags = B_TEAM_DEBUG_THREADS
| B_TEAM_DEBUG_TEAM_CREATION | B_TEAM_DEBUG_IMAGES;
error = set_team_debugging_flags(fNubPort, teamDebugFlags);
if (error != B_OK)
return error;
return B_OK;
}
status_t
Team::Init(system_profiler_team_added* addedInfo)
{
fID = addedInfo->team;
fArgs = addedInfo->name + addedInfo->args_offset;
return B_OK;
}
status_t
Team::InitThread(Thread* thread)
{
// The thread
thread->SetLazyImages(!_SynchronousProfiling());
// create the sample area
char areaName[B_OS_NAME_LENGTH];
snprintf(areaName, sizeof(areaName), "profiling samples %ld",
thread->ID());
void* samples;
area_id sampleArea = create_area(areaName, &samples, B_ANY_ADDRESS,
SAMPLE_AREA_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (sampleArea < 0) {
fprintf(stderr, "%s: Failed to create sample area for thread %ld: "
"%s\n", kCommandName, thread->ID(), strerror(sampleArea));
return sampleArea;
}
thread->SetSampleArea(sampleArea, (addr_t*)samples);
// add the current images to the thread
int32 imageCount = fImages.CountItems();
for (int32 i = 0; i < imageCount; i++) {
status_t error = thread->AddImage(fImages.ItemAt(i));
if (error != B_OK)
return error;
}
if (!_SynchronousProfiling()) {
// set thread debugging flags and start profiling
int32 threadDebugFlags = 0;
// if (!traceTeam) {
// threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL
// | (traceChildThreads
// ? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0);
// }
status_t error = set_thread_debugging_flags(fNubPort, thread->ID(),
threadDebugFlags);
if (error != B_OK)
return error;
// start profiling
debug_nub_start_profiler message;
message.reply_port = fDebugContext.reply_port;
message.thread = thread->ID();
message.interval = gOptions.interval;
message.sample_area = sampleArea;
message.stack_depth = gOptions.stack_depth;
message.variable_stack_depth = gOptions.analyze_full_stack;
debug_nub_start_profiler_reply reply;
error = send_debug_message(&fDebugContext,
B_DEBUG_START_PROFILER, &message, sizeof(message), &reply,
sizeof(reply));
if (error != B_OK || (error = reply.error) != B_OK) {
fprintf(stderr, "%s: Failed to start profiler for thread %ld: %s\n",
kCommandName, thread->ID(), strerror(error));
return error;
}
thread->SetInterval(reply.interval);
fThreads.Add(thread);
// resume the target thread to be sure, it's running
resume_thread(thread->ID());
} else {
// debugger-less profiling
thread->SetInterval(gOptions.interval);
fThreads.Add(thread);
}
return B_OK;
}
void
Team::RemoveThread(Thread* thread)
{
fThreads.Remove(thread);
}
void
Team::Exec(int32 event, const char* args, const char* threadName)
{
// remove all non-kernel images
int32 imageCount = fImages.CountItems();
for (int32 i = imageCount - 1; i >= 0; i--) {
Image* image = fImages.ItemAt(i);
if (image->Owner() == ID())
_RemoveImage(i, event);
}
fArgs = args;
// update the main thread
ThreadList::Iterator it = fThreads.GetIterator();
while (Thread* thread = it.Next()) {
if (thread->ID() == ID()) {
thread->UpdateInfo(threadName);
break;
}
}
}
status_t
Team::AddImage(SharedImage* sharedImage, const image_info& imageInfo,
team_id owner, int32 event)
{
// create the image
Image* image = new(std::nothrow) Image(sharedImage, imageInfo, owner,
event);
if (image == NULL)
return B_NO_MEMORY;
if (!fImages.AddItem(image)) {
delete image;
return B_NO_MEMORY;
}
// 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.
ThreadList::Iterator it = fThreads.GetIterator();
while (Thread* thread = it.Next())
thread->AddImage(image);
return B_OK;
}
status_t
Team::RemoveImage(image_id imageID, int32 event)
{
for (int32 i = 0; Image* image = fImages.ItemAt(i); i++) {
if (image->ID() == imageID) {
_RemoveImage(i, event);
return B_OK;
}
}
return B_ENTRY_NOT_FOUND;
}
Image*
Team::FindImage(image_id id) const
{
for (int32 i = 0; Image* image = fImages.ItemAt(i); i++) {
if (image->ID() == id)
return image;
}
return NULL;
}
void
Team::_RemoveImage(int32 index, int32 event)
{
Image* image = fImages.RemoveItemAt(index);
if (image == NULL)
return;
if (_SynchronousProfiling()) {
ThreadList::Iterator it = fThreads.GetIterator();
while (Thread* thread = it.Next())
thread->RemoveImage(image);
} else {
// 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->ReleaseReference();
}
↑ V576 Incorrect format. Consider checking the fourth actual argument of the 'fprintf' function. The memsize type argument is expected.
↑ V576 Incorrect format. Consider checking the fourth actual argument of the 'fprintf' function. The memsize type argument is expected.
↑ V576 Incorrect format. Consider checking the fourth actual argument of the 'fprintf' function. The memsize type argument is expected.
↑ V576 Incorrect format. Consider checking the fourth actual argument of the 'fprintf' function. The memsize type argument is expected.
↑ V576 Incorrect format. Consider checking the fourth actual argument of the 'snprintf' function. The memsize type argument is expected.