Generate timer results XML¶
This operation transforms the flat, semicolon-delimited timer dictionary into a hierarchical result tree and serializes that tree as XML. It is the library's primary reporting path: it is how a caller who has been starting and stopping timers throughout a run turns the accumulated data into a document that can be inspected, logged, or archived.
| Field | Value |
|---|---|
| Operation ID | CT-OP-004 |
| Trigger | Caller invokes CodeTimer.Results() or CodeTimer.Results(bool includeTimeSpans) |
| Inputs | Optional includeTimeSpans flag |
| Outputs | XDocument rooted at <Timer>, or null when no timer data exists |
| Primary components | CodeTimer.Results, CodeTimerResult.CodeTimerResult, CodeTimerResult.CreateItems, CodeTimerResult.OutputXml, CodeTimerResult.RecurseXml |
| Entry point | SAIF.Framework.CodeTimer\SAIF.Framework.CodeTimer\CodeTimer.cs |
Steps¶
- Normalize the call to
CodeTimer.Results(bool includeTimeSpans)— the parameterless overload simply delegates toResults(false), so time-span detail is opt-in rather than the default. - Check whether the static
datadictionary contains any entries at all. - If the dictionary is empty, return
nullimmediately rather than constructing and returning an empty<Timer>document. - Construct a new
CodeTimerResult(data), whose constructor immediately callsCreateItems()to build the reporting tree before any XML is produced. - Within
CreateItems(), iterate everyCodeTimerEntrycurrently in the dictionary. - If any entry is still marked as running, abandon the reporting attempt and throw under BR-003 — a report is only meaningful once every timer it would summarize has actually finished.
- Split each entry's
;-delimited timer name into its component parts, and walk or create the correspondingCodeTimerItemnodes so the flat key space becomes a proper parent/child tree. - Populate the leaf node that matches the entry's full key with its elapsed time, quantity, start/stop timestamps, shortest/longest span, and span history; populate any intermediate node created purely for grouping with sentinel values such as
Elapsed = -1so it can be distinguished from a real, measured timer. - Call
OutputXml(includeTimeSpans), which creates a newXDocumentwith a single<Timer>root element to hold the serialized tree. - Recursively serialize each top-level
CodeTimerItemthroughRecurseXml(...), which decides per node which attributes are worth emitting. - Emit the
short,long,avg, andqtyattributes only when the item has been measured more than once (Qty > 1); a single-execution timer has no meaningful range or average to report (BR-006). - Emit the
msattribute only when the item's elapsed value is greater than zero, so grouping-only nodes stay free of a misleading duration (BR-006). - Emit
<span>child elements only when the caller requestedincludeTimeSpans, the item recorded more than one span, and each individual span's computed duration is greater than zero milliseconds — a single span or a zero-length span carries no additional signal (BR-006). - Recurse into an item's children only when that item both has children and has a positive
Elapsedvalue; once every reachable node has been visited, return the completedXDocumentto the caller.
Process flow¶
The following diagram visualizes this operation's control flow.
flowchart TD
Start([Results request]) --> HasData{Any timer data?}
HasData -->|No| NoData([Return null])
HasData -->|Yes| BuildResult[Construct CodeTimerResult]
BuildResult --> Running{Any entry still running?}
Running -->|Yes| Error([Throw running-timer exception])
Running -->|No| BuildTree[Create CodeTimerItem tree]
BuildTree --> Serialize[Serialize XML output]
Serialize --> EndOk([Return XDocument])
Failure and edge-case behavior¶
- Requesting results while any timer in the store is still running throws under BR-003 — the caller must ensure every started timer has been stopped first.
Results()returnsnull, not an empty document, when no timer entries have ever been captured; callers must check fornullrather than assuming anXDocumentis always returned.- Even with
includeTimeSpansset totrue, a timer that was only ever started and stopped once produces no<span>elements, becauseRecurseXmlrequires more than one recorded span before it will serialize any (BR-006). - Intermediate parent nodes that exist only to group child timers under a shared key prefix do not recurse into their children unless that parent node itself also has a positive
Elapsedvalue, which can leave otherwise-valid child measurements unreported if the grouping node was never itself timed.
Related documentation¶
Sources¶
- SAIF.Framework.CodeTimer\SAIF.Framework.CodeTimer\CodeTimer.cs
- SAIF.Framework.CodeTimer\SAIF.Framework.CodeTimer\CodeTimerEntry.cs
- SAIF.Framework.CodeTimer\SAIF.Framework.CodeTimer\CodeTimerItem.cs
- SAIF.Framework.CodeTimer\SAIF.Framework.CodeTimer\CodeTimerResult.cs