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 #include "MemSpyDriverHeapWalker.h" |
|
19 |
|
20 // User includes |
|
21 #include "MemSpyDriverUtils.h" |
|
22 |
|
23 // Defines |
|
24 #define PRINTDEBUG( a ) { if ( PrintDebug() ) a; } |
|
25 |
|
26 |
|
27 RMemSpyDriverHeapWalker::RMemSpyDriverHeapWalker(RMemSpyDriverRHeapBase& aHeap, MMemSpyHeapWalkerObserver* aObserver) |
|
28 : iHeap(aHeap), iPrintDebug(EFalse), iObserver(aObserver) |
|
29 { |
|
30 InitialiseStats(); |
|
31 } |
|
32 |
|
33 |
|
34 TInt RMemSpyDriverHeapWalker::Traverse() |
|
35 // |
|
36 // Walk the heap calling the info function. |
|
37 // |
|
38 { |
|
39 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - START")); |
|
40 InitialiseStats(); |
|
41 if ( iObserver ) |
|
42 { |
|
43 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - heap walk init..." )); |
|
44 iObserver->HandleHeapWalkInit(); |
|
45 } |
|
46 |
|
47 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - heap walk init complete" )); |
|
48 |
|
49 TInt err = iHeap.Helper()->Walk(&CellCallback, this); |
|
50 FinaliseStats(); |
|
51 //PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - END - pF: 0x%08x, pC: 0x%08x, heapBase: 0x%08x, heapTop: 0x%08x", pF, pC, heapBase, heapTop)); |
|
52 return err; |
|
53 } |
|
54 |
|
55 TBool RMemSpyDriverHeapWalker::CellCallback(RAllocatorHelper& aHelper, TAny* aContext, RAllocatorHelper::TExtendedCellType aCellType, TLinAddr aCellAddress, TInt aLength) |
|
56 { |
|
57 return static_cast<RMemSpyDriverHeapWalker*>(aContext)->DoCellCallback(aHelper, aCellType, aCellAddress, aLength); |
|
58 } |
|
59 |
|
60 TBool RMemSpyDriverHeapWalker::DoCellCallback(RAllocatorHelper& aHelper, RAllocatorHelper::TExtendedCellType aCellType, TLinAddr aCellAddress, TInt aLength) |
|
61 { |
|
62 TAny* cellAddress = (TAny*)aCellAddress; |
|
63 TMemSpyDriverCellType memspyCellType = (TMemSpyDriverCellType)aCellType; // We make sure these use the same values |
|
64 switch (aCellType) |
|
65 { |
|
66 case RAllocatorHelper::EHeapBadFreeCellAddress: |
|
67 PRINTDEBUG(Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EBadFreeCellAddress: 0x%08x", cellAddress)); |
|
68 NotifyCell(memspyCellType, cellAddress, 0); |
|
69 return EFalse; |
|
70 case RAllocatorHelper::EHeapBadFreeCellSize: |
|
71 PRINTDEBUG(Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EBadFreeCellSize: 0x%08x", cellAddress)); |
|
72 NotifyCell(memspyCellType, cellAddress, aLength); |
|
73 return EFalse; |
|
74 case RAllocatorHelper::EHeapBadAllocatedCellSize: |
|
75 PRINTDEBUG(Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EBadAllocatedCellSize: 0x%08x", cellAddress)); |
|
76 NotifyCell(memspyCellType, cellAddress, aLength); |
|
77 return EFalse; |
|
78 case RAllocatorHelper::EHeapBadAllocatedCellAddress: |
|
79 PRINTDEBUG(Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EBadAllocatedCellAddress: 0x%08x", cellAddress)); |
|
80 NotifyCell(memspyCellType, cellAddress, aLength); |
|
81 return EFalse; |
|
82 default: |
|
83 break; |
|
84 } |
|
85 |
|
86 if (aCellType & RAllocatorHelper::EAllocationMask) |
|
87 { |
|
88 PRINTDEBUG(Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EGoodAllocatedCell: 0x%08x", cellAddress)); |
|
89 TInt nestingLevel = -1; |
|
90 aHelper.GetCellNestingLevel(cellAddress, nestingLevel); |
|
91 TInt allocCount = aHelper.AllocCountForCell(cellAddress); |
|
92 if (allocCount < 0) allocCount = -1; // This is what NotifyCell expects |
|
93 return NotifyCell(memspyCellType, cellAddress, aLength, nestingLevel, allocCount); |
|
94 } |
|
95 else if (aCellType & RAllocatorHelper::EFreeMask) |
|
96 { |
|
97 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EGoodFreeCell: 0x%08x", cellAddress)); |
|
98 return NotifyCell(memspyCellType, cellAddress, aLength); |
|
99 } |
|
100 else if (aCellType & RAllocatorHelper::EBadnessMask) |
|
101 { |
|
102 NotifyCell(memspyCellType, cellAddress, aLength); |
|
103 return EFalse; |
|
104 } |
|
105 return ETrue; // For any new types that get added |
|
106 } |
|
107 |
|
108 |
|
109 void RMemSpyDriverHeapWalker::CopyStatsTo( TMemSpyHeapStatisticsRHeap& aStats ) |
|
110 { |
|
111 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::CopyStatsTo() - START")); |
|
112 |
|
113 // Copy free cell info |
|
114 TMemSpyHeapStatisticsRHeapFree& free = aStats.StatsFree(); |
|
115 free.SetTypeCount( iStats.iFreeCellCount ); |
|
116 free.SetTypeSize( iStats.iTotalFreeSpace ); |
|
117 |
|
118 // If the last cell was a free cell, and it was also the largest cell |
|
119 // then we use the prior largest free cell instead. This is because |
|
120 // slack space is already reported separately. |
|
121 TAny* largestFreeCellAddress = (TAny*) iStats.iLargestCellAddressFree; |
|
122 TUint largestFreeCellSize = iStats.iLargestCellSizeFree; |
|
123 if ( iStats.iLastCellWasFreeCell && iStats.iLargestCellSizeFree == iStats.iSlackSpace && iStats.iSpackSpaceCellAddress == iStats.iLargestCellAddressFree ) |
|
124 { |
|
125 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::CopyStatsTo() - using previous max free cell stats, since largest free cell is slack cell at end of heap...")); |
|
126 largestFreeCellAddress = (TAny*) iStats.iLargestCellAddressFreePrevious; |
|
127 largestFreeCellSize = iStats.iLargestCellSizeFreePrevious; |
|
128 } |
|
129 |
|
130 free.SetLargestCellAddress( largestFreeCellAddress ); |
|
131 free.SetLargestCellSize( largestFreeCellSize ); |
|
132 free.SetSlackSpaceCellSize( iStats.iSlackSpace ); |
|
133 free.SetSlackSpaceCellAddress( (TAny*) iStats.iSpackSpaceCellAddress ); |
|
134 free.SetChecksum( iStats.iFreeCellCRC ); |
|
135 |
|
136 // Copy allocated cell info |
|
137 TMemSpyHeapStatisticsRHeapAllocated& alloc = aStats.StatsAllocated(); |
|
138 alloc.SetTypeCount( iStats.iAllocCellCount ); |
|
139 alloc.SetTypeSize( iStats.iTotalAllocSpace ); |
|
140 alloc.SetLargestCellAddress( (TAny*) iStats.iLargestCellAddressAlloc ); |
|
141 alloc.SetLargestCellSize( iStats.iLargestCellSizeAlloc ); |
|
142 |
|
143 aStats.iCommittedFreeSpace = iHeap.Helper()->CommittedFreeSpace(); |
|
144 |
|
145 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::CopyStatsTo() - END")); |
|
146 } |
|
147 |
|
148 |
|
149 void RMemSpyDriverHeapWalker::SetObserver( MMemSpyHeapWalkerObserver* aObserver ) |
|
150 { |
|
151 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::SetObserver() - aObserver: 0x%08x", aObserver )); |
|
152 iObserver = aObserver; |
|
153 } |
|
154 |
|
155 TBool RMemSpyDriverHeapWalker::NotifyCell( TMemSpyDriverCellType aType, TAny* aCellAddress, TInt aLength, TInt aNestingLevel, TInt aAllocNumber ) |
|
156 { |
|
157 // Update stats first |
|
158 UpdateStats( aType, aCellAddress, aLength, aNestingLevel, aAllocNumber ); |
|
159 |
|
160 // Notify observer |
|
161 TBool continueTraversal = ETrue; |
|
162 if ( iObserver ) |
|
163 { |
|
164 continueTraversal = iObserver->HandleHeapCell( aType, aCellAddress, aLength, aNestingLevel, aAllocNumber ); |
|
165 } |
|
166 // |
|
167 return continueTraversal; |
|
168 } |
|
169 |
|
170 |
|
171 void RMemSpyDriverHeapWalker::UpdateStats( TMemSpyDriverCellType aCellType, TAny* aCellAddress, TInt aLength, TInt aNestingLevel, TInt aAllocNumber ) |
|
172 { |
|
173 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::UpdateStats - type: %d address: 0x%08x, len: %8d, nestingLev: %8d, allocNum: %8d", aCellType, aCellAddress, aLength, aNestingLevel, aAllocNumber )); |
|
174 |
|
175 if (aCellType & EMemSpyDriverFreeCellMask) |
|
176 { |
|
177 // Update checksum |
|
178 iStats.iFreeCellCRC = iStats.iFreeCellCRC ^ reinterpret_cast<TUint32>( aCellAddress ); |
|
179 |
|
180 // Track cell counts and length |
|
181 ++iStats.iFreeCellCount; |
|
182 iStats.iTotalFreeSpace += aLength; |
|
183 iStats.iLastFreeCellLength = aLength; |
|
184 |
|
185 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::UpdateStats - WAS FREE CELL - iFreeCellCRC: 0x%08x, iFreeCellCount: %d, iTotalFreeSpace: %d, iLastFreeCellLength: %d", iStats.iFreeCellCRC, iStats.iFreeCellCount, iStats.iTotalFreeSpace, iStats.iLastFreeCellLength)); |
|
186 |
|
187 // Identify biggest cell |
|
188 if ( (TUint) aLength > iStats.iLargestCellSizeFree ) |
|
189 { |
|
190 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::UpdateStats - this cell (%d bytes big) is bigger than previous largested FREE cell (%d bytes) => making it the new largest FREE cell", aLength, iStats.iLargestCellSizeFree)); |
|
191 iStats.iLargestCellSizeFreePrevious = iStats.iLargestCellSizeFree; |
|
192 iStats.iLargestCellSizeFree = aLength; |
|
193 iStats.iLargestCellAddressFreePrevious = iStats.iLargestCellAddressFree; |
|
194 iStats.iLargestCellAddressFree = (TLinAddr) aCellAddress; |
|
195 } |
|
196 |
|
197 // Identify first cell |
|
198 if ( iStats.iFirstFreeCellAddress == 0 ) |
|
199 { |
|
200 iStats.iFirstFreeCellLength = aLength; |
|
201 iStats.iFirstFreeCellAddress = (TLinAddr) aCellAddress; |
|
202 } |
|
203 } |
|
204 else if (aCellType & EMemSpyDriverAllocatedCellMask) |
|
205 { |
|
206 // Track cell counts and length |
|
207 ++iStats.iAllocCellCount; |
|
208 iStats.iTotalAllocSpace += aLength; |
|
209 iStats.iLastFreeCellLength = 0; |
|
210 |
|
211 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::UpdateStats - WAS ALLOC CELL - iAllocCellCount: %d, iTotalAllocSpace: %d", iStats.iAllocCellCount, iStats.iTotalAllocSpace)); |
|
212 |
|
213 // Identify biggest cell |
|
214 if ( (TUint) aLength > iStats.iLargestCellSizeAlloc ) |
|
215 { |
|
216 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::UpdateStats - this cell (%d bytes big) is bigger than previous largested ALLOC cell (%d bytes) => making it the new largest ALLOC cell", aLength, iStats.iLargestCellSizeAlloc)); |
|
217 iStats.iLargestCellSizeAlloc = aLength; |
|
218 iStats.iLargestCellAddressAlloc = (TLinAddr) aCellAddress; |
|
219 } |
|
220 } |
|
221 |
|
222 iStats.iLastCellType = aCellType; |
|
223 iStats.iLastCellAddress = (TLinAddr) aCellAddress; |
|
224 iStats.iLastCellWasFreeCell = (aCellType & EMemSpyDriverFreeCellMask); |
|
225 ++iStats.iNumberOfWalkedCells; |
|
226 } |
|
227 |
|
228 |
|
229 void RMemSpyDriverHeapWalker::InitialiseStats() |
|
230 { |
|
231 iStats.iFreeCellCRC = 0; |
|
232 iStats.iNumberOfWalkedCells = 0; |
|
233 iStats.iFirstFreeCellAddress = 0; |
|
234 iStats.iFirstFreeCellLength = 0; |
|
235 iStats.iLastCellType = EMemSpyDriverAllocatedCellMask; |
|
236 iStats.iLastCellWasFreeCell = EFalse; |
|
237 iStats.iLastFreeCellLength = 0; |
|
238 iStats.iTotalFreeSpace = 0; |
|
239 iStats.iTotalAllocSpace = 0; |
|
240 iStats.iSlackSpace = 0; |
|
241 iStats.iFreeCellCount = 0; |
|
242 iStats.iAllocCellCount = 0; |
|
243 iStats.iLargestCellSizeFree = 0; |
|
244 iStats.iLargestCellSizeAlloc = 0; |
|
245 iStats.iLargestCellAddressFree = 0; |
|
246 iStats.iLargestCellAddressAlloc = 0; |
|
247 iStats.iLargestCellSizeFreePrevious = 0; |
|
248 iStats.iLargestCellAddressFreePrevious = 0; |
|
249 iStats.iSpackSpaceCellAddress = 0; |
|
250 iStats.iLastCellAddress = 0; |
|
251 } |
|
252 |
|
253 |
|
254 void RMemSpyDriverHeapWalker::FinaliseStats() |
|
255 { |
|
256 if ( iStats.iLastCellWasFreeCell ) |
|
257 { |
|
258 iStats.iSlackSpace = iStats.iLastFreeCellLength; |
|
259 iStats.iSpackSpaceCellAddress = iStats.iLastCellAddress; |
|
260 } |
|
261 |
|
262 PrintStats(); |
|
263 } |
|
264 |
|
265 |
|
266 void RMemSpyDriverHeapWalker::PrintStats() |
|
267 { |
|
268 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - HEAP SUMMARY FOR THREAD:" ) ); |
|
269 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - ------------------------------------------------------------" ) ); |
|
270 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iNumberOfWalkedCells : %10d", iStats.iNumberOfWalkedCells ) ); |
|
271 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iFirstFreeCellAddress : 0x%08x", iStats.iFirstFreeCellAddress ) ); |
|
272 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iFirstFreeCellLength : %10d", iStats.iFirstFreeCellLength ) ); |
|
273 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iLastCellWasFreeCell : %10d", iStats.iLastCellWasFreeCell ) ); |
|
274 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iLastCellType : %10d", iStats.iLastCellType ) ); |
|
275 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iLastFreeCellLength : %10d", iStats.iLastFreeCellLength ) ); |
|
276 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iTotalFreeSpace : %10d", iStats.iTotalFreeSpace ) ); |
|
277 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iTotalAllocSpace : %10d", iStats.iTotalAllocSpace ) ); |
|
278 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iSlackSpace : %10d", iStats.iSlackSpace ) ); |
|
279 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iFreeCellCount : %10d", iStats.iFreeCellCount ) ); |
|
280 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iAllocCellCount : %10d", iStats.iAllocCellCount ) ); |
|
281 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iLargestCellSizeFree : %10d", iStats.iLargestCellSizeFree ) ); |
|
282 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iLastFreeCellLength : %10d", iStats.iLastFreeCellLength ) ); |
|
283 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iLargestCellSizeAlloc : %10d", iStats.iLargestCellSizeAlloc ) ); |
|
284 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iLargestCellAddressFree : 0x%08x", iStats.iLargestCellAddressFree ) ); |
|
285 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iLargestCellAddressAlloc : 0x%08x", iStats.iLargestCellAddressAlloc ) ); |
|
286 PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iFreeCellCRC : 0x%08x", iStats.iFreeCellCRC ) ); |
|
287 } |
|