2 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2013, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
13 #include <debug_support.h>
14 #include <system_profiler_defs.h>
16 #include "debug_utils.h"
22 //#define TRACE_PROFILE_TEAM
23 #ifdef TRACE_PROFILE_TEAM
24 # define TRACE(x...) printf(x)
26 # define TRACE(x...) do {} while(false)
31 SAMPLE_AREA_SIZE
= 128 * 1024,
42 fDebugContext
.nub_port
= -1;
48 if (fDebugContext
.nub_port
>= 0)
49 destroy_debug_context(&fDebugContext
);
52 remove_team_debugger(fID
);
54 for (int32 i
= 0; Image
* image
= fImages
.ItemAt(i
); i
++)
55 image
->ReleaseReference();
60 Team::Init(team_id teamID
, port_id debuggerPort
)
64 status_t error
= get_team_info(teamID
, &teamInfo
);
69 fArgs
= teamInfo
.args
;
71 // install ourselves as the team debugger
72 fNubPort
= install_team_debugger(teamID
, debuggerPort
);
74 fprintf(stderr
, "%s: Failed to install as debugger for team %ld: "
75 "%s\n", kCommandName
, teamID
, strerror(fNubPort
));
80 error
= init_debug_context(&fDebugContext
, teamID
, fNubPort
);
82 fprintf(stderr
, "%s: Failed to init debug context for team %ld: "
83 "%s\n", kCommandName
, teamID
, strerror(error
));
87 // set team debugging flags
88 int32 teamDebugFlags
= B_TEAM_DEBUG_THREADS
89 | B_TEAM_DEBUG_TEAM_CREATION
| B_TEAM_DEBUG_IMAGES
;
90 error
= set_team_debugging_flags(fNubPort
, teamDebugFlags
);
99 Team::Init(system_profiler_team_added
* addedInfo
)
101 fID
= addedInfo
->team
;
102 fArgs
= addedInfo
->name
+ addedInfo
->args_offset
;
108 Team::InitThread(Thread
* thread
)
111 thread
->SetLazyImages(!_SynchronousProfiling());
113 // create the sample area
114 char areaName
[B_OS_NAME_LENGTH
];
115 snprintf(areaName
, sizeof(areaName
), "profiling samples %ld",
118 area_id sampleArea
= create_area(areaName
, &samples
, B_ANY_ADDRESS
,
119 SAMPLE_AREA_SIZE
, B_NO_LOCK
, B_READ_AREA
| B_WRITE_AREA
);
120 if (sampleArea
< 0) {
121 fprintf(stderr
, "%s: Failed to create sample area for thread %ld: "
122 "%s\n", kCommandName
, thread
->ID(), strerror(sampleArea
));
126 thread
->SetSampleArea(sampleArea
, (addr_t
*)samples
);
128 // add the current images to the thread
129 int32 imageCount
= fImages
.CountItems();
130 for (int32 i
= 0; i
< imageCount
; i
++) {
131 status_t error
= thread
->AddImage(fImages
.ItemAt(i
));
136 if (!_SynchronousProfiling()) {
137 // set thread debugging flags and start profiling
138 int32 threadDebugFlags
= 0;
140 // threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL
141 // | (traceChildThreads
142 // ? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0);
144 status_t error
= set_thread_debugging_flags(fNubPort
, thread
->ID(),
150 debug_nub_start_profiler message
;
151 message
.reply_port
= fDebugContext
.reply_port
;
152 message
.thread
= thread
->ID();
153 message
.interval
= gOptions
.interval
;
154 message
.sample_area
= sampleArea
;
155 message
.stack_depth
= gOptions
.stack_depth
;
156 message
.variable_stack_depth
= gOptions
.analyze_full_stack
;
158 debug_nub_start_profiler_reply reply
;
159 error
= send_debug_message(&fDebugContext
,
160 B_DEBUG_START_PROFILER
, &message
, sizeof(message
), &reply
,
162 if (error
!= B_OK
|| (error
= reply
.error
) != B_OK
) {
163 fprintf(stderr
, "%s: Failed to start profiler for thread %ld: %s\n",
164 kCommandName
, thread
->ID(), strerror(error
));
168 thread
->SetInterval(reply
.interval
);
170 fThreads
.Add(thread
);
172 // resume the target thread to be sure, it's running
173 resume_thread(thread
->ID());
175 // debugger-less profiling
176 thread
->SetInterval(gOptions
.interval
);
177 fThreads
.Add(thread
);
185 Team::RemoveThread(Thread
* thread
)
187 fThreads
.Remove(thread
);
192 Team::Exec(int32 event
, const char* args
, const char* threadName
)
194 // remove all non-kernel images
195 int32 imageCount
= fImages
.CountItems();
196 for (int32 i
= imageCount
- 1; i
>= 0; i
--) {
197 Image
* image
= fImages
.ItemAt(i
);
198 if (image
->Owner() == ID())
199 _RemoveImage(i
, event
);
204 // update the main thread
205 ThreadList::Iterator it
= fThreads
.GetIterator();
206 while (Thread
* thread
= it
.Next()) {
207 if (thread
->ID() == ID()) {
208 thread
->UpdateInfo(threadName
);
216 Team::AddImage(SharedImage
* sharedImage
, const image_info
& imageInfo
,
217 team_id owner
, int32 event
)
220 Image
* image
= new(std::nothrow
) Image(sharedImage
, imageInfo
, owner
,
225 if (!fImages
.AddItem(image
)) {
230 // Although we generally synchronize the threads' images lazily, we have
231 // to add new images at least, since otherwise images could be added
232 // and removed again, and the hits inbetween could never be matched.
233 ThreadList::Iterator it
= fThreads
.GetIterator();
234 while (Thread
* thread
= it
.Next())
235 thread
->AddImage(image
);
242 Team::RemoveImage(image_id imageID
, int32 event
)
244 for (int32 i
= 0; Image
* image
= fImages
.ItemAt(i
); i
++) {
245 if (image
->ID() == imageID
) {
246 _RemoveImage(i
, event
);
251 return B_ENTRY_NOT_FOUND
;
256 Team::FindImage(image_id id
) const
258 for (int32 i
= 0; Image
* image
= fImages
.ItemAt(i
); i
++) {
259 if (image
->ID() == id
)
268 Team::_RemoveImage(int32 index
, int32 event
)
270 Image
* image
= fImages
.RemoveItemAt(index
);
274 if (_SynchronousProfiling()) {
275 ThreadList::Iterator it
= fThreads
.GetIterator();
276 while (Thread
* thread
= it
.Next())
277 thread
->RemoveImage(image
);
279 // Note: We don't tell the threads that the image has been removed. They
280 // will be updated lazily when their next profiler update arrives. This
281 // is necessary, since the update might contain samples hitting that
285 image
->SetDeletionEvent(event
);
286 image
->ReleaseReference();