Skip to content

Commit c37e029

Browse files
jonpryordellis1972
authored andcommitted
[logcat-parse] Support repeated handles. (#35)
I've come across some log files which would contain *several thousand* global references, as per the `grefc` values, but when processing via logcat-parse `grefs.AlivePeers.Count()` would invariably return `11`, or some other ludicrously low value given the input. On further investigation, a problem is with repeated handle values. Once a handle has been disposed, there's no reason why it couldn't be reused again: +g+ grefc 1 gwrefc 0 obj-handle 0x4a00009/L -> new-handle 0x19004aa/G from thread '(null)'(3) -g- grefc 0 gwrefc 0 handle 0x19004aa/G from thread '(null)'(3) # OK, created + destroyed an instance... +g+ grefc 1 gwrefc 0 obj-handle 0x4a00009/L -> new-handle 0x19004aa/G from thread '(null)'(3) # OK, created a *different* instance Unfortunately, `logcat-parse` would treat the second +g+ as if it were an alias of the originally created instance. As such, `grefs.AlivePeers.Count()` would return 0, not 1, which is wrong. To better support this, keep a separate `alive` list of peers, and only consult the "alive" list when performing handle lookups. This prevents the original -- dead! -- PeerInfo from being reused, allowing us to have (more?) accurate peer information.
1 parent a9312d2 commit c37e029

File tree

5 files changed

+74
-4
lines changed

5 files changed

+74
-4
lines changed

tools/logcat-parse/Grefs.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class Grefs {
1313
const string ThreadAndStack = @"(thread (?<thread>'[^']+'\([^)]+\)))?(?<stack>.*)$";
1414
const string AddGrefFormat = Prefix + @"\+g\+ grefc (?<gcount>\d+) gwrefc (?<wgcount>\d+) obj-handle (?<handle>0x[0-9A-Fa-f]+)/(?<handle_type>.) -> new-handle (?<ghandle>0x[0-9A-Fa-f]+)/(?<ghandle_type>.) from " + ThreadAndStack;
1515
const string AddWgrefFormat = Prefix + @"\+w\+ grefc (?<gcount>\d+) gwrefc (?<wgcount>\d+) obj-handle (?<handle>0x[0-9A-Fa-f]+)/(?<handle_type>.) -> new-handle (?<whandle>0x[0-9A-Fa-f]+)/(?<whandle_type>.) from " + ThreadAndStack;
16-
const string AtFormat = Prefix + @"(?<stack> at.*$)";
16+
const string AtFormat = Prefix + @"(?<stack>\s+at.*$)";
1717
const string DisposingFormat = Prefix + @"Disposing handle (?<handle>0x[0-9A-Fa-f]+)$";
1818
const string FinalizingFormat = Prefix + @"Finalizing (?<type>[^ ]+) handle (?<handle>0x[0-9A-Fa-f]+)$";
1919
const string HandleFormat = Prefix + @"handle (?<handle>0x[0-9A-Fa-f]+); key_handle (?<key_handle>0x[0-9A-Fa-f]+): Java Type: `(?<jtype>[^`]+)`; MCW type: `(?<mtype>.*)`$";
@@ -53,11 +53,12 @@ public static Grefs Parse (TextReader reader, int? pid = null, GrefParseOptions
5353
HashSet<JniHandleInfo> WeakRefs = new HashSet<JniHandleInfo>();
5454

5555
List<PeerInfo> allocated = new List<PeerInfo> ();
56+
List<PeerInfo> alive = new List<PeerInfo> ();
5657

5758
public GrefParseOptions ParseOptions {get; private set;}
5859
public IList<PeerInfo> AllocatedPeers {get; private set;}
5960
public IEnumerable<PeerInfo> AlivePeers {
60-
get {return allocated.Where (p => !p.Collected && !p.Disposed && !p.Finalized);}
61+
get {return alive;}
6162
}
6263

6364
public int GrefCount {
@@ -145,6 +146,7 @@ Dictionary<Regex, Action<Match, int>> CreateHandlers (int? pid)
145146
if (!WeakRefs.Any (w => p.Handles.Contains (w))) {
146147
p.Collected = true;
147148
p.DestroyedOnThread = m.Groups ["thread"].Value;
149+
alive.Remove (p);
148150
}
149151
CheckCounts (m, l);
150152

@@ -158,6 +160,7 @@ Dictionary<Regex, Action<Match, int>> CreateHandlers (int? pid)
158160
if (!GlobalRefs.Any (g => p.Handles.Contains (g))) {
159161
p.Collected = true;
160162
p.DestroyedOnThread = m.Groups ["thread"].Value;
163+
alive.Remove (p);
161164
}
162165
CheckCounts (m, l);
163166

@@ -208,9 +211,9 @@ void CheckCounts (Match m, int lineNumber)
208211
PeerInfo GetPeerInfo (Match m)
209212
{
210213
var h = GetHandle (m, "handle");
211-
var i = allocated.FindLastIndex (p => p.Handles.Contains (h));
214+
var i = alive.FindLastIndex (p => p.Handles.Contains (h));
212215
if (i >= 0)
213-
return allocated [i];
216+
return alive [i];
214217
var pid = m.Groups ["pid"].Value;
215218
var peer = new PeerInfo (pid) {
216219
CreatedOnThread = m.Groups ["thread"].Value,
@@ -219,6 +222,7 @@ PeerInfo GetPeerInfo (Match m)
219222
},
220223
};
221224
allocated.Add (peer);
225+
alive.Add (peer);
222226
return peer;
223227
}
224228
}

tools/logcat-parse/PeerInfo.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ public bool Finalized {
146146
set {state |= PeerInfoState.Finalized;}
147147
}
148148

149+
public bool Alive {
150+
get {return state == PeerInfoState.Alive;}
151+
}
152+
149153
public string JniType {get; internal set;}
150154
public string McwType {get; internal set;}
151155

tools/logcat-parse/Tests/GrefsTest.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,56 @@ public void TrackThreadInformation ()
398398
peer.GetStackTraceForHandle ("0x100492/G"));
399399
}
400400
}
401+
402+
[Test]
403+
public void RepeatedThreadHandles ()
404+
{
405+
using (var source = new StreamReader (Assembly.GetExecutingAssembly ().GetManifestResourceStream ("stdio-repeated-handles"))) {
406+
var info = Grefs.Parse (source, options: GrefParseOptions.ThrowOnCountMismatch);
407+
Assert.AreEqual (2, info.AllocatedPeers.Count);
408+
Assert.AreEqual (1, info.AlivePeers.Count ());
409+
Assert.AreEqual (1, info.GrefCount);
410+
Assert.AreEqual (0, info.WeakGrefCount);
411+
412+
var peer = info.AllocatedPeers [0];
413+
Assert.IsTrue (peer.Collected);
414+
Assert.IsTrue (peer.Disposed);
415+
Assert.IsFalse (peer.Finalized);
416+
Assert.AreEqual ("java/lang/String", peer.JniType);
417+
Assert.AreEqual ("Java.Lang.String", peer.McwType);
418+
419+
Assert.AreEqual ("'(null)'(3)", peer.CreatedOnThread);
420+
Assert.AreEqual ("'(null)'(3)", peer.DestroyedOnThread);
421+
422+
Assert.AreEqual ("0x41e29778", peer.KeyHandle);
423+
Assert.AreEqual (2, peer.Handles.Count);
424+
Assert.IsTrue (peer.Handles.Contains ("0x4a00009/L"));
425+
Assert.IsTrue (peer.Handles.Contains ("0x19004aa/G"));
426+
427+
Assert.AreEqual (
428+
" at Doesn't Matter",
429+
peer.GetStackTraceForHandle ("0x19004aa/G"));
430+
431+
peer = info.AllocatedPeers [1];
432+
Assert.IsFalse (peer.Collected);
433+
Assert.IsFalse (peer.Disposed);
434+
Assert.IsFalse (peer.Finalized);
435+
Assert.AreEqual ("java/lang/String", peer.JniType);
436+
Assert.AreEqual ("Java.Lang.String", peer.McwType);
437+
438+
Assert.AreEqual ("'(null)'(3)", peer.CreatedOnThread);
439+
Assert.AreEqual (null, peer.DestroyedOnThread);
440+
441+
Assert.AreEqual ("0x41e29778", peer.KeyHandle);
442+
Assert.AreEqual (2, peer.Handles.Count);
443+
Assert.IsTrue (peer.Handles.Contains ("0x4a00009/L"));
444+
Assert.IsTrue (peer.Handles.Contains ("0x19004aa/G"));
445+
446+
Assert.AreEqual (
447+
" at Doesn't Matter",
448+
peer.GetStackTraceForHandle ("0x19004aa/G"));
449+
}
450+
}
401451
}
402452
}
403453

tools/logcat-parse/Tests/LogcatParse-Tests.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,5 +84,8 @@
8484
<EmbeddedResource Include="Resources\stdio-Finalized-threads.txt">
8585
<LogicalName>stdio-Finalized-threads</LogicalName>
8686
</EmbeddedResource>
87+
<EmbeddedResource Include="Resources\stdio-repeated-handles.txt">
88+
<LogicalName>stdio-repeated-handles</LogicalName>
89+
</EmbeddedResource>
8790
</ItemGroup>
8891
</Project>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
+g+ grefc 1 gwrefc 0 obj-handle 0x4a00009/L -> new-handle 0x19004aa/G from thread '(null)'(3)
2+
at Doesn't Matter
3+
handle 0x19004aa; key_handle 0x41e29778: Java Type: `java/lang/String`; MCW type: `Java.Lang.String`
4+
Disposing handle 0x19004aa
5+
-g- grefc 0 gwrefc 0 handle 0x19004aa/G from thread '(null)'(3)
6+
at Doesn't Matter
7+
+g+ grefc 1 gwrefc 0 obj-handle 0x4a00009/L -> new-handle 0x19004aa/G from thread '(null)'(3)
8+
at Doesn't Matter
9+
handle 0x19004aa; key_handle 0x41e29778: Java Type: `java/lang/String`; MCW type: `Java.Lang.String`

0 commit comments

Comments
 (0)