-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds two flags that allows PMI to output inlining and tail-call decisions to stdout.
- Loading branch information
1 parent
9542bbd
commit 589d838
Showing
8 changed files
with
242 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# jit-decisions-analyze - Managed JIT decisions analysis tool |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
|
||
namespace jit_decisions_analyze | ||
{ | ||
internal class Program | ||
{ | ||
private static void Main(string[] args) | ||
{ | ||
List<Event> events = new List<Event>(); | ||
int malformed = 0; | ||
static void WriteProgress(double pct) | ||
{ | ||
Console.CursorLeft = 0; | ||
Console.Write("{0:F2}% done", pct); | ||
} | ||
|
||
using (var sr = new StreamReader(File.OpenRead(args[0]))) | ||
{ | ||
int lines = 0; | ||
string line; | ||
while ((line = sr.ReadLine()) != null) | ||
{ | ||
if (!line.StartsWith("JITTracing: ")) | ||
continue; | ||
|
||
line = line.Substring("JITTracing: ".Length); | ||
Event evt = ToEvent(line); | ||
if (evt != null) | ||
events.Add(evt); | ||
else | ||
malformed++; | ||
|
||
if (lines++ % 10000 == 0) | ||
WriteProgress(sr.BaseStream.Position / (double)sr.BaseStream.Length * 100); | ||
} | ||
} | ||
|
||
WriteProgress(100); | ||
Console.WriteLine(); | ||
|
||
Console.WriteLine("{0} total well-formed events ({1} filtered away because they were malformed)", events.Count, malformed); | ||
List<TailCallEvent> tailCalls = events.OfType<TailCallEvent>().ToList(); | ||
WriteInfo("Implicit", tailCalls.Where(t => !t.TailPrefix)); | ||
WriteInfo("Explicit", tailCalls.Where(t => t.TailPrefix)); | ||
WriteInfo("Inlining", events.OfType<InliningEvent>()); | ||
} | ||
|
||
private static Event ToEvent(string l) | ||
{ | ||
string[] data = l.Split("@!@!@"); | ||
if (data.Length % 2 == 0) | ||
return null; | ||
|
||
Dictionary<string, string> payload = new Dictionary<string, string>(); | ||
for (int i = 1; i < data.Length; i += 2) | ||
payload.Add(data[i], data[i + 1]); | ||
|
||
string tailPrefix; | ||
string failReason; | ||
switch (data[0]) | ||
{ | ||
case "MethodJitTailCallSucceeded": | ||
tailPrefix = payload.GetValueOrDefault("TailPrefix"); | ||
if (tailPrefix == null) | ||
return null; | ||
|
||
return new TailCallSucceededEvent { TailPrefix = tailPrefix == "True" }; | ||
case "MethodJitTailCallFailed": | ||
tailPrefix = payload.GetValueOrDefault("TailPrefix"); | ||
failReason = payload.GetValueOrDefault("FailReason"); | ||
if (failReason == null || tailPrefix == null) | ||
return null; | ||
|
||
return new TailCallFailedEvent { FailReason = failReason, TailPrefix = tailPrefix == "True" }; | ||
case "MethodJitInliningSucceeded": | ||
return new InliningSucceededEvent(); | ||
case "MethodJitInliningFailed": | ||
failReason = payload.GetValueOrDefault("FailReason"); | ||
if (failReason == null) | ||
return null; | ||
|
||
return new InliningFailedEvent { FailReason = failReason }; | ||
default: | ||
return null; | ||
} | ||
} | ||
|
||
private static void WriteInfo(string name, IEnumerable<Event> events) | ||
{ | ||
List<Event> list = events.ToList(); | ||
int sites = list.Count; | ||
int sitesSuccessful = list.Count(IsSuccessEvent); | ||
Console.WriteLine("{0} call sites: {1}/{2} converted", name, sitesSuccessful, sites); | ||
if (sites == 0) | ||
return; | ||
|
||
string GetInfoString(Event e) | ||
{ | ||
switch (e) | ||
{ | ||
case TailCallSucceededEvent f: return "Successfully converted"; | ||
case InliningSucceededEvent f: return "Successfully converted"; | ||
case TailCallFailedEvent f: return f.FailReason; | ||
case InliningFailedEvent f: return f.FailReason; | ||
default: throw new ArgumentException("No fail reason on event"); | ||
} | ||
} | ||
|
||
var groupedFailures = list.GroupBy(GetInfoString).OrderByDescending(g => g.Count()); | ||
foreach (var g in groupedFailures) | ||
Console.WriteLine("[{0:00.00}%] {1}", g.Count() / (double)sites * 100, g.Key); | ||
|
||
Console.WriteLine(); | ||
} | ||
|
||
private static bool IsSuccessEvent(Event e) => e is TailCallSucceededEvent || e is InliningSucceededEvent; | ||
} | ||
|
||
internal abstract class Event | ||
{ | ||
} | ||
|
||
internal abstract class TailCallEvent : Event | ||
{ | ||
public bool TailPrefix { get; set; } | ||
} | ||
|
||
internal class TailCallSucceededEvent : TailCallEvent | ||
{ | ||
} | ||
|
||
internal class TailCallFailedEvent : TailCallEvent | ||
{ | ||
public string FailReason { get; set; } | ||
} | ||
|
||
internal abstract class InliningEvent : Event | ||
{ | ||
} | ||
|
||
internal class InliningSucceededEvent : InliningEvent | ||
{ | ||
} | ||
|
||
internal class InliningFailedEvent : InliningEvent | ||
{ | ||
public string FailReason { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<Import Project="$([MSBuild]::GetPathOfFileAbove(target-framework.props))" /> | ||
<Import Project="$([MSBuild]::GetPathOfFileAbove(jit-include.props))" /> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<Compile Include="..\util\util.cs" Link="util.cs" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics.Tracing; | ||
|
||
namespace pmi | ||
{ | ||
internal class JITDecisionEventListener : EventListener | ||
{ | ||
// We cannot use a parameter to this event listener because | ||
// EventListener constructor calls OnEventWritten, which will happen | ||
// before we have been able to run our own constructor. | ||
internal static readonly HashSet<string> s_enabledEvents = new HashSet<string>(); | ||
|
||
protected override void OnEventSourceCreated(EventSource eventSource) | ||
{ | ||
if (eventSource.Name != "Microsoft-Windows-DotNETRuntime") | ||
return; | ||
|
||
EventKeywords jitTracing = (EventKeywords)0x1000; // JITTracing | ||
EnableEvents(eventSource, EventLevel.Verbose, jitTracing); | ||
} | ||
|
||
protected override void OnEventWritten(EventWrittenEventArgs data) | ||
{ | ||
if (!s_enabledEvents.Contains(data.EventName)) | ||
return; | ||
|
||
List<string> dataStrings = new List<string> { data.EventName }; | ||
|
||
for (int i = 0; i < data.Payload.Count; i++) | ||
{ | ||
dataStrings.Add(data.PayloadNames[i]); | ||
dataStrings.Add(data.Payload[i] != null ? data.Payload[i].ToString() : ""); | ||
} | ||
|
||
// Log payload separated by @!@!@. This is somewhat ugly, but easy enough to parse | ||
// and avoids pulling in a dependency here. | ||
Console.WriteLine("JITTracing: {0}", string.Join("@!@!@", dataStrings)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters