Skip to content

Commit cecda47

Browse files
radekdoulikmarek-safar
authored andcommitted
[aprofutil] Add -p and -f options
-p PORT allows easier retrieval of AOT profile from the application running with aot profiler, using the socket connection on local PORT -f instructs the tool to try setup adb port forwarding to/from Android device or emulator Example usage, retrieve the AOT profile from Android: > mono aprofutil.exe -s -v -f -p 9998 -o my.aprof Calling 'adb forward tcp:9998 tcp:9998'... Reading from '127.0.0.1:9998'... Read total 94903 bytes... Summary: Modules: 6 Types: 262 Methods: 1,162 Going to write the profile to 'my.aprof'
1 parent 824cc12 commit cecda47

File tree

1 file changed

+85
-18
lines changed

1 file changed

+85
-18
lines changed

mcs/tools/aprofutil/Program.cs

Lines changed: 85 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.IO;
4+
using System.Net.Sockets;
45
using System.Text.RegularExpressions;
56
using Mono.Options;
67
using Mono.Profiler.Aot;
@@ -11,6 +12,7 @@ namespace aotprofiletool {
1112
class MainClass {
1213
static readonly string Name = "aotprofile-tool";
1314

15+
static bool AdbForward;
1416
static bool Methods;
1517
static bool Modules;
1618
static bool Summary;
@@ -23,6 +25,8 @@ class MainClass {
2325

2426
static string Output;
2527

28+
static int Port = -1;
29+
2630
static string ProcessArguments (string [] args)
2731
{
2832
var help = false;
@@ -43,21 +47,27 @@ static string ProcessArguments (string [] args)
4347
{ "d|modules",
4448
"Show modules in the profile",
4549
v => Modules = true },
50+
{ "f|adb-forward",
51+
"Set adb socket forwarding for Android",
52+
v => AdbForward = true },
4653
{ "filter-method=",
47-
"Filter by method with regex VALUE",
54+
"Filter by method with regex {VALUE}",
4855
v => FilterMethod = new Regex (v) },
4956
{ "filter-module=",
50-
"Filter by module with regex VALUE",
57+
"Filter by module with regex {VALUE}",
5158
v => FilterModule = new Regex (v) },
5259
{ "filter-type=",
53-
"Filter by type with regex VALUE",
60+
"Filter by type with regex {VALUE}",
5461
v => FilterType = new Regex (v) },
5562
{ "m|methods",
5663
"Show methods in the profile",
5764
v => Methods = true },
5865
{ "o|output=",
59-
"Write profile to OUTPUT file",
66+
"Write profile to {OUTPUT} file",
6067
v => Output = v },
68+
{ "p|port=",
69+
"Read profile from aot profiler using local connection on {PORT}",
70+
v => int.TryParse (v, out Port) },
6171
{ "s|summary",
6272
"Show summary of the profile",
6373
v => Summary = true },
@@ -79,35 +89,92 @@ static string ProcessArguments (string [] args)
7989
Environment.Exit (0);
8090
}
8191

82-
if (remaining.Count != 1) {
83-
Error ("Please specify one <aotprofile-file> to process.");
92+
if (remaining.Count != 1 && Port < 0) {
93+
Error ("Please specify one <aotprofile-file> to process or network PORT with -p.");
8494
Environment.Exit (2);
8595
}
8696

87-
return remaining [0];
97+
return remaining.Count > 0 ? remaining [0] : null;
8898
}
8999

90-
public static void Main (string [] args)
100+
static ProfileData ReadProfileFromPort (ProfileReader reader)
91101
{
92-
var path = ProcessArguments (args);
102+
ProfileData pd;
93103

94-
if (!File.Exists (path)) {
95-
Error ($"'{path}' doesn't exist.");
96-
Environment.Exit (3);
104+
if (AdbForward) {
105+
var cmdArgs = $"forward tcp:{Port} tcp:{Port}";
106+
if (Verbose)
107+
ColorWriteLine ($"Calling 'adb {cmdArgs}'...", ConsoleColor.Yellow);
108+
109+
System.Diagnostics.Process.Start ("adb", cmdArgs);
110+
}
111+
112+
using (var client = new TcpClient ("127.0.0.1", Port)) {
113+
using (var stream = client.GetStream ()) {
114+
var msgData = System.Text.Encoding.ASCII.GetBytes ("save\n");
115+
116+
stream.Write (msgData, 0, msgData.Length);
117+
118+
if (Verbose)
119+
ColorWriteLine ($"Reading from '127.0.0.1:{Port}'...", ConsoleColor.Yellow);
120+
121+
using (var memoryStream = new MemoryStream (128 * 1024)) {
122+
var data = new byte [4 * 1024];
123+
int len;
124+
125+
while ((len = stream.Read (data, 0, data.Length)) > 0) {
126+
memoryStream.Write (data, 0, len);
127+
128+
if (Verbose)
129+
ColorWrite ($"Read {len} bytes...\r", ConsoleColor.Yellow);
130+
}
131+
132+
if (Verbose)
133+
ColorWriteLine ($"Read total {memoryStream.Length} bytes...", ConsoleColor.Yellow);
134+
135+
memoryStream.Seek (0, SeekOrigin.Begin);
136+
137+
pd = reader.ReadAllData (memoryStream);
138+
}
139+
}
97140
}
98141

142+
return pd;
143+
}
144+
145+
public static void Main (string [] args)
146+
{
147+
var path = ProcessArguments (args);
148+
99149
if (args.Length == 1) {
100150
Modules = Types = Methods = true;
101151
}
102152

103153
var reader = new ProfileReader ();
104-
ProfileData pd;
105-
106-
using (var stream = new FileStream (path, FileMode.Open)) {
107-
if (Verbose)
108-
ColorWriteLine ($"Reading '{path}'...", ConsoleColor.Yellow);
154+
ProfileData pd = null;
155+
156+
if (path == null) {
157+
if (Port < 0) {
158+
Error ($"You should specify path or -p PORT to read the profile.");
159+
Environment.Exit (4);
160+
} else {
161+
try {
162+
pd = ReadProfileFromPort (reader);
163+
} catch (Exception e) {
164+
Error ($"Unable to read profile through local port: {Port}.\n{e}");
165+
Environment.Exit (5);
166+
}
167+
}
168+
} else if (!File.Exists (path)) {
169+
Error ($"'{path}' doesn't exist.");
170+
Environment.Exit (3);
171+
} else {
172+
using (var stream = new FileStream (path, FileMode.Open)) {
173+
if (Verbose)
174+
ColorWriteLine ($"Reading '{path}'...", ConsoleColor.Yellow);
109175

110-
pd = reader.ReadAllData (stream);
176+
pd = reader.ReadAllData (stream);
177+
}
111178
}
112179

113180
List<MethodRecord> methods = new List<MethodRecord> (pd.Methods);

0 commit comments

Comments
 (0)