---
title: Start a timed operation
summary: Begin or resume a timer entry for an attributed method/custom name within an optional parent hierarchy.
status: draft
owner: SAIF
last_reviewed: 2026-07-30
library: SAIF.Framework.CodeTimer
reference_type: package
operation_id: CT-OP-001
trigger: Caller invokes CodeTimer.Start(MethodBase...) on an instrumented method.
---

# Start a timed operation

This operation opens a new timing window for a method, or resumes one that was previously started, and returns the hierarchical key that a matching `Stop` call will need later. It is the entry point that lets a caller build nested timer paths — a parent operation's key can be threaded into child calls so the resulting report shows one operation's timing nested inside another's.

| Field | Value |
| --- | --- |
| **Operation ID** | CT-OP-001 |
| **Trigger** | Caller invokes `CodeTimer.Start(MethodBase...)` |
| **Inputs** | `MethodBase method`, optional `customName`, optional `parentTimerKey` |
| **Outputs** | Timer key string; new or resumed `CodeTimerEntry` state when timing is allowed |
| **Primary components** | `CodeTimer.Start`, `CodeTimer.GetCodeTimerParent`, `CodeTimerEntry.Start`, `CodeTimerEntry.CodeTimerEntry` |
| **Entry point** | `SAIF.Framework.CodeTimer\SAIF.Framework.CodeTimer\CodeTimer.cs` |

## Steps

1. Derive the base timer name from `method.Name`, appending `.{customName}` whenever the caller supplied a custom suffix, so that two calls to the same method under different names produce distinct timer entries.
2. Inspect the target method for a `CodeTimerAttribute` via reflection — this is the per-method gate that decides whether the method participates in timing at all.
   - If the method carries no `CodeTimerAttribute`, return the incoming `parentTimerKey` unchanged and make no changes to the timer store ([BR-005](../business-rules.md#br-005-timing-is-only-recorded-when-both-the-global-switch-and-any-per-method-attribute-allow-it)).
   - If the attribute is present but its `Enabled` flag is `false`, return the incoming `parentTimerKey` unchanged, again without touching the store ([BR-005](../business-rules.md#br-005-timing-is-only-recorded-when-both-the-global-switch-and-any-per-method-attribute-allow-it)).
3. Assemble the hierarchical timer key via `GetCodeTimerParent`, inserting a `;` separator only when a non-empty parent key was supplied — this is what turns a flat name into a `parent;child` path that later reporting steps can split back apart.
4. Evaluate the global `CodeTimer.Enabled` switch, the second and coarser-grained gate.
   - If the switch is `false`, return an empty string and skip every state change, regardless of what the per-method attribute allowed ([BR-005](../business-rules.md#br-005-timing-is-only-recorded-when-both-the-global-switch-and-any-per-method-attribute-allow-it)).
5. Look up the composite key in the static `data` dictionary that backs the entire timer store.
   - If no entry exists yet for that key, create a new `CodeTimerEntry`; its constructor stamps both `started` and `lastStarted` with `DateTime.Now`, sets the initial `quantity` to `1`, and marks the entry as running.
   - If an entry already exists for that key, call `CodeTimerEntry.Start()` to resume it rather than replacing it, which preserves prior accumulated statistics across repeated start/stop cycles for the same key.
     - On failure: if the entry is already marked running, `CodeTimerEntry.Start()` refuses the duplicate start and throws instead of silently restarting the clock ([BR-001](../business-rules.md#br-001-a-timer-must-not-be-started-while-already-running)).
6. Return the composite key to the caller. This value has no further use for the caller other than being passed back in as `parentTimerKey` on a nested `Start` call, or reused to address the same entry on the matching `Stop` call.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Start request]) --> Resolve[Resolve method and custom name]
	Resolve --> Attr{Attribute present<br>and enabled?}
	Attr -->|No| NoOp([Return parent key])
	Attr -->|Yes| BuildKey[Build hierarchical key]
	BuildKey --> Enabled{CodeTimer.Enabled?}
	Enabled -->|No| Disabled([Return empty string])
	Enabled -->|Yes| Exists{Entry already exists?}
	Exists -->|No| Create[Create CodeTimerEntry]
	Exists -->|Yes| Resume[Resume existing entry]
	Create --> EndOk([Return timer key])
	Resume --> EndOk
```

## Failure and edge-case behavior

- A method with no `CodeTimerAttribute` produces no timer entry at all; the call is a pass-through that simply hands back the incoming parent key.
- When the global timer subsystem is disabled, `Start` returns an empty string rather than a usable key, so callers should not assume a non-empty key is always returned ([BR-005](../business-rules.md#br-005-timing-is-only-recorded-when-both-the-global-switch-and-any-per-method-attribute-allow-it)).
- Calling `Start` again for a key that is already running — for example, a re-entrant or recursive call that was not designed to nest — throws under [BR-001](../business-rules.md#br-001-a-timer-must-not-be-started-while-already-running) rather than extending the existing timing window.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Configuration](../configuration.md)
- [API reference](../api/index.md)

## Sources
- SAIF.Framework.CodeTimer\SAIF.Framework.CodeTimer\CodeTimer.cs
- SAIF.Framework.CodeTimer\SAIF.Framework.CodeTimer\CodeTimerAttribute.cs
- SAIF.Framework.CodeTimer\SAIF.Framework.CodeTimer\CodeTimerEntry.cs
