RemoteDrawingEngine: Reduce RP_READ_BITMAP result timeout.
[haiku.git] / src / bin / debug / profile / Team.cpp
blob433fde1269e5726ce86e2f4f89c43676d1300939
1 /*
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.
5 */
7 #include "Team.h"
9 #include <new>
11 #include <image.h>
13 #include <debug_support.h>
14 #include <system_profiler_defs.h>
16 #include "debug_utils.h"
18 #include "Image.h"
19 #include "Options.h"
22 //#define TRACE_PROFILE_TEAM
23 #ifdef TRACE_PROFILE_TEAM
24 # define TRACE(x...) printf(x)
25 #else
26 # define TRACE(x...) do {} while(false)
27 #endif
30 enum {
31 SAMPLE_AREA_SIZE = 128 * 1024,
35 Team::Team()
37 fID(-1),
38 fNubPort(-1),
39 fThreads(),
40 fImages(20, false)
42 fDebugContext.nub_port = -1;
46 Team::~Team()
48 if (fDebugContext.nub_port >= 0)
49 destroy_debug_context(&fDebugContext);
51 if (fNubPort >= 0)
52 remove_team_debugger(fID);
54 for (int32 i = 0; Image* image = fImages.ItemAt(i); i++)
55 image->ReleaseReference();
59 status_t
60 Team::Init(team_id teamID, port_id debuggerPort)
62 // get team info
63 team_info teamInfo;
64 status_t error = get_team_info(teamID, &teamInfo);
65 if (error != B_OK)
66 return error;
68 fID = teamID;
69 fArgs = teamInfo.args;
71 // install ourselves as the team debugger
72 fNubPort = install_team_debugger(teamID, debuggerPort);
73 if (fNubPort < 0) {
74 fprintf(stderr, "%s: Failed to install as debugger for team %ld: "
75 "%s\n", kCommandName, teamID, strerror(fNubPort));
76 return fNubPort;
79 // init debug context
80 error = init_debug_context(&fDebugContext, teamID, fNubPort);
81 if (error != B_OK) {
82 fprintf(stderr, "%s: Failed to init debug context for team %ld: "
83 "%s\n", kCommandName, teamID, strerror(error));
84 return 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);
91 if (error != B_OK)
92 return error;
94 return B_OK;
98 status_t
99 Team::Init(system_profiler_team_added* addedInfo)
101 fID = addedInfo->team;
102 fArgs = addedInfo->name + addedInfo->args_offset;
103 return B_OK;
107 status_t
108 Team::InitThread(Thread* thread)
110 // The 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",
116 thread->ID());
117 void* samples;
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));
123 return 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));
132 if (error != B_OK)
133 return error;
136 if (!_SynchronousProfiling()) {
137 // set thread debugging flags and start profiling
138 int32 threadDebugFlags = 0;
139 // if (!traceTeam) {
140 // threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL
141 // | (traceChildThreads
142 // ? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0);
143 // }
144 status_t error = set_thread_debugging_flags(fNubPort, thread->ID(),
145 threadDebugFlags);
146 if (error != B_OK)
147 return error;
149 // start profiling
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,
161 sizeof(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));
165 return 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());
174 } else {
175 // debugger-less profiling
176 thread->SetInterval(gOptions.interval);
177 fThreads.Add(thread);
180 return B_OK;
184 void
185 Team::RemoveThread(Thread* thread)
187 fThreads.Remove(thread);
191 void
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);
202 fArgs = args;
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);
209 break;
215 status_t
216 Team::AddImage(SharedImage* sharedImage, const image_info& imageInfo,
217 team_id owner, int32 event)
219 // create the image
220 Image* image = new(std::nothrow) Image(sharedImage, imageInfo, owner,
221 event);
222 if (image == NULL)
223 return B_NO_MEMORY;
225 if (!fImages.AddItem(image)) {
226 delete image;
227 return B_NO_MEMORY;
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);
237 return B_OK;
241 status_t
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);
247 return B_OK;
251 return B_ENTRY_NOT_FOUND;
255 Image*
256 Team::FindImage(image_id id) const
258 for (int32 i = 0; Image* image = fImages.ItemAt(i); i++) {
259 if (image->ID() == id)
260 return image;
263 return NULL;
267 void
268 Team::_RemoveImage(int32 index, int32 event)
270 Image* image = fImages.RemoveItemAt(index);
271 if (image == NULL)
272 return;
274 if (_SynchronousProfiling()) {
275 ThreadList::Iterator it = fThreads.GetIterator();
276 while (Thread* thread = it.Next())
277 thread->RemoveImage(image);
278 } else {
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
282 // image.
285 image->SetDeletionEvent(event);
286 image->ReleaseReference();