|
1 // sampler.cpp |
|
2 // |
|
3 // Copyright (c) 1999 - 2010 Accenture. All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of the "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 // Accenture - Initial contribution |
|
11 // |
|
12 |
|
13 #include <platform.h> |
|
14 |
|
15 #include "sampler.h" |
|
16 //#include <nkern.h> |
|
17 //#include <kernel.h> |
|
18 #include <kern_priv.h> |
|
19 _LIT(KLddName,"topsampler"); |
|
20 |
|
21 const TInt KMinRate=10; |
|
22 const TInt KMaxRate=1000; |
|
23 const TInt KRawBufSize = 20000; // Enough for 20 seconds of samples - since max expected refresh rate in UI is 10s we can do everything nice and simply with one buffer |
|
24 |
|
25 class DDeviceSampler : public DLogicalDevice |
|
26 { |
|
27 public: |
|
28 DDeviceSampler(); |
|
29 virtual TInt Install(); |
|
30 virtual void GetCaps(TDes8& aDes) const; |
|
31 virtual TInt Create(DLogicalChannelBase*& aChannel); |
|
32 }; |
|
33 |
|
34 class DProfile : public DLogicalChannel |
|
35 { |
|
36 public: |
|
37 DProfile(); |
|
38 ~DProfile(); |
|
39 protected: |
|
40 virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); |
|
41 virtual void HandleMsg(TMessageBase* aMsg); |
|
42 private: |
|
43 TInt StartSampling(TInt aRate); |
|
44 TInt StopSampling(); |
|
45 TInt Reset(); |
|
46 //TInt GetErrors(TDes8* aDes); |
|
47 TInt ProcessReadRequest(); |
|
48 void Complete(TInt aResult); |
|
49 inline TBool Running() |
|
50 {return iTimer.iState!=NTimer::EIdle;} |
|
51 private: |
|
52 static void Sample(TAny*); |
|
53 void DoSample(); |
|
54 |
|
55 |
|
56 private: |
|
57 TUint32 iStartTime; |
|
58 TInt iRepeat; |
|
59 TInt iPeriod; |
|
60 DThread* iClient; |
|
61 TRequestStatus* iReqStatus; |
|
62 TDes8* iClientDes; // client des pointer |
|
63 TUint32 iBuf1[KRawBufSize]; // First word is the current position in the buffer |
|
64 TUint32 iBuf2[KRawBufSize]; // Have two buffers that we can switch between, this avoids us having to stop the sampler timer, or disable interrupts or whatever, when we want to drain the buffer |
|
65 TUint32* iCurrentBuf; // Pointer to either iBuf1 or iBuf2 |
|
66 |
|
67 struct TReport |
|
68 { |
|
69 TUint iRawBufferErrCounter; |
|
70 TUint iCodeSegErrCounter; |
|
71 TInt iReportMask; |
|
72 } iReport; |
|
73 |
|
74 NTimer iTimer; |
|
75 }; |
|
76 |
|
77 DECLARE_STANDARD_LDD() |
|
78 { |
|
79 return new DDeviceSampler; |
|
80 } |
|
81 |
|
82 DDeviceSampler::DDeviceSampler() |
|
83 // |
|
84 // Constructor |
|
85 // |
|
86 { |
|
87 //iParseMask=0; |
|
88 //iUnitsMask=0; |
|
89 iVersion=TVersion(1,0,0); |
|
90 } |
|
91 |
|
92 TInt DDeviceSampler::Install() |
|
93 // |
|
94 // Install the device driver. |
|
95 // |
|
96 { |
|
97 TInt r=SetName(&KLddName); |
|
98 return r; |
|
99 } |
|
100 |
|
101 void DDeviceSampler::GetCaps(TDes8& /*aDes*/) const |
|
102 // |
|
103 // Return the capabilities. |
|
104 // |
|
105 { |
|
106 } |
|
107 |
|
108 TInt DDeviceSampler::Create(DLogicalChannelBase*& aChannel) |
|
109 // |
|
110 // Create a channel on the device. |
|
111 // |
|
112 { |
|
113 aChannel=new DProfile; |
|
114 return aChannel?KErrNone:KErrNoMemory; |
|
115 } |
|
116 |
|
117 DProfile::DProfile() |
|
118 : iTimer(Sample,this) |
|
119 // |
|
120 // Constructor |
|
121 // |
|
122 { |
|
123 iCurrentBuf = iBuf1; |
|
124 iCurrentBuf[0] = 1; |
|
125 } |
|
126 |
|
127 DProfile::~DProfile() |
|
128 // |
|
129 // Destructor |
|
130 // |
|
131 { |
|
132 iTimer.Cancel(); |
|
133 Kern::SafeClose((DObject*&)iClient, NULL); |
|
134 } |
|
135 |
|
136 TInt DProfile::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer) |
|
137 // |
|
138 // Create the channel from the passed info. |
|
139 // |
|
140 { |
|
141 if (!Kern::QueryVersionSupported(TVersion(1,0,1),aVer)) |
|
142 return KErrNotSupported; |
|
143 |
|
144 iClient=&Kern::CurrentThread(); |
|
145 iClient->Open(); |
|
146 //Kern::SetThreadPriority(24); |
|
147 SetDfcQ(Kern::DfcQue0()); |
|
148 iMsgQ.Receive(); |
|
149 return KErrNone; |
|
150 } |
|
151 |
|
152 void DProfile::Complete(TInt aResult) |
|
153 //Completes user request |
|
154 { |
|
155 DEBUG_PROFILER(Kern::Printf("C");) |
|
156 Kern::RequestComplete(iClient,iReqStatus,aResult); |
|
157 } |
|
158 |
|
159 TInt DProfile::StartSampling(TInt aRate) |
|
160 { |
|
161 DEBUG_PROFILER(Kern::Printf("START");) |
|
162 //Activate timer |
|
163 aRate=Min(KMaxRate, Max(KMinRate, aRate)); |
|
164 iPeriod=1000/aRate; |
|
165 |
|
166 if (!Running()) |
|
167 { |
|
168 iCurrentBuf = iBuf1; |
|
169 iCurrentBuf[0] = 1; |
|
170 iTimer.OneShot(iPeriod); |
|
171 } |
|
172 |
|
173 DEBUG_PROFILER(Kern::Printf("START end");) |
|
174 return KErrNone; |
|
175 } |
|
176 |
|
177 TInt DProfile::Reset() |
|
178 { |
|
179 // |
|
180 // Resets the device. It is the first message sent by profiler application. |
|
181 // |
|
182 if (Running()) |
|
183 return KErrGeneral; |
|
184 |
|
185 DEBUG_PROFILER(Kern::Printf("RST %d", aXIPOnly);) |
|
186 |
|
187 iTimer.Cancel(); |
|
188 iPeriod=1; |
|
189 iReqStatus=NULL; |
|
190 iClientDes=NULL; |
|
191 |
|
192 iReport.iRawBufferErrCounter = 0; |
|
193 iReport.iCodeSegErrCounter = 0; |
|
194 iReport.iReportMask = 0; |
|
195 DEBUG_PROFILER(Kern::Printf("RST end");) |
|
196 return KErrNone; |
|
197 } |
|
198 |
|
199 TInt DProfile::StopSampling() |
|
200 // |
|
201 // Stops sampling |
|
202 // |
|
203 { |
|
204 DEBUG_PROFILER(Kern::Printf("STOP");) |
|
205 if (Running()) |
|
206 { |
|
207 iTimer.Cancel(); |
|
208 } |
|
209 if (iReqStatus) |
|
210 Complete(KErrNone); |
|
211 |
|
212 DEBUG_PROFILER(Kern::Printf("STOP end");) |
|
213 return KErrNone; |
|
214 } |
|
215 |
|
216 TInt DProfile::ProcessReadRequest() |
|
217 { |
|
218 // Whatever the status of the profiler, return the contents of the current sampling buffer |
|
219 DEBUG_PROFILER(Kern::Printf("READ");) |
|
220 TInt max=Kern::ThreadGetDesMaxLength(iClient, iClientDes); |
|
221 if (max<0) |
|
222 return max; |
|
223 if (max==0) |
|
224 return KErrArgument; |
|
225 |
|
226 TUint32* otherBuf = (iCurrentBuf == iBuf1 ? iBuf2 : iBuf1); |
|
227 otherBuf[0] = 1; // Reset other buf |
|
228 TUint32* bufToWrite = iCurrentBuf; |
|
229 iCurrentBuf = otherBuf; // And switch do it, so we can safely mess with bufToWrite without the sampling ISR adding more data under our feet |
|
230 TInt numSamples = bufToWrite[0] - 1; // Because bufToWrite[0] is an index and the data actually starts at index 1 |
|
231 TPtrC8 desToWrite((TUint8*)&bufToWrite[1], (numSamples)*sizeof(TUint32)); |
|
232 |
|
233 TInt r = Kern::ThreadDesWrite(iClient, iClientDes, desToWrite, 0, 0, iClient); |
|
234 return r; |
|
235 } |
|
236 |
|
237 void DProfile::HandleMsg(TMessageBase* aMsg) |
|
238 // |
|
239 // Client requests |
|
240 // |
|
241 { |
|
242 TInt r=KErrNone; |
|
243 TThreadMessage& m=*(TThreadMessage*)aMsg; |
|
244 //BEGIN TOMSCI commented out this check as it is too strict |
|
245 /* |
|
246 if (m.Client()!=iClient) |
|
247 { |
|
248 m.PanicClient(_L("SAMPLER"),EAccessDenied); |
|
249 return; |
|
250 } |
|
251 */ |
|
252 //END TOMSCI |
|
253 TInt id=m.iValue; |
|
254 if (id==(TInt)ECloseMsg) |
|
255 { |
|
256 DEBUG_PROFILER(Kern::Printf("CLOSE");) |
|
257 iTimer.Cancel(); |
|
258 m.Complete(KErrNone,EFalse); |
|
259 iMsgQ.CompleteAll(KErrServerTerminated); |
|
260 DEBUG_PROFILER(Kern::Printf("CLOSE end");) |
|
261 return; |
|
262 } |
|
263 else if (id<0) |
|
264 { |
|
265 if (id!=~RSampler::ERequestRead) |
|
266 { |
|
267 TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); |
|
268 Kern::RequestComplete(iClient,pS,KErrNotSupported); |
|
269 } |
|
270 if (iReqStatus) |
|
271 { |
|
272 m.PanicClient(_L("SAMPLER"),ERequestAlreadyPending); |
|
273 return; |
|
274 } |
|
275 iReqStatus=(TRequestStatus*)m.Ptr0(); |
|
276 iClientDes=(TDes8*)m.Ptr1(); |
|
277 TInt err = ProcessReadRequest(); |
|
278 Complete(err); |
|
279 } |
|
280 else if (id==KMaxTInt) |
|
281 { |
|
282 TInt mask=m.Int0(); |
|
283 if (mask & (1<<RSampler::ERequestRead)) |
|
284 { |
|
285 Complete(KErrCancel); |
|
286 } |
|
287 } |
|
288 else |
|
289 { |
|
290 switch(id) |
|
291 { |
|
292 case RSampler::EControlStartProfile: |
|
293 r=StartSampling(m.Int0()); |
|
294 break; |
|
295 case RSampler::EControlStopProfile: |
|
296 r=StopSampling(); |
|
297 break; |
|
298 case RSampler::EControlResetProfile: |
|
299 r=Reset(); |
|
300 break; |
|
301 //case RSampler::EControlGetErrors: |
|
302 // r=GetErrors((TDes8*)m.Ptr0()); |
|
303 // break; |
|
304 default: |
|
305 r=KErrNotSupported; |
|
306 break; |
|
307 } |
|
308 } |
|
309 m.Complete(r,ETrue); |
|
310 } |
|
311 |
|
312 void DProfile::Sample(TAny* aPtr) |
|
313 { |
|
314 DProfile& d=*(DProfile*)aPtr; |
|
315 d.DoSample(); |
|
316 } |
|
317 |
|
318 void DProfile::DoSample() |
|
319 { |
|
320 iTimer.Again(iPeriod); |
|
321 |
|
322 TUint32& currentPos = iCurrentBuf[0]; |
|
323 if (currentPos < (TUint)KRawBufSize) // space in buffer |
|
324 { |
|
325 DThread* pT=Kern::NThreadToDThread(NKern::CurrentThread()); |
|
326 if (pT!=NULL) |
|
327 { |
|
328 iCurrentBuf[currentPos] = pT->iId; |
|
329 currentPos++; |
|
330 } |
|
331 } |
|
332 else |
|
333 iReport.iRawBufferErrCounter++; |
|
334 } |