|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <piprofiler/ProfilerVersion.h> |
|
20 #include <piprofiler/ProfilerTraces.h> |
|
21 |
|
22 #include <kern_priv.h> |
|
23 #include <plat_priv.h> |
|
24 |
|
25 #include "PriSamplerImpl.h" |
|
26 |
|
27 #if !defined(__NKERN_H__) |
|
28 #include <nkern.h> |
|
29 #endif |
|
30 |
|
31 #define TAG(obj) (*(TUint32*)&(obj->iAsyncDeleteNext)) |
|
32 #define PROFILER_THREAD_MARK ((TUint32)0x00000002) |
|
33 |
|
34 |
|
35 DPriSamplerImpl::DPriSamplerImpl() : |
|
36 sampleDescriptor(&(this->sample[1]),0,256) |
|
37 { |
|
38 LOGTEXT("PriSamplerImpl::PriSamplerImpl() - konstruktori"); |
|
39 |
|
40 iCountti = 50; // sample threads 16 cycles before actual MEM and PRI sample time... |
|
41 iNewThreadCount = 0; |
|
42 iThreadCount = 0; |
|
43 iProcessing = ENothingToProcess; |
|
44 |
|
45 for(TInt i=0;i<KProfilerMaxThreadAmount;i++) |
|
46 { |
|
47 this->threadsToSample[i] = 0; |
|
48 this->threadNamesToReport[i] = 0; |
|
49 } |
|
50 |
|
51 } |
|
52 |
|
53 DPriSamplerImpl::~DPriSamplerImpl() |
|
54 { |
|
55 |
|
56 } |
|
57 |
|
58 TInt DPriSamplerImpl::CreateFirstSample() |
|
59 { |
|
60 LOGTEXT("PriSamplerImpl::CreateFirstSample - entry"); |
|
61 |
|
62 this->sampleDescriptor.Zero(); |
|
63 this->sampleDescriptor.Append(_L8("Bappea_V")); |
|
64 this->sampleDescriptor.Append(PROFILER_PRI_SAMPLER_VERSION); |
|
65 this->sampleDescriptor.Append(_L8("_PRI")); |
|
66 |
|
67 sample[0] = this->sampleDescriptor.Size(); |
|
68 |
|
69 LOGTEXT("PriSamplerImpl::CreateFirstSample - exit"); |
|
70 |
|
71 return (TInt)(sample[0]+1); |
|
72 } |
|
73 |
|
74 TBool DPriSamplerImpl::SampleNeeded() |
|
75 { |
|
76 iCountti++; |
|
77 if(iCountti % (iPriSamplingPeriod) == 0) |
|
78 { |
|
79 LOGTEXT("PriSamplerImpl::SampleNeeded - true"); |
|
80 return true; |
|
81 } |
|
82 else |
|
83 { |
|
84 return false; |
|
85 } |
|
86 } |
|
87 |
|
88 |
|
89 TInt DPriSamplerImpl::SampleImpl() |
|
90 { |
|
91 /* |
|
92 * |
|
93 * EKA-2 implementation of PRI trace |
|
94 * |
|
95 */ |
|
96 if(this->iProcessing == ENothingToProcess) |
|
97 { |
|
98 if((iCountti % iPriSamplingPeriod) != 0 ) return 0; |
|
99 |
|
100 LOGTEXT("Processing threads..."); |
|
101 |
|
102 DObjectCon& threads = *Kern::Containers()[EThread]; |
|
103 |
|
104 // PRI trace variables |
|
105 this->iThreadCount = 0; |
|
106 this->iNewThreadCount = 0; |
|
107 TInt totalThreadCount = threads.Count(); |
|
108 |
|
109 for(TInt i=0;i<totalThreadCount;i++) |
|
110 { |
|
111 DThread* t = (DThread*)(threads)[i]; |
|
112 LOGSTRING3("Processing thread %d, tag: 0x%x",i,TAG(t)); |
|
113 |
|
114 if( (TAG(t) & PROFILER_THREAD_MARK) == 0) |
|
115 { |
|
116 LOGSTRING2("Marking thread %d",i); |
|
117 // this thread's chunk has not been reported yet |
|
118 this->threadNamesToReport[iNewThreadCount] = t; |
|
119 iNewThreadCount++; |
|
120 // tag the thread |
|
121 TAG(t) |= PROFILER_THREAD_MARK; |
|
122 LOGSTRING2("New Thread %d",i); |
|
123 } |
|
124 else |
|
125 { |
|
126 LOGSTRING3("Thread %d marked already - 0x%x",i,TAG(t)); |
|
127 } |
|
128 |
|
129 // the thread has been tagged, add heap chunks to the list |
|
130 this->threadsToSample[this->iThreadCount] = t; |
|
131 this->iThreadCount++; |
|
132 LOGSTRING2("Added thread %d to threads to sample",i); |
|
133 } |
|
134 |
|
135 if(this->iThreadCount > 0 || this->iNewThreadCount > 0) |
|
136 { |
|
137 this->iProcessing = EStartingToProcess; |
|
138 |
|
139 // process the first sample |
|
140 TInt length = this->ProcessChunks(); |
|
141 |
|
142 if(length == 0) |
|
143 { |
|
144 this->iProcessing = ENothingToProcess; |
|
145 } |
|
146 |
|
147 return length; |
|
148 } |
|
149 else |
|
150 { |
|
151 // there were no threads, should not take place |
|
152 LOGTEXT("PriSamplerImpl::SampleImpl - Error, no threads"); |
|
153 return 0; |
|
154 } |
|
155 } |
|
156 else |
|
157 { |
|
158 TInt length = this->ProcessChunks(); |
|
159 if(length == 0) |
|
160 { |
|
161 this->iProcessing = ENothingToProcess; |
|
162 } |
|
163 return length; |
|
164 } |
|
165 } |
|
166 |
|
167 inline TInt DPriSamplerImpl::ProcessChunks() |
|
168 { |
|
169 /* |
|
170 * |
|
171 * EKA-2 implementation of PRI trace |
|
172 * |
|
173 */ |
|
174 |
|
175 if(iNewThreadCount > 0) |
|
176 { |
|
177 if(this->iProcessing == EStartingToProcess) |
|
178 { |
|
179 // this is the first sample, encode a code for names |
|
180 this->iProcessing = EProcessingNames; |
|
181 return EncodeNameCode(); |
|
182 } |
|
183 |
|
184 // there are new thread names to report |
|
185 iNewThreadCount--; |
|
186 DThread* t = this->threadNamesToReport[iNewThreadCount]; |
|
187 return EncodeChunkName(*t); |
|
188 } |
|
189 else if(iThreadCount > 0) |
|
190 { |
|
191 if(this->iProcessing == EProcessingNames || this->iProcessing == EStartingToProcess) |
|
192 { |
|
193 // this is the first data sample, encode a code for data |
|
194 this->iProcessing = EProcessingData; |
|
195 return EncodeDataCode(); |
|
196 } |
|
197 |
|
198 // there are no new chunks to report |
|
199 // thus generate the real report |
|
200 iThreadCount--; |
|
201 DThread* t = this->threadsToSample[iThreadCount]; |
|
202 LOGSTRING2("PriSamplerImpl::ProcessChunks - starting to process thread 0x%x",t); |
|
203 return EncodeChunkData(*t); |
|
204 } |
|
205 else |
|
206 { |
|
207 // everything is processed |
|
208 return 0; |
|
209 } |
|
210 } |
|
211 |
|
212 inline TInt DPriSamplerImpl::EncodeNameCode() |
|
213 { |
|
214 sample[0] = 1; |
|
215 sample[1] = 0xbb; // pri trace name code |
|
216 return 2; |
|
217 } |
|
218 |
|
219 inline TInt DPriSamplerImpl::EncodeDataCode() |
|
220 { |
|
221 sample[0] = 1; |
|
222 sample[1] = 0xee; // pri trace data code |
|
223 return 2; |
|
224 } |
|
225 |
|
226 |
|
227 inline TInt DPriSamplerImpl::EncodeChunkName(DThread& t) |
|
228 { |
|
229 // the size of the following name is in the first byte |
|
230 TUint8* size = &sample[0]; |
|
231 *size = 0; |
|
232 this->sampleDescriptor.Zero(); |
|
233 |
|
234 t.TraceAppendFullName(this->sampleDescriptor,false); |
|
235 *size += this->sampleDescriptor.Size(); |
|
236 |
|
237 // copy the 4 bytes from the thread id field |
|
238 this->sampleDescriptor.Append((TUint8*)&(t.iId),sizeof(TUint)); |
|
239 *size += sizeof(TUint); |
|
240 |
|
241 // the size is the descriptor length + the size field |
|
242 LOGSTRING2("Name size - %d",*size); |
|
243 return ((TInt)(*size))+1; |
|
244 } |
|
245 |
|
246 |
|
247 inline TInt DPriSamplerImpl::EncodeChunkData(DThread& t) |
|
248 { |
|
249 LOGTEXT("PriSamplerImpl::EncodeChunkData - entry"); |
|
250 LOGSTRING2("PriSamplerImpl::EncodeChunkData - processing thread 0x%x ",&t); |
|
251 |
|
252 // the size of the following name is in the first byte |
|
253 TUint8* size = &sample[0]; |
|
254 *size = 0; |
|
255 this->sampleDescriptor.Zero(); |
|
256 |
|
257 LOGTEXT("PriSamplerImpl::EncodeChunkData - cleared"); |
|
258 |
|
259 // append the thread id |
|
260 this->sampleDescriptor.Append((TUint8*)&(t.iId),sizeof(TUint)); |
|
261 *size += sizeof(TUint); |
|
262 |
|
263 // NKern::LockSystem(); |
|
264 // TInt priority(-1); |
|
265 // if(&t && t.Open()== KErrNone) |
|
266 // { |
|
267 // priority = t.iDefaultPriority; |
|
268 // } |
|
269 // NKern::UnlockSystem(); |
|
270 |
|
271 // append the priority of the nanokernel fast semaphore |
|
272 // this->sampleDescriptor.Append((TUint8*)&priority,sizeof(TUint8)); |
|
273 // append the priority of the nanokernel fast semaphore |
|
274 this->sampleDescriptor.Append((TUint8*)&(t.iNThread.iPriority),sizeof(TUint8)); |
|
275 // add space because EKA-1 implementation needs it |
|
276 this->sampleDescriptor.Append((TUint8)0x0); |
|
277 *size += 2*sizeof(TUint8); |
|
278 |
|
279 LOGTEXT("PriSamplerImpl::EncodeChunkData - appended priority"); |
|
280 |
|
281 |
|
282 LOGSTRING2("Data size - %d",*size); |
|
283 return ((TInt)(*size))+1; |
|
284 } |
|
285 |
|
286 |
|
287 void DPriSamplerImpl::Reset() |
|
288 { |
|
289 /* |
|
290 * |
|
291 * EKA-2 implementation of PRI trace |
|
292 * |
|
293 */ |
|
294 |
|
295 LOGTEXT("PriSamplerImpl::Reset"); |
|
296 iCountti = 50; // sample threads 16 cycles before actual MEM and PRI sample time... |
|
297 this->iThreadCount = 0; |
|
298 this->iNewThreadCount = 0; |
|
299 this->iProcessing = ENothingToProcess; |
|
300 this->sampleDescriptor.Zero(); |
|
301 |
|
302 |
|
303 // clear all thread tags |
|
304 DObjectCon* threads = Kern::Containers()[EThread]; |
|
305 TInt totalThreadCount = threads->Count(); |
|
306 for(TInt i=0;i<totalThreadCount;i++) |
|
307 { |
|
308 DThread* t = (DThread*)(*threads)[i]; |
|
309 TAG(t) = (TAG(t) & 0xfffffffd); |
|
310 } |
|
311 } |
|
312 |