ovni/doc/user/runtime/index.md

110 lines
4.3 KiB
Markdown
Raw Normal View History

# Introduction
To use *libovni* to instrument a program, follow the next instructions
carefully, or you may end up with an incomplete trace that is rejected at
emulation.
You can also generate a valid trace from your own software or hardware
directly, but be sure to follow the [trace specification](trace_spec.md).
## Initialization
To initialize libovni follow these steps in all threads:
1. **Check the version**. Call `ovni_version_check()` once before calling any
ovni function. It can be called multiple times from any thread, but only one
is required.
2024-09-17 08:05:27 +02:00
2. **Init the process**. Call `ovni_proc_init()` to initialize the process. It
can only be called **once per process** and it must be called before the
thread is initialized.
2024-09-17 08:05:27 +02:00
3. **Init the thread**. Call `ovni_thread_init()` to initialize the thread.
Multiple attempts to initialize the same thread are ignored with a warning.
The `ovni_proc_init()` arguments are as follows:
```c
void ovni_proc_init(int app, const char *loom, int pid);
```
The `app` defines the "appid" of the program, which must be a number >0. This is
useful to run multiple processes some of which run the same "app", so you can
2024-09-17 08:05:27 +02:00
tell which one is which. The `loom` argument defines the
[loom](../concepts/part-model.md#loom) name and maps the process to that
loom. It must be compose of the host name, a dot and a suffix. The PID is the
one obtained by `getpid(2)`.
The `ovni_thread_init()` function only accepts one argument, the TID as returned
by `gettid(2)`.
## Setup metadata
Once the process and thread are initialized, you can begin adding metadata to
the thread stream.
1. **Require models**. Call `ovni_thread_require()` with the required model
version before emitting events for a given model. Only required once from a
thread in a given trace.
2. **Emit loom CPUs**. Call `ovni_add_cpu()` to register each CPU in the loom. It can
be done from a single thread or multiple threads, in the latter the list of
CPUs is merged.
3. **Set the rank**. If you use MPI, call `ovni_proc_set_rank()` to register the
rank and number of ranks of the current execution. Only once per process.
## Start the execution
The current thread must switch to the "Running" state before any event can be
2024-09-17 08:05:27 +02:00
processed by the emulator. Do so by emitting a [`OHx`
event](../emulation/events.md#OHx) in the stream with the appropriate payload:
```c
static void thread_execute(int32_t cpu, int32_t ctid, uint64_t tag)
{
struct ovni_ev ev = {0};
ovni_ev_set_clock(&ev, ovni_clock_now());
ovni_ev_set_mcv(&ev, "OHx");
ovni_payload_add(&ev, (uint8_t *) &cpu, sizeof(cpu));
ovni_payload_add(&ev, (uint8_t *) &ctid, sizeof(ctid));
ovni_payload_add(&ev, (uint8_t *) &tag, sizeof(tag));
ovni_ev_emit(&ev);
}
```
The `cpu` is the logical index (not the physical ID) of the loom CPU at which
this thread will begin the execution. Use -1 if it is not known. The `ctid` and
`tag` allow you to track the exact point at which a given thread was created and
by which thread but they are not relevant for the first thread, so they can be
set to -1.
## Emit events
After this point you can emit any other event from this thread. Use the
`ovni_ev_*` set of functions to create and emit events. Notice that all events
are refer to the current thread that emits them.
If you need to store metadata information, use the `ovni_attr_*` set of
functions. The metadata is stored in disk by `ovni_attr_fluch()` and when the
thread is freed by `ovni_thread_free()`.
Attempting to emit events or writing metadata without having a thread
initialized will cause your program to abort.
## Finishing the execution
To finalize the execution **every thread** must perform the following steps,
otherwise the trace **will be rejected**.
1. **End the current thread**. Emit a [`OHe` event](../emulation/events.md#OHe) to inform the current thread ends.
2. **Flush the buffer**. Call `ovni_flush()` to be sure all events are written
to disk.
3. **Free the thread**. Call `ovni_thread_free()` to complete the stream and
free the memory used by the buffer.
4. **Finish the process**. If this is the last thread, call `ovni_proc_fini()`
to set the process state to finished.
If a thread fails to perform these steps, the complete trace will be rejected by
the emulator as it cannot guarantee the trace to be consistent.