Skip to content

Commit

Permalink
Add support for specifying an output base filename (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
xoofx committed Nov 26, 2024
1 parent b393939 commit 67cba04
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 23 deletions.
34 changes: 14 additions & 20 deletions doc/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,25 +137,20 @@ This is the main command to profile an application - Only working within an elev
Usage: ultra profile [Options] <pid | -- execName arg0 arg1...>

-h, -?, --help Show this message and exit
-o, --output=FILE The base output FILE name. Default is ultra_<process_name>_yyyy-MM-dd_HH_mm_ss.
--pid=PID The PID of the process to attach the profiler to.
--sampling-interval=VALUE The VALUE of the sample interval in ms. Default
is 8190Hz = 0.122ms.
--symbol-path=VALUE The VALUE of symbol path. The default value is `;
SRV*C:\Users\alexa\AppData\Local\Temp\
SymbolCache*https://msdl.microsoft.com/download/
symbols;SRV*C:\Users\alexa\AppData\Local\Temp\
SymbolCache*https://symbols.nuget.org/download/
--sampling-interval=VALUE The VALUE of the sample interval in ms. Default is 8190Hz = 0.122ms.
--symbol-path=VALUE The VALUE of symbol path. The default value is `;SRV*C:\Users\alexa\AppData\
Local\Temp\SymbolCache*https://msdl.microsoft.com/download/symbols;SRV*C:\
Users\alexa\AppData\Local\Temp\SymbolCache*https://symbols.nuget.org/download/
symbols`.
--keep-merged-etl-file Keep the merged ETL file.
--keep-intermediate-etl-files Keep the intermediate ETL files before merging.
--mode=VALUE Defines how the stdout/stderr of a program
explicitly started by ultra should be
integrated in its output. Default is `silent`
which will not mix program's output. The other
options are: `raw` is going to mix ultra and
program output together in a raw output. `live`
is going to mix ultra and program output within
a live table.
--mode=VALUE Defines how the stdout/stderr of a program explicitly started by ultra should be
integrated in its output. Default is `silent` which will not mix program's
output. The other options are: `raw` is going to mix ultra and program output
together in a raw output. `live` is going to mix ultra and program output
within a live table.
```

### Convert
Expand All @@ -168,11 +163,10 @@ It requires a list of PID in order to only produce results for these processes.
Usage: ultra convert --pid xxx <etl_file_name.etl>

-h, -?, --help Show this message and exit
-o, --output=FILE The base output FILE name. Default is the input file name without the extension.
--pid=PID The PID of the process
--symbol-path=VALUE The VALUE of symbol path. The default value is `;
SRV*C:\Users\alexa\AppData\Local\Temp\
SymbolCache*https://msdl.microsoft.com/download/
symbols;SRV*C:\Users\alexa\AppData\Local\Temp\
SymbolCache*https://symbols.nuget.org/download/
--symbol-path=VALUE The VALUE of symbol path. The default value is `;SRV*C:\Users\alexa\AppData\
Local\Temp\SymbolCache*https://msdl.microsoft.com/download/symbols;SRV*C:\
Users\alexa\AppData\Local\Temp\SymbolCache*https://symbols.nuget.org/download/
symbols`.
```
7 changes: 4 additions & 3 deletions src/Ultra.Core/EtwUltraProfiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ public async Task<string> Run(EtwUltraProfilerOptions ultraProfilerOptions)

ultraProfilerOptions.LogProgress?.Invoke($"Merging ETL Files");
// Merge file (and to force Volume mapping)
var etlFinalFile = $"{baseName}.etl";
var etlFinalFile = $"{ultraProfilerOptions.BaseOutputFileName ?? baseName}.etl";
TraceEventSession.Merge([kernelFileName, userFileName, rundownSession], etlFinalFile);
//TraceEventSession.Merge([kernelFileName, userFileName], $"{baseName}.etl");

Expand All @@ -315,7 +315,8 @@ public async Task<string> Run(EtwUltraProfilerOptions ultraProfilerOptions)
if (!ultraProfilerOptions.KeepMergedEtl)
{
File.Delete(etlFinalFile);
File.Delete($"{baseName}.etlx");
var etlxFinalFile = Path.ChangeExtension(etlFinalFile, ".etlx");
File.Delete(etlxFinalFile);
}

return jsonFinalFile;
Expand All @@ -333,7 +334,7 @@ public async Task<string> Convert(string etlFile, List<int> pIds, EtwUltraProfil

var directory = Path.GetDirectoryName(etlFile);
var etlFileNameWithoutExtension = Path.GetFileNameWithoutExtension(etlFile);
var jsonFinalFile = $"{etlFileNameWithoutExtension}.json.gz";
var jsonFinalFile = $"{ultraProfilerOptions.BaseOutputFileName ?? etlFileNameWithoutExtension}.json.gz";
ultraProfilerOptions.LogProgress?.Invoke($"Converting to Firefox Profiler JSON");
await using var stream = File.Create(jsonFinalFile);
await using var gzipStream = new GZipStream(stream, CompressionLevel.Optimal);
Expand Down
13 changes: 13 additions & 0 deletions src/Ultra.Core/EtwUltraProfilerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@ public EtwUltraProfilerOptions()

public string? SymbolPathText { get; set; }

public string? BaseOutputFileName { get; set; }

public void EnsureDirectoryForBaseOutputFileName()
{
if (BaseOutputFileName == null) return;

var directory = Path.GetDirectoryName(BaseOutputFileName);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
}

public SymbolPath GetCachedSymbolPath()
{
var symbolPath = new SymbolPath();
Expand Down
6 changes: 6 additions & 0 deletions src/Ultra/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ static async Task<int> Main(string[] args)
new CommandUsage("Usage: {NAME} [Options] <pid | -- execName arg0 arg1...>"),
_,
new HelpOption(),
{ "o|output=", "The base output {FILE} name. Default is ultra_<process_name>_yyyy-MM-dd_HH_mm_ss.", v => options.BaseOutputFileName = v },
{ "pid=", "The {PID} of the process to attach the profiler to.", (int pid) => { pidList.Add(pid); } },
{ "sampling-interval=", $"The {{VALUE}} of the sample interval in ms. Default is 8190Hz = {options.CpuSamplingIntervalInMs:0.000}ms.", (float v) => options.CpuSamplingIntervalInMs = v },
{ "symbol-path=", $"The {{VALUE}} of symbol path. The default value is `{options.GetCachedSymbolPath()}`.", v => options.SymbolPathText = v },
Expand Down Expand Up @@ -91,6 +92,8 @@ static async Task<int> Main(string[] args)
options.Arguments.AddRange(arguments.AsSpan().Slice(1));
}

options.EnsureDirectoryForBaseOutputFileName();

var etwProfiler = new EtwUltraProfiler();
Console.CancelKeyPress += (sender, eventArgs) =>
{
Expand Down Expand Up @@ -262,6 +265,7 @@ await AnsiConsole.Live(statusTable.Table)
new CommandUsage("Usage: {NAME} --pid xxx <etl_file_name.etl>"),
_,
new HelpOption(),
{ "o|output=", "The base output {FILE} name. Default is the input file name without the extension.", v => options.BaseOutputFileName = v },
{ "pid=", "The {PID} of the process", (int pid) => { pidList.Add(pid); } },
{ "symbol-path=", $"The {{VALUE}} of symbol path. The default value is `{options.GetCachedSymbolPath()}`.", v => options.SymbolPathText = v },
async (ctx, arguments) =>
Expand Down Expand Up @@ -328,6 +332,8 @@ await AnsiConsole.Status()
}
};

options.EnsureDirectoryForBaseOutputFileName();

fileOutput = await etwProfiler.Convert(etlFile, pidList, options);
}
finally
Expand Down

0 comments on commit 67cba04

Please sign in to comment.