Skip to content

Commit 08bc887

Browse files
VPDPersonalclaude
andcommitted
docs(profiler-markers): one example type, generated-code block, minimal sample section
- quick start now uses FlockSimulation like the rest of the page - Profiler screenshot replaces the ASCII tree; the duplicate "Result in Profiler" section becomes a one-line "Package sample" - collapsible generated-code example under Step(); line-number and ENABLE_PROFILER bullets shortened - drop the using/IDisposable semantics sentence (Unity behaviour, not FastTools) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 8f77799 commit 08bc887

2 files changed

Lines changed: 89 additions & 47 deletions

File tree

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
# ProfilerMarkers
22

3-
`this.Marker()` automatically creates a Unity Profiler marker.
3+
`this.Marker()` creates a Unity Profiler marker named `Type.Method (line)` — no static `ProfilerMarker` field and no hand-typed name.
44

55
## Quick start
66

7+
The examples on this page work with the `FlockSimulation` class from the [ProfilerMarkers sample](../Samples~/ProfilerMarkers/Documentation/README.md):
8+
79
| Before — Unity API | After — FastTools |
810
|---|---|
9-
| <pre lang="csharp"><code>private static readonly&#10; ProfilerMarker UpdateMarker =&#10; new("MotionSimulation.Update");&#10;&#10;private void Update()&#10;&#123;&#10; using var _ =&#10; UpdateMarker.Auto();&#10; Simulate();&#10;&#125;</code></pre> | <pre lang="csharp"><code>private void Update()&#10;&#123;&#10; using var _ = this.Marker();&#10; Simulate();&#10;&#125;</code></pre> |
11+
| <pre lang="csharp"><code>private static readonly&#10; ProfilerMarker StepMarker =&#10; new("FlockSimulation.Step");&#10;&#10;public void Step()&#10;&#123;&#10; using var _ = StepMarker.Auto();&#10; Integrate();&#10;&#125;</code></pre> | <pre lang="csharp"><code>public void Step()&#10;&#123;&#10; using var _ = this.Marker();&#10; Integrate();&#10;&#125;</code></pre> |
1012

11-
Works in `MonoBehaviour` and ordinary C# classes. The generator ships with the package; the extension is in the global namespace — no extra `using`, attributes, or `partial` declaration needed. The marker is named `Type.Method (line)`.
13+
Works in `MonoBehaviour` and ordinary C# classes. The generator ships with the package; the extension is in the global namespace — no extra `using`, attributes, or `partial` declaration needed.
1214

1315
## Scope and names
1416

15-
`Marker()` returns a `ProfilerMarker.AutoScope`: measurement starts at the call and ends when leaving `using`, including on `return` or an exception. `.WithName("Steering")` replaces the method part of the name; the type and line number remain.
17+
`Marker()` returns a `ProfilerMarker.AutoScope`. `.WithName("Steering")` replaces the method part of the name; the type and line number remain.
1618

1719
```csharp
1820
public void Step()
@@ -35,35 +37,54 @@ public void Step()
3537
}
3638
```
3739

38-
In the Profiler with 120 loop iterations:
40+
<details>
41+
<summary>Generated code</summary>
42+
43+
Abridged: without `global::` and the repeated attribute. Line numbers count from the top of the block above; in a real file they are source-file lines.
44+
45+
```csharp
46+
// <auto-generated>
47+
[GeneratedCode("Aspid.FastTools.Generators.ProfilerMarkersGenerator", "1.0.0")]
48+
internal static class __FlockSimulationProfilerMarkerExtensions
49+
{
50+
private static readonly ProfilerMarker Step = new("FlockSimulation.Step (3)");
51+
private static readonly ProfilerMarker Step_2 = new("FlockSimulation.Steering (5)");
52+
private static readonly ProfilerMarker Step_3 = new("FlockSimulation.Steering.Agent (9)");
53+
private static readonly ProfilerMarker Step_4 = new("FlockSimulation.Integrate (14)");
3954

40-
```text
41-
FlockSimulation.Step (…)
42-
├── FlockSimulation.Steering (…)
43-
│ └── FlockSimulation.Steering.Agent (…) — 120 calls to one marker
44-
└── FlockSimulation.Integrate (…)
55+
public static ProfilerMarker.AutoScope Marker(this FlockSimulation _, [CallerLineNumber] int line = -1)
56+
{
57+
#if ENABLE_PROFILER
58+
if (line is 3) return Step.Auto();
59+
if (line is 5) return Step_2.Auto();
60+
if (line is 9) return Step_3.Auto();
61+
if (line is 14) return Step_4.Auto();
62+
#endif
63+
return default;
64+
}
65+
}
4566
```
4667

47-
`WithName` accepts only a string literal: `"Steering"`, `@"Steering"`, or `$"Steering"` without substitutions. Variables, `const`, `nameof`, concatenation, and `$"Agent {index}"` keep the original method name — the generator reads the source text and does not evaluate expressions. The argument is still evaluated at runtime.
68+
</details>
4869

49-
> [!IMPORTANT]
50-
> Do not call `this.Marker()` without `using`: measurement will not end automatically. Scopes must not cross `await` or `yield`; measure synchronous sections separately ([Unity limitation](https://docs.unity3d.com/6000.0/Documentation/Manual/profiler-add-markers-code.html)).
70+
The tree in **CPU Usage → Hierarchy** mirrors the `using` nesting, and a marker inside a loop stays a single row with a `Calls` count. Deep Profile is not needed.
5171

52-
## Generation details
72+
![FlockSimulation markers in CPU Usage: Steering and Integrate nested under Step, Steering.Agent with 120 calls](../Samples~/ProfilerMarkers/Documentation/Images/profiler-markers.png)
5373

54-
- **Line number.** The marker is selected by `CallerLineNumber`, so each call within a type needs its own line, including across `partial` files. Moving the call changes the name suffix.
55-
- **Lambdas and local functions** use the nearest declared member: `Ctor` for constructors, the property name for accessors.
56-
- **Generic types** get separate markers per closed type: `Worker<int>.Run()` → `Worker<Int32>.Run (line)`.
57-
- **Without `ENABLE_PROFILER`** the extension returns `default`: nothing is measured, the code inside `using` still runs, `WithName` arguments are still evaluated.
74+
FlockSimulation markers in CPU Usage: Steering and Integrate nested under Step, Steering.Agent with 120 calls
5875

59-
<a id="result"></a>
76+
`WithName` accepts only a string literal: `"Steering"`, `@"Steering"`, or `$"Steering"` without substitutions. Variables, `const`, `nameof`, concatenation, and `$"Agent {index}"` keep the original method name — the generator reads the source text and does not evaluate expressions. The argument is still evaluated at runtime.
6077

61-
## Result in the Profiler
78+
> [!IMPORTANT]
79+
> Do not call `this.Marker()` without `using`: the measurement will not end automatically. A scope must not cross `await` or `yield`; measure synchronous sections separately ([Unity limitation](https://docs.unity3d.com/6000.0/Documentation/Manual/profiler-add-markers-code.html)).
6280
63-
Open **Window → Analysis → Profiler**, enable recording, and run the scene. Select a frame in **CPU Usage → Hierarchy** and search for the type name. Deep Profile is not required.
81+
## Generation details
6482

65-
![Flock and FlockSimulation markers in CPU Usage: Steering.Agent has 120 calls](../Samples~/ProfilerMarkers/Documentation/Images/profiler-markers.png)
83+
- **Line number.** Every call in a type needs its own line, including across `partial` files. Moving a call changes the name suffix.
84+
- **Member name.** A method contributes its own name, a constructor `Ctor`, a property accessor the property name. Lambdas and local functions use the member they are declared in.
85+
- **Generic types** get separate markers per closed type: `Worker<int>.Run()` → `Worker<Int32>.Run (line)`.
86+
- **Without `ENABLE_PROFILER`** nothing is measured, but the code inside `using` and the `WithName` arguments still run.
6687

67-
Flock and FlockSimulation markers in CPU Usage: Steering.Agent has 120 calls
88+
## Package sample
6889

69-
To reproduce this, import the [ProfilerMarkers sample](../Samples~/ProfilerMarkers/Documentation/README.md#try), open `Scenes/ProfilerMarkers.unity`, and search for `Flock`. Timings depend on the frame and machine.
90+
A flock scene with 120 agents where `FlockSimulation` carries the markers shown above: [ProfilerMarkers](../Samples~/ProfilerMarkers/Documentation/README.md).
Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
# ProfilerMarkers
22

3-
`this.Marker()` автоматически создаёт маркер Unity Profiler.
3+
`this.Marker()` создаёт маркер Unity Profiler с именем `Тип.Метод (строка)` — без статического поля `ProfilerMarker` и без имени, набранного руками.
44

55
## Быстрый старт
66

7+
Примеры на этой странице работают с классом `FlockSimulation` из [примера ProfilerMarkers](../../Samples~/ProfilerMarkers/Documentation/README.ru.md):
8+
79
| До — Unity API | После — FastTools |
810
|---|---|
9-
| <pre lang="csharp"><code>private static readonly&#10; ProfilerMarker UpdateMarker =&#10; new("MotionSimulation.Update");&#10;&#10;private void Update()&#10;&#123;&#10; using var _ =&#10; UpdateMarker.Auto();&#10; Simulate();&#10;&#125;</code></pre> | <pre lang="csharp"><code>private void Update()&#10;&#123;&#10; using var _ = this.Marker();&#10; Simulate();&#10;&#125;</code></pre> |
11+
| <pre lang="csharp"><code>private static readonly&#10; ProfilerMarker StepMarker =&#10; new("FlockSimulation.Step");&#10;&#10;public void Step()&#10;&#123;&#10; using var _ = StepMarker.Auto();&#10; Integrate();&#10;&#125;</code></pre> | <pre lang="csharp"><code>public void Step()&#10;&#123;&#10; using var _ = this.Marker();&#10; Integrate();&#10;&#125;</code></pre> |
1012

11-
Работает в `MonoBehaviour` и обычных C#-классах. Генератор входит в пакет; расширение находится в глобальном пространстве имён — дополнительные `using`, атрибуты и `partial` не нужны. Маркер называется `Тип.Метод (строка)`.
13+
Работает в `MonoBehaviour` и обычных C#-классах. Генератор входит в пакет; расширение находится в глобальном пространстве имён — дополнительные `using`, атрибуты и `partial` не нужны.
1214

1315
## Область и имя
1416

15-
`Marker()` возвращает `ProfilerMarker.AutoScope`: замер начинается при вызове и завершается при выходе из `using`, включая `return` и исключения. `.WithName("Steering")` заменяет часть имени с методом; тип и номер строки остаются.
17+
`Marker()` возвращает `ProfilerMarker.AutoScope`. `.WithName("Steering")` заменяет часть имени с методом; тип и номер строки остаются.
1618

1719
```csharp
1820
public void Step()
@@ -35,35 +37,54 @@ public void Step()
3537
}
3638
```
3739

38-
В Profiler при 120 итерациях цикла:
40+
<details>
41+
<summary>Сгенерированный код</summary>
42+
43+
Сокращённо: без `global::` и повторов атрибута. Номера строк считаются от начала блока выше; в реальном файле это строки исходника.
44+
45+
```csharp
46+
// <auto-generated>
47+
[GeneratedCode("Aspid.FastTools.Generators.ProfilerMarkersGenerator", "1.0.0")]
48+
internal static class __FlockSimulationProfilerMarkerExtensions
49+
{
50+
private static readonly ProfilerMarker Step = new("FlockSimulation.Step (3)");
51+
private static readonly ProfilerMarker Step_2 = new("FlockSimulation.Steering (5)");
52+
private static readonly ProfilerMarker Step_3 = new("FlockSimulation.Steering.Agent (9)");
53+
private static readonly ProfilerMarker Step_4 = new("FlockSimulation.Integrate (14)");
3954

40-
```text
41-
FlockSimulation.Step (…)
42-
├── FlockSimulation.Steering (…)
43-
│ └── FlockSimulation.Steering.Agent (…) — 120 вызовов одного маркера
44-
└── FlockSimulation.Integrate (…)
55+
public static ProfilerMarker.AutoScope Marker(this FlockSimulation _, [CallerLineNumber] int line = -1)
56+
{
57+
#if ENABLE_PROFILER
58+
if (line is 3) return Step.Auto();
59+
if (line is 5) return Step_2.Auto();
60+
if (line is 9) return Step_3.Auto();
61+
if (line is 14) return Step_4.Auto();
62+
#endif
63+
return default;
64+
}
65+
}
4566
```
4667

68+
</details>
69+
70+
Дерево в **CPU Usage → Hierarchy** повторяет вложенность `using`, а маркер внутри цикла остаётся одной строкой со счётчиком `Calls`. Deep Profile не нужен.
71+
72+
![Маркеры FlockSimulation в CPU Usage: Steering и Integrate вложены в Step, у Steering.Agent — 120 вызовов](../../Samples~/ProfilerMarkers/Documentation/Images/profiler-markers.png)
73+
74+
Маркеры FlockSimulation в CPU Usage: Steering и Integrate вложены в Step, у Steering.Agent — 120 вызовов
75+
4776
`WithName` принимает только строковый литерал: `"Steering"`, `@"Steering"` или `$"Steering"` без подстановок. Переменные, `const`, `nameof`, конкатенация и `$"Agent {index}"` оставляют исходное имя метода — генератор читает текст исходника и не вычисляет выражения. Сам аргумент во время выполнения всё равно вычисляется.
4877

4978
> [!IMPORTANT]
5079
> Не вызывайте `this.Marker()` без `using`: замер не завершится автоматически. Область не должна пересекать `await` или `yield`; измеряйте синхронные участки отдельно ([ограничение Unity](https://docs.unity3d.com/6000.0/Documentation/Manual/profiler-add-markers-code.html)).
5180
5281
## Особенности генерации
5382

54-
- **Номер строки.** Маркер выбирается по `CallerLineNumber`, поэтому каждому вызову в типе нужна своя строка, в том числе в разных файлах `partial`. Перенос вызова меняет суффикс имени.
55-
- **Лямбды и локальные функции** используют ближайший объявленный член: `Ctor` для конструктора, имя свойства для аксессора.
83+
- **Номер строки.** Каждому вызову в типе нужна своя строка, в том числе в разных файлах `partial`. Перенос вызова меняет суффикс имени.
84+
- **Имя члена.** Метод даёт своё имя, конструктор — `Ctor`, аксессор свойства — имя свойства. Лямбды и локальные функции используют член, в котором объявлены.
5685
- **Generic-типы** получают отдельные маркеры на каждый закрытый тип: `Worker<int>.Run()` → `Worker<Int32>.Run (строка)`.
57-
- **Без `ENABLE_PROFILER`** расширение возвращает `default`: ничего не измеряется, код внутри `using` выполняется, аргументы `WithName` по-прежнему вычисляются.
58-
59-
<a id="result"></a>
60-
61-
## Результат в Profiler
62-
63-
Откройте **Window → Analysis → Profiler**, включите запись и запустите сцену. Выберите кадр в **CPU Usage → Hierarchy** и найдите имя типа. Deep Profile не нужен.
64-
65-
![Маркеры Flock и FlockSimulation в CPU Usage: у Steering.Agent — 120 вызовов](../../Samples~/ProfilerMarkers/Documentation/Images/profiler-markers.png)
86+
- **Без `ENABLE_PROFILER`** ничего не измеряется, но код внутри `using` и аргументы `WithName` по-прежнему выполняются.
6687

67-
Маркеры Flock и FlockSimulation в CPU Usage: у Steering.Agent — 120 вызовов
88+
## Пример в пакете
6889

69-
Чтобы повторить, импортируйте [пример ProfilerMarkers](../../Samples~/ProfilerMarkers/Documentation/README.ru.md#попробуйте), откройте `Scenes/ProfilerMarkers.unity` и найдите `Flock`. Время зависит от кадра и машины.
90+
Сцена со стаей из 120 агентов, где `FlockSimulation` размечен показанными выше маркерами: [ProfilerMarkers](../../Samples~/ProfilerMarkers/Documentation/README.ru.md).

0 commit comments

Comments
 (0)