| # Trace experiments | |
| Execution traces allow for trialing new events on an experimental basis via | |
| trace experiments. | |
| This document is a guide that explains how you can define your own trace | |
| experiments. | |
| Note that if you're just trying to do some debugging or perform some light | |
| instrumentation, then a trace experiment is way overkill. | |
| Use `runtime/trace.Log` instead. | |
| Even if you're just trying to create a proof-of-concept for a low-frequency | |
| event, `runtime/trace.Log` will probably be easier overall if you can make | |
| it work. | |
| Consider a trace experiment if: | |
| - The volume of new trace events will be relatively high, and so the events | |
| would benefit from a more compact representation (creating new tables to | |
| deduplicate data, taking advantage of the varint representation, etc.). | |
| - It's not safe to call `runtime/trace.Log` (or its runtime equivalent) in | |
| the contexts you want to generate an event (for example, for events about | |
| timers). | |
| ## Defining a new experiment | |
| To define a new experiment, modify `internal/trace/tracev2` to define a | |
| new `Experiment` enum value. | |
| An experiment consists of two parts: timed events and experimental batches. | |
| Timed events are events like any other and follow the same format. | |
| They are easier to order and require less work to make use of. | |
| Experimental batches are essentially bags of bytes that correspond to | |
| an entire trace generation. | |
| What they contain and how they're interpreted is totally up to you, but | |
| they're most often useful for tables that your other events can refer into. | |
| For example, the AllocFree experiment uses them to store type information | |
| that allocation events can refer to. | |
| ### Defining new events | |
| 1. Define your new experiment event types (by convention, experimental events | |
| types start at ID 127, so look for the `const` block defining events | |
| starting there). | |
| 2. Describe your new events in `specs`. | |
| Use the documentation for `Spec` to write your new specs, and check your | |
| work by running the tests in the `internal/trace/tracev2` package. | |
| If you wish for your event argument to be interpreted in a particular | |
| way, follow the naming convention in | |
| `src/internal/trace/tracev2/spec.go`. | |
| For example, if you intend to emit a string argument, make sure the | |
| argument name has the suffix `string`. | |
| 3. Add ordering and validation logic for your new events to | |
| `src/internal/trace/order.go` by listing handlers for those events in | |
| the `orderingDispatch` table. | |
| If your events are always emitted in a regular user goroutine context, | |
| then the handler should be trivial and just validate the scheduling | |
| context to match userGoReqs. | |
| If it's more complicated, see `(*ordering).advanceAllocFree` for a | |
| slightly more complicated example that handles events from a larger | |
| variety of execution environments. | |
| If you need to encode a partial ordering, look toward the scheduler | |
| events (names beginning with `Go`) or just ask someone for help. | |
| 4. Add your new events to the `tracev2Type2Kind` table in | |
| `src/internal/trace/event.go`. | |
| ## Emitting data | |
| ### Emitting your new events | |
| 1. Define helper methods on `runtime.traceEventWriter` for emitting your | |
| events. | |
| 2. Instrument the runtime with calls to these helper methods. | |
| Make sure to call `traceAcquire` and `traceRelease` around the operation | |
| your event represents, otherwise it will not be emitted atomically with | |
| that operation completing, resulting in a potentially misleading trace. | |
| ### Emitting experimental batches | |
| To emit experimental batches, use the `runtime.unsafeTraceExpWriter` to | |
| write experimental batches associated with your experiment. | |
| Heed the warnings and make sure that while you write them, the trace | |
| generation cannot advance. | |
| Note that each experiment can only have one distinguishable set of | |
| batches. | |
| ## Recovering experimental data | |
| ### Recovering experimental events from the trace | |
| Experimental events will appear in the event stream as an event with the | |
| `EventExperimental` `Kind`. | |
| Use the `Experimental` method to collect the raw data inserted into the | |
| trace. | |
| It's essentially up to you to interpret the event from here. | |
| I recommend writing a thin wrapper API to present a cleaner interface if you | |
| so desire. | |
| ### Recovering experimental batches | |
| Parse out all the experimental batches from `Sync` events as they come. | |
| These experimental batches are all for the same generation as all the | |
| experimental events up until the next `Sync` event. |