|
1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * |
|
5 * Redistribution and use in source and binary forms, with or without |
|
6 * modification, are permitted provided that the following conditions are met: |
|
7 * |
|
8 * - Redistributions of source code must retain the above copyright notice, |
|
9 * this list of conditions and the following disclaimer. |
|
10 * - Redistributions in binary form must reproduce the above copyright notice, |
|
11 * this list of conditions and the following disclaimer in the documentation |
|
12 * and/or other materials provided with the distribution. |
|
13 * - Neither the name of Nokia Corporation nor the names of its contributors |
|
14 * may be used to endorse or promote products derived from this software |
|
15 * without specific prior written permission. |
|
16 * |
|
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
|
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
27 * POSSIBILITY OF SUCH DAMAGE. |
|
28 * |
|
29 * Initial Contributors: |
|
30 * Nokia Corporation - initial contribution. |
|
31 * |
|
32 * Contributors: |
|
33 * |
|
34 * Description: |
|
35 * |
|
36 */ |
|
37 |
|
38 using System; |
|
39 using System.Text; |
|
40 using System.Text.RegularExpressions; |
|
41 using System.Threading; |
|
42 using System.Collections; |
|
43 using System.Collections.Generic; |
|
44 using SymbianUtils; |
|
45 using SymbianUtils.Range; |
|
46 using SymbianUtils.RawItems; |
|
47 using HeapLib.Cells; |
|
48 using HeapLib.Array; |
|
49 using HeapLib.Reconstructor; |
|
50 using SymbianUtils.TextUtilities.Readers.Types.Array; |
|
51 |
|
52 namespace HeapComparisonLib.Data |
|
53 { |
|
54 public class ComparsionEngine : AsyncArrayReader<HeapCell> |
|
55 { |
|
56 #region Constructors & destructor |
|
57 public ComparsionEngine( HeapReconstructor aReconstructor1, HeapReconstructor aReconstructor2 ) |
|
58 : base( new ComparsionCellSupplierProxy( aReconstructor1 ) ) |
|
59 { |
|
60 iReconstructor1 = aReconstructor1; |
|
61 iReconstructor2 = aReconstructor2; |
|
62 } |
|
63 #endregion |
|
64 |
|
65 #region API |
|
66 public void Compare() |
|
67 { |
|
68 AsyncRead(); |
|
69 } |
|
70 #endregion |
|
71 |
|
72 #region Properties |
|
73 public HeapReconstructor Reconstructor1 |
|
74 { |
|
75 get { return iReconstructor1; } |
|
76 } |
|
77 |
|
78 public HeapReconstructor Reconstructor2 |
|
79 { |
|
80 get { return iReconstructor2; } |
|
81 } |
|
82 |
|
83 public HeapCellArrayWithStatistics ResultsUnchanged |
|
84 { |
|
85 get { return iUnchanged; } |
|
86 } |
|
87 |
|
88 public HeapCellArrayWithStatistics ResultsUnchangedLengthButDifferentContents |
|
89 { |
|
90 get { return iUnchangedLengthButDifferentContents; } |
|
91 } |
|
92 |
|
93 public HeapCellArrayWithStatistics ResultsChanged |
|
94 { |
|
95 get { return iChanged; } |
|
96 } |
|
97 |
|
98 public HeapCellArrayWithStatistics ResultsUniqueInHeap1 |
|
99 { |
|
100 get { return iUniqueInReconstructor1; } |
|
101 } |
|
102 |
|
103 public HeapCellArrayWithStatistics ResultsUniqueInHeap2 |
|
104 { |
|
105 get { return iUniqueInReconstructor2; } |
|
106 } |
|
107 #endregion |
|
108 |
|
109 #region From AsyncArrayReader |
|
110 protected override void HandleObject( HeapCell aCell, int aIndex, int aCount ) |
|
111 { |
|
112 if ( aCell.Address == 0xc8023e5c || |
|
113 aCell.Address == 0xc8024064 || |
|
114 aCell.Address == 0xc80276d4 || |
|
115 aCell.Address == 0xc82100b4 |
|
116 ) |
|
117 { |
|
118 int x = 0; |
|
119 x++; |
|
120 } |
|
121 |
|
122 uint address = aCell.Address; |
|
123 HeapCell locatedCell = iReconstructor2.Data.CellByExactAddress( address ); |
|
124 // |
|
125 if ( locatedCell != null ) |
|
126 { |
|
127 System.Diagnostics.Debug.Assert( aCell.Tag == null ); |
|
128 |
|
129 // Remove sucessfully located cells from the 2nd list |
|
130 iReconstructor2.Data.Remove( locatedCell ); |
|
131 |
|
132 // Check vtables to detect if the same |
|
133 HeapCell.TType origType = aCell.Type; |
|
134 HeapCell.TType locatedType = locatedCell.Type; |
|
135 |
|
136 uint origVTable = aCell.PossibleVTableAddress; |
|
137 uint locatedVTable = locatedCell.PossibleVTableAddress; |
|
138 |
|
139 // Compare length, type and vTable |
|
140 if ( origType == locatedType ) |
|
141 { |
|
142 // Type is the same... |
|
143 if ( aCell.Length == locatedCell.Length ) |
|
144 { |
|
145 CompareCellsWithSameLengths( aCell, locatedCell ); |
|
146 } |
|
147 else |
|
148 { |
|
149 CompareCellsWithDifferentLengths( aCell, locatedCell ); |
|
150 } |
|
151 } |
|
152 else |
|
153 { |
|
154 // The cell is not of the same type, so they cannot have |
|
155 // any commonality between them. Therefore they are unique in their |
|
156 // respective heaps. |
|
157 iUniqueInReconstructor1.Add( aCell ); |
|
158 iUniqueInReconstructor2.Add( locatedCell ); |
|
159 } |
|
160 } |
|
161 else |
|
162 { |
|
163 // There wasn't any corresponding cell in the second list, so it's got to be |
|
164 // unique to the first heap |
|
165 iUniqueInReconstructor1.Add( aCell ); |
|
166 } |
|
167 } |
|
168 |
|
169 protected override void HandleReadCompleted() |
|
170 { |
|
171 try |
|
172 { |
|
173 base.HandleReadCompleted(); |
|
174 } |
|
175 finally |
|
176 { |
|
177 // Anything left behind in reconstructor 2 was unique to it. |
|
178 int count = iReconstructor2.Data.Count; |
|
179 int alreadyHave = iUniqueInReconstructor2.Count; |
|
180 foreach ( HeapCell leftover in iReconstructor2.Data ) |
|
181 { |
|
182 iUniqueInReconstructor2.Add( leftover ); |
|
183 } |
|
184 System.Diagnostics.Debug.Assert( alreadyHave + count == iUniqueInReconstructor2.Count ); |
|
185 } |
|
186 |
|
187 /* |
|
188 int unchanged = CountBySymbol( "CFsDisconnectRequest", iUnchanged ); |
|
189 int diffContents = CountBySymbol( "CFsDisconnectRequest", iUnchangedLengthButDifferentContents ); |
|
190 int changed = CountBySymbol( "CFsDisconnectRequest", iChanged ); |
|
191 int unique1 = 0;// CountBySymbol( "CFsDisconnectRequest", iUniqueInReconstructor1 ); |
|
192 int unique2 = CountBySymbol( "CFsDisconnectRequest", iUniqueInReconstructor2 ); |
|
193 |
|
194 int total = unchanged + diffContents + changed + unique1 + unique2; |
|
195 |
|
196 int x = total; |
|
197 */ |
|
198 } |
|
199 #endregion |
|
200 |
|
201 #region Internal methods |
|
202 private void CompareCellsWithSameLengths( HeapCell aFromRecon1, HeapCell aFromRecon2 ) |
|
203 { |
|
204 System.Diagnostics.Debug.Assert( aFromRecon1.Tag == null ); |
|
205 System.Diagnostics.Debug.Assert( aFromRecon1.Address == aFromRecon2.Address ); |
|
206 System.Diagnostics.Debug.Assert( aFromRecon2.Type == aFromRecon2.Type ); |
|
207 System.Diagnostics.Debug.Assert( aFromRecon1.Length == aFromRecon2.Length ); |
|
208 |
|
209 // Cells are the same, at least at face value. We also compare |
|
210 // contents to spot those that are entirely [unchanged]. |
|
211 bool equal = ( aFromRecon1.IsIdentical( aFromRecon2 ) ); |
|
212 if ( equal ) |
|
213 { |
|
214 // Absolutely identical to one another |
|
215 aFromRecon1.Tag = aFromRecon2; |
|
216 iUnchanged.Add( aFromRecon1 ); |
|
217 } |
|
218 else |
|
219 { |
|
220 // Same length, same type, but otherwise the contents are different |
|
221 // |
|
222 // If it's an allocated cell and the vTables are different, then |
|
223 // the cell is treated as [unique]. |
|
224 // |
|
225 // If it's a free cell, we don't care. |
|
226 if ( aFromRecon2.Type == HeapCell.TType.EAllocated ) |
|
227 { |
|
228 uint vt1 = aFromRecon1.IsUnknown ? 0 : aFromRecon1.PossibleVTableAddress; |
|
229 uint vt2 = aFromRecon2.IsUnknown ? 0 : aFromRecon2.PossibleVTableAddress; |
|
230 |
|
231 // If there was no associated symbol then the comparison will be zero vs |
|
232 // zero, in which case we'll still treat it as the [same length, diff content], |
|
233 // rather than unique. This might happen for blob cells, e.g. those that |
|
234 // are the payload for RArray or CBufFlat etc. |
|
235 if ( vt1 == vt2 ) |
|
236 { |
|
237 // VTables are the same, but somehow the remaining content is different. |
|
238 // Must also check whether one is a descriptor an the other isn't! |
|
239 if ( aFromRecon1.IsDescriptor != aFromRecon2.IsDescriptor ) |
|
240 { |
|
241 // One is a descriptor, the other isn't => [unique] |
|
242 iUniqueInReconstructor1.Add( aFromRecon1 ); |
|
243 iUniqueInReconstructor2.Add( aFromRecon2 ); |
|
244 } |
|
245 else |
|
246 { |
|
247 // [same length, diff content] |
|
248 aFromRecon1.Tag = aFromRecon2; |
|
249 iUnchangedLengthButDifferentContents.Add( aFromRecon1 ); |
|
250 } |
|
251 } |
|
252 else |
|
253 { |
|
254 // VTables are different, lengths and types are the same => [unique] |
|
255 iUniqueInReconstructor1.Add( aFromRecon1 ); |
|
256 iUniqueInReconstructor2.Add( aFromRecon2 ); |
|
257 } |
|
258 } |
|
259 else |
|
260 { |
|
261 // Must be a free cell, and since the length is the same we |
|
262 // really don't care => [same length, diff content] |
|
263 aFromRecon1.Tag = aFromRecon2; |
|
264 iUnchangedLengthButDifferentContents.Add( aFromRecon1 ); |
|
265 } |
|
266 } |
|
267 } |
|
268 |
|
269 private void CompareCellsWithDifferentLengths( HeapCell aFromRecon1, HeapCell aFromRecon2 ) |
|
270 { |
|
271 System.Diagnostics.Debug.Assert( aFromRecon1.Tag == null ); |
|
272 System.Diagnostics.Debug.Assert( aFromRecon1.Address == aFromRecon2.Address ); |
|
273 System.Diagnostics.Debug.Assert( aFromRecon2.Type == aFromRecon2.Type ); |
|
274 System.Diagnostics.Debug.Assert( aFromRecon1.Length != aFromRecon2.Length ); |
|
275 |
|
276 if ( aFromRecon1.Type == HeapCell.TType.EFree ) |
|
277 { |
|
278 // Free cells, same address, different lengths => [changed] |
|
279 aFromRecon1.Tag = aFromRecon2; |
|
280 iChanged.Add( aFromRecon1 ); |
|
281 } |
|
282 else if ( aFromRecon1.Type == HeapCell.TType.EAllocated ) |
|
283 { |
|
284 if ( aFromRecon1.IsUnknown && aFromRecon2.IsUnknown ) |
|
285 { |
|
286 // Check if both are descriptors. If they are not, then |
|
287 // assume unique. |
|
288 if ( aFromRecon1.IsDescriptor != aFromRecon2.IsDescriptor ) |
|
289 { |
|
290 // One is a descriptor, one isn't => [unique] |
|
291 iUniqueInReconstructor1.Add( aFromRecon1 ); |
|
292 iUniqueInReconstructor2.Add( aFromRecon2 ); |
|
293 } |
|
294 else |
|
295 { |
|
296 // Cells with unknown vTables, but at the same address are just assumed to be blobs that |
|
297 // have grown or shrunk => [changed] |
|
298 aFromRecon1.Tag = aFromRecon2; |
|
299 iChanged.Add( aFromRecon1 ); |
|
300 } |
|
301 } |
|
302 else |
|
303 { |
|
304 uint vt1 = aFromRecon1.IsUnknown ? 0 : aFromRecon1.PossibleVTableAddress; |
|
305 uint vt2 = aFromRecon2.IsUnknown ? 0 : aFromRecon2.PossibleVTableAddress; |
|
306 |
|
307 // If either vTable is different, then they are [unique]. If the vTables |
|
308 // are the same, then this is odd - classes with known vTables shouldn't change |
|
309 // size dynamically? |
|
310 if ( vt1 == vt2 ) |
|
311 { |
|
312 // VTables are the same, but somehow the length has |
|
313 // changed. I don't know what to do about this at the moment so |
|
314 // am filing the cells in the unique bucket! |
|
315 iUniqueInReconstructor1.Add( aFromRecon1 ); |
|
316 iUniqueInReconstructor2.Add( aFromRecon2 ); |
|
317 } |
|
318 else |
|
319 { |
|
320 // VTables are different, lengths not the same, types is the same => [unique] |
|
321 iUniqueInReconstructor1.Add( aFromRecon1 ); |
|
322 iUniqueInReconstructor2.Add( aFromRecon2 ); |
|
323 } |
|
324 } |
|
325 } |
|
326 } |
|
327 |
|
328 private static bool CompareCommonContents( HeapCell aLeft, HeapCell aRight ) |
|
329 { |
|
330 HeapCell smaller = aLeft; |
|
331 HeapCell larger = aRight; |
|
332 if ( aLeft.RawItems.Count > aRight.RawItems.Count ) |
|
333 { |
|
334 smaller = aRight; |
|
335 larger = aLeft; |
|
336 } |
|
337 |
|
338 // The payload length is in bytes, the raw item count is in 32 bit words. |
|
339 // They should agree, once multipled by 4 - if not, something is badly borked. |
|
340 // We should probably throw an exception, but try to be tolerant for now... |
|
341 if ( smaller.RawItems.Count * 4 != smaller.PayloadLength ) |
|
342 { |
|
343 return false; |
|
344 } |
|
345 else if ( larger.RawItems.Count * 4 != larger.PayloadLength ) |
|
346 { |
|
347 return false; |
|
348 } |
|
349 |
|
350 int smallerSize = smaller.RawItems.Count; |
|
351 for ( int i = 0; i < smallerSize; i++ ) |
|
352 { |
|
353 RawItem itemS = smaller[ i ]; |
|
354 RawItem itemL = larger[ i ]; |
|
355 // |
|
356 if ( itemS.Data != itemL.Data ) |
|
357 { |
|
358 return false; |
|
359 } |
|
360 } |
|
361 |
|
362 return true; |
|
363 } |
|
364 |
|
365 private static int CountBySymbol( string aText, HeapCellArray aArray ) |
|
366 { |
|
367 int ret = 0; |
|
368 int count = aArray.Count; |
|
369 for ( int i = 0; i < count; i++ ) |
|
370 { |
|
371 HeapCell cell = aArray[ i ]; |
|
372 string sym = cell.SymbolStringWithoutDescriptorPrefix; |
|
373 if ( sym.Contains( aText ) ) |
|
374 { |
|
375 ++ret; |
|
376 } |
|
377 } |
|
378 return ret; |
|
379 } |
|
380 #endregion |
|
381 |
|
382 #region Data members |
|
383 private readonly HeapReconstructor iReconstructor1; |
|
384 private readonly HeapReconstructor iReconstructor2; |
|
385 // |
|
386 private HeapCellArrayWithStatistics iUnchanged = new HeapCellArrayWithStatistics(); |
|
387 private HeapCellArrayWithStatistics iUnchangedLengthButDifferentContents = new HeapCellArrayWithStatistics(); |
|
388 private HeapCellArrayWithStatistics iChanged = new HeapCellArrayWithStatistics(); |
|
389 private HeapCellArrayWithStatistics iUniqueInReconstructor1 = new HeapCellArrayWithStatistics(); |
|
390 private HeapCellArrayWithStatistics iUniqueInReconstructor2 = new HeapCellArrayWithStatistics(); |
|
391 #endregion |
|
392 } |
|
393 |
|
394 internal class ComparsionCellSupplierProxy : AsyncArrayObjectSupplier<HeapCell> |
|
395 { |
|
396 #region Constructors & destructor |
|
397 public ComparsionCellSupplierProxy( HeapReconstructor aReconstructor ) |
|
398 { |
|
399 iReconstructor = aReconstructor; |
|
400 } |
|
401 #endregion |
|
402 |
|
403 #region AsyncArrayObjectSupplier<HeapCell> Members |
|
404 public int ObjectCount |
|
405 { |
|
406 get { return iReconstructor.Data.Count; } |
|
407 } |
|
408 |
|
409 public HeapCell this[ int aIndex ] |
|
410 { |
|
411 get { return iReconstructor.Data[ aIndex ]; } |
|
412 } |
|
413 #endregion |
|
414 |
|
415 #region Data members |
|
416 private readonly HeapReconstructor iReconstructor; |
|
417 #endregion |
|
418 } |
|
419 } |