Skip to content

Commit

Permalink
Add basic documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
xoofx committed Nov 18, 2024
1 parent d411667 commit 5737c0f
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 55 deletions.
129 changes: 128 additions & 1 deletion doc/readme.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,130 @@
# Ultra User Guide

This is a default project description.
## Quick Start

> ____
> 🚨 The profiler **requires to run from an elevated prompt with administrative rights** 🚨
>
> _This is required to allow to collect full stack traces, including kernel and native functions._
> ____
Example: open a **terminal with administrative rights**, to profile an executable called `my_commands.exe`:

```console
$ ultra.exe profile -- my_command.exe arg0 arg1 arg2...
```

This will create a `ultra_my_command_..._.json.gz` trace file in the current directory.

## Ultra Profiler UI

In order to visualize a trace produced by `ultra.exe` you need to go to https://profiler.firefox.com/ and open the generated `json.gz` trace file.

### Timeline

This screenshot shows a profile captured with ultra and is available online [here](https://share.firefox.dev/3Cya7YW)

You have access to several capabilities:
- Zoom in a timeline
- When in the Flame Graph / Stack Chart, you can hold `SHIFT + MouseWheel` to zoom-in / zoom-out

![Timeline](profile_example.png)

### Flame Graph / Stack Chart

The Flame Graph / Stack Chart is a visualization of the time spent in functions. The width of the boxes is proportional to the time spent in the function. The boxes are stacked to show the call hierarchy.

![Flame Graph](profile_flame_graph.png)

### Categories

When selecting functions, you can visualize the split between the time in the different modules:

- `.NET`: Managed code (user or BCL)
- `.NET JIT`: Functions participating in the JIT to compile methods
- `.NET GC`: Functions participating in the GC
- `.NET CLR`: Functions used by the CoreCLR runtime
- `Native`: Native functions
- `Kernel`: Kernel functions - displayed with hexadecimal address

The colors are reflected in the Flame Graph / Stack Chart to easily spot the different usage.

![Categories](profile_categories.png)

While hovering the mouse over a function, you can see the time spent in the function and the categories:

Here is an example of a function in the `JIT` category:

![Category JIT)](profile_category_jit.png)


Here is an example of a function in the `GC` category:

![Category GC](profile_category_gc.png)

### Memory Track

The memory track shows the managed memory usage of the process. You can see the memory usage over time.

![Profile Memory](profile_memory.png)

## GC Allocation Track

The GC Allocation Track shows the allocation rate of the process. You can see the allocation rate over time.

![Profile GC Allocation](profile_gc_alloc.png)

### JIT and GC Markers

The JIT and GC markers are displayed in the timeline. You can see the JIT and GC events in the timeline.

You can also see them in the Marker Chart and Marker Table view.

![Profile JIT and GC Markers](profile_markers.png)

## Ultra Command Line

ultra.exe command line options:

```console
Usage: ultra [Options] command

-h, -?, --help Show this message and exit
-v, --version Show the version of this command
--verbose Display verbose progress

Available commands:
profile Profile a new process or attach to an existing process
convert Convert an existing ETL file to a Firefox Profiler json file
```

## Profile

This is the main command to profile an application - Only working within an elevated prompt:

```console
Usage: ultra profile [Options] <pid | -- execName arg0 arg1...>

-h, -?, --help Show this message and exit
--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\xoofx\AppData\Local\Temp\SymbolCache*https://msdl.microsoft.com/download/symbols;SRV*C:\Users\xoofx\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.
```

## Convert

Convert an existing ETL file to a Firefox Profiler json file:

It requires a list of PID in order to only produce results for these processes.

```console
Usage: ultra convert --pid xxx <etl_file_name.etl>

-h, -?, --help Show this message and exit
--pid=PID The PID of the process
--symbol-path=VALUE The VALUE of symbol path. The default value is `;SRV*C:\Users\xoofx\AppData\Local\Temp\SymbolCache*https://msdl.microsoft.com/download/symbols;SRV*C:\Users\xoofx\AppData\Local\Temp\SymbolCache*https://
symbols.nuget.org/download/symbols`.
```
20 changes: 19 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Ultra is a an advanced profiler for .NET Applications available on Windows.
- ETW based **sampling profiler** - up to 8190 samples/second
- UI based on https://profiler.firefox.com/
- Traces shareable online: Check this example: ✨ https://share.firefox.dev/3Cya7YW
- **Timeline** visualization
- **Flamegraph / Stack Chart** visualization
- **Call Tree** visualization
- **Marker Chart** and **Marker Table** visualization
- Precise **kernel**, **native** and **managed** **function call stacks**
- Categorization of functions:
- `.NET`, `.NET JIT`, `.NET GC`, `.NET CLR`, `Native`, `Kernel`
Expand All @@ -34,12 +38,26 @@ You need to have installed a [.NET 8.0+ SDK](https://dotnet.microsoft.com/en-us/
$ dotnet tool install -g Ultra # The command ultra.exe will be available from your PATH
```

Open a **terminal in administrative rights**, to profile the executable `my_commands.exe`:
> ____
> 🚨 The profiler **requires to run from an elevated prompt with administrative rights** 🚨
>
> _This is required to allow to collect full stack traces, including kernel and native functions._
> ____
Example: open a **terminal with administrative rights**, to profile an executable called `my_commands.exe`:

```console
$ ultra.exe profile -- my_command.exe arg0 arg1 arg2...
```

> ⚠️ Notice the `--` separator to separate the arguments to `ultra.exe` from the arguments to the profiled application.
Profiling a running application just requires the PID of the process to profile:

```console
$ ultra.exe profile 15243 # PID of the process to profile
```

## 📖 User Guide

For more details on how to use Ultra, please visit the [user guide](https://github.com/xoofx/Ultra/blob/main/doc/readme.md).
Expand Down
6 changes: 3 additions & 3 deletions src/Ultra.Core/Ultra.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
</PropertyGroup>

<PropertyGroup>
<Description>This is a default project description</Description>
<Description>Ultra is a an advanced profiler for .NET Applications available on Windows.</Description>
<Copyright>Alexandre Mutel</Copyright>
<NeutralLanguage>en-US</NeutralLanguage>
<Authors>Alexandre Mutel</Authors>
<PackageTags>tag1;tag2;tag3</PackageTags>
<PackageTags>profiler;etw</PackageTags>
<PackageReadmeFile>readme.md</PackageReadmeFile>
<PackageIcon>ultra.png</PackageIcon>
<PackageProjectUrl>https://github.com/xoofx/ultra</PackageProjectUrl>
Expand All @@ -27,7 +27,7 @@

<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)../../img/ultra.png" Pack="true" PackagePath="/" />
<None Include="$(MSBuildThisFileDirectory)../../readme.md" Pack="true" PackagePath="/" />
<None Include="readme.md" Pack="true" PackagePath="/" />
</ItemGroup>

<ItemGroup>
Expand Down
20 changes: 20 additions & 0 deletions src/Ultra.Core/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Ultra.Core

Ultra is a an advanced profiler for .NET Applications available on Windows.

Ultra.Core is the core library that contains the core functionalities of the Ultra profiler:

- ETW sampling profiler via the class `EtwUltraProfiler`
- Converter to Firefox Profiler format via the class `EtwConverterToFirefox`

## 📖 User Guide

For more details on how to use Ultra, please visit the [user guide](https://github.com/xoofx/Ultra/blob/main/doc/readme.md).

## 🪪 License

This software is released under the [BSD-2-Clause license](https://opensource.org/licenses/BSD-2-Clause).

## 🤗 Author

Alexandre Mutel aka [xoofx](https://xoofx.github.io).
84 changes: 37 additions & 47 deletions src/Ultra.Example/Program.cs
Original file line number Diff line number Diff line change
@@ -1,58 +1,48 @@
namespace Ultra.Example;
// Sample program using Markdig and Scriban to create a workload example for profiling with ultra

/// <summary>
/// Sample program using Markdig and Scriban to create a workload example for profiling with ultra
/// </summary>
internal class Program
const int countBenchMarkdig = 500;
const int countBenchScriban = 5000;
var md = await File.ReadAllTextAsync(Path.Combine(AppContext.BaseDirectory, "CommonMark.md"));

var benchMarkdig = () =>
{
static async Task Main(string[] args)
for (int i = 0; i < countBenchMarkdig; i++)
{
const int CountBenchMarkdig = 500;
const int CountBenchScriban = 5000;

var md = await File.ReadAllTextAsync(Path.Combine(AppContext.BaseDirectory, "CommonMark.md"));

var benchMarkdig = () =>
{
for (int i = 0; i < CountBenchMarkdig; i++)
{
var html = Markdig.Markdown.ToHtml(md);
}
};

var benchScriban = () =>
{
var template = Scriban.Template.Parse("""
{{ for $i in values }}
[{{i}}] This is an example of a template with a loop
{{ end }}
""");
var html = Markdig.Markdown.ToHtml(md);
}
};

var values = new List<string> { "one", "two", "three" };
for (int i = 0; i < CountBenchScriban; i++)
{
var text = template.Render(new { values = values });
}
};
var benchScriban = () =>
{
var template = Scriban.Template.Parse("""
{{ for $i in values }}
[{{i}}] This is an example of a template with a loop
{{ end }}
""");

var values = new List<string> { "one", "two", "three" };
for (int i = 0; i < countBenchScriban; i++)
{
var text = template.Render(new { values = values });
}
};

benchMarkdig();
benchMarkdig();

var tasks = new List<Task>();
var tasks = new List<Task>();

for (int i = 0; i < Math.Max(2, Environment.ProcessorCount / 4); i++)
{
var markdigTask = new Task(benchMarkdig);
var scribanTask = new Task(benchScriban);
for (int i = 0; i < Math.Max(2, Environment.ProcessorCount / 4); i++)
{
var markdigTask = new Task(benchMarkdig);
var scribanTask = new Task(benchScriban);

markdigTask.Start();
scribanTask.Start();
markdigTask.Start();
scribanTask.Start();

tasks.Add(markdigTask);
tasks.Add(scribanTask);
}
tasks.Add(markdigTask);
tasks.Add(scribanTask);
}

benchScriban();
benchScriban();

await Task.WhenAll(tasks);
}
}
await Task.WhenAll(tasks);
5 changes: 4 additions & 1 deletion src/Ultra.Tests/FirefoxProfilerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@

namespace Ultra.Tests;

/// <summary>
/// No real tests here yet, just to check the serialization of Firefox profiler format
/// </summary>
[TestClass]
public class Class1Test
public class FirefoxProfilerTests
{
[TestMethod]
public void TestMarker()
Expand Down
9 changes: 9 additions & 0 deletions src/Ultra/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"profiles": {
"Ultra": {
"commandName": "Project",
"commandLineArgs": "convert --pid 472972 .\\ultra_Ultra.Example_2024-11-18_12_04_12.etl",
"workingDirectory": "C:\\code\\Captures"
}
}
}
4 changes: 2 additions & 2 deletions src/Ultra/Ultra.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
</PropertyGroup>

<PropertyGroup>
<Description>This is a default project description</Description>
<Description>Ultra is a an advanced profiler for .NET Applications available on Windows.</Description>
<Copyright>Alexandre Mutel</Copyright>
<NeutralLanguage>en-US</NeutralLanguage>
<Authors>Alexandre Mutel</Authors>
<PackageTags>tag1;tag2;tag3</PackageTags>
<PackageTags>profiler;etw</PackageTags>
<PackageReadmeFile>readme.md</PackageReadmeFile>
<PackageIcon>ultra.png</PackageIcon>
<PackageProjectUrl>https://github.com/xoofx/ultra</PackageProjectUrl>
Expand Down
5 changes: 5 additions & 0 deletions src/ultra.sln
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ultra.Core", "Ultra.Core\Ul
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ultra.Example", "Ultra.Example\Ultra.Example.csproj", "{E0F444AD-490E-464F-BA51-A82886C7FF6A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{2D4C3E26-09DE-45BB-A581-6EEF97C6CFA1}"
ProjectSection(SolutionItems) = preProject
..\doc\readme.md = ..\doc\readme.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down
2 changes: 2 additions & 0 deletions src/ultra.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Markdig/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

0 comments on commit 5737c0f

Please sign in to comment.