2024-09-17 12:59:30 +02:00
|
|
|
# Mark events
|
2024-06-20 11:08:29 +02:00
|
|
|
|
|
|
|
The mark API allows you to add arbitrary events in a trace to mark regions of
|
|
|
|
interest while debugging or developing a new program or library. The events are
|
|
|
|
processed by the emulator to generate a timeline.
|
|
|
|
|
|
|
|
## Usage in runtime
|
|
|
|
|
|
|
|
Follow these steps to correctly use the API. Most problems will be detected in
|
|
|
|
emulation and cause a panic if you are not careful.
|
|
|
|
|
|
|
|
### Create a mark type
|
|
|
|
|
|
|
|
You can create up to 100 types of marks, each will be shown in its own Paraver
|
|
|
|
timeline. To create a new type, use the following call:
|
|
|
|
|
|
|
|
```c
|
|
|
|
void ovni_mark_type(int32_t type, long flags, const char *title);
|
|
|
|
```
|
|
|
|
|
|
|
|
The numeric value `type` must be a number between 0 and 99 (both included). The
|
|
|
|
`title` will be used to give a name to the Paraver timeline.
|
|
|
|
|
|
|
|
The default with flags set to zero, is to create a channel that can hold a
|
|
|
|
single value only (see [channels](../../dev/channels.md)). To use a stack of
|
|
|
|
values add the `OVNI_MARK_STACK` value to the flags.
|
|
|
|
|
2024-07-22 17:50:00 +02:00
|
|
|
Only one thread among all nodes needs to define a type to be available globally,
|
|
|
|
but the same type can be defined from multiple threads, as long as the same
|
|
|
|
flags and title argument are used. The idea is to avoid having to check if the
|
|
|
|
type was already defined or not.
|
|
|
|
|
2024-06-20 11:08:29 +02:00
|
|
|
### Define labels (optional)
|
|
|
|
|
|
|
|
The values that are written to the channel can have labels to display in the
|
|
|
|
Paraver timeline. The labels are optional, if not given the numeric value will
|
|
|
|
be shown in Paraver.
|
|
|
|
|
|
|
|
Use the following call to register a label for a value in a given type.
|
|
|
|
|
|
|
|
```c
|
|
|
|
void ovni_mark_label(int32_t type, int64_t value, const char *label);
|
|
|
|
```
|
|
|
|
|
2024-07-22 17:50:00 +02:00
|
|
|
A value can only have at most a single label associated. Multiple threads can
|
|
|
|
call the `ovni_mark_label()` with the same type and value as long as they use
|
|
|
|
the same label. New labels for the same type can be associated from different
|
|
|
|
threads, as long as the values are different.
|
|
|
|
|
|
|
|
All value and label pairs are combined from all threads and will be available in
|
|
|
|
the Paraver view for each type.
|
|
|
|
|
2024-06-20 11:08:29 +02:00
|
|
|
### Emit events
|
|
|
|
|
|
|
|
All mark channels begin with the default value *null*, which is not shown in
|
2024-06-20 11:32:20 +02:00
|
|
|
Paraver and will be displayed as the usual empty space. The value of the channel
|
|
|
|
can be changed over time with the following functions.
|
|
|
|
|
|
|
|
!!! warning
|
|
|
|
|
|
|
|
The value 0 is forbidden, as it is used by Paraver to represent the
|
|
|
|
"empty" state.
|
2024-06-20 11:08:29 +02:00
|
|
|
|
|
|
|
If you have used a single channel (without `OVNI_MARK_STACK`), then you must use
|
|
|
|
the following call to emit events at runtime:
|
|
|
|
|
|
|
|
```c
|
|
|
|
void ovni_mark_set(int32_t type, int64_t value);
|
|
|
|
```
|
|
|
|
|
|
|
|
It will update the value of the channel to the given `value`.
|
|
|
|
|
|
|
|
If you have used a stack channel (with `OVNI_MARK_STACK`), then you must use the
|
|
|
|
push/pop set of calls:
|
|
|
|
|
|
|
|
```c
|
|
|
|
void ovni_mark_push(int32_t type, int64_t value);
|
|
|
|
void ovni_mark_pop(int32_t type, int64_t value);
|
|
|
|
```
|
|
|
|
|
2024-06-20 11:48:31 +02:00
|
|
|
The value in the pop call must match the previous pushed value.
|
|
|
|
|
2024-09-17 12:59:30 +02:00
|
|
|
<details>
|
|
|
|
<summary>Example OmpSs-2 program</summary>
|
|
|
|
<br>
|
|
|
|
<div style="padding-left: 1em; border-left: 3px solid #ddd">
|
|
|
|
<p>
|
|
|
|
Here is a dummy program showing how to use the mark API with an OmpSs-2 program.
|
|
|
|
Notice that there is no initialization of the current thread or process, as it
|
|
|
|
already occurs inside the OmpSs-2 runtime before reaching the main.
|
|
|
|
|
|
|
|
```c
|
|
|
|
/* Build with:
|
|
|
|
* $ clang -fompss-2 -lovni dummy.c -o dummy
|
|
|
|
* Enable instrumentation in nanos6:
|
|
|
|
* $ echo 'version.instrument = "ovni"' > nanos6.toml
|
|
|
|
* Run:
|
|
|
|
* $ ./dummy
|
|
|
|
* Emulate:
|
|
|
|
* $ ovniemu ovni
|
|
|
|
* View timeline:
|
|
|
|
* $ wxparaver ovni/cpu.prv ovni/cfg/cpu/ovni/mark.cfg
|
|
|
|
*/
|
|
|
|
#include <ovni.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
enum { INDEX = 0, RUN = 1 };
|
|
|
|
|
|
|
|
static void process(int run, int i)
|
|
|
|
{
|
|
|
|
ovni_mark_push(RUN, run + 1);
|
|
|
|
ovni_mark_push(INDEX, i + 1);
|
|
|
|
usleep(10000); // Dummy operation for 10 ms
|
|
|
|
ovni_mark_pop(INDEX, i + 1);
|
|
|
|
ovni_mark_pop(RUN, run + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(void)
|
|
|
|
{
|
|
|
|
ovni_mark_type(INDEX, OVNI_MARK_STACK, "Index");
|
|
|
|
ovni_mark_type(RUN, OVNI_MARK_STACK, "Run");
|
|
|
|
|
|
|
|
for (int run = 0; run < 10; run++) {
|
|
|
|
for (int i = 0; i < 50; i++) {
|
|
|
|
#pragma oss task
|
|
|
|
process(run, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma oss taskwait
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
<!-- Images don't seem to work via markdown -->
|
|
|
|
<p>Here is the resulting timeline loaded in Paraver with the gradient color
|
|
|
|
configuration, showing the first mark type (the index):
|
|
|
|
<img style="margin-top: 1em" alt="" src="../fig/mark.png"></p>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</details>
|
|
|
|
<p></p>
|
|
|
|
|
2024-06-20 11:08:29 +02:00
|
|
|
## Usage in Paraver
|
|
|
|
|
|
|
|
Each thread holds a channel for each mark type that you have defined. The
|
|
|
|
information of the mark channels is propagated to the Paraver timeline in
|
|
|
|
Thread and CPU views.
|
|
|
|
|
|
|
|
When a thread is not *running*, the value of the mark channels is not shown in
|
|
|
|
Paraver. In the case of the CPU timeline, only the values of the running thread are
|
|
|
|
shown. If there are no running threads, nothing is shown.
|
|
|
|
|
|
|
|
Follow the next steps to create a configuration to suit your needs. You only
|
|
|
|
need to do it once, then you can save the configuration file and reuse it for
|
|
|
|
future traces.
|
|
|
|
|
|
|
|
### Filtering the type
|
|
|
|
|
|
|
|
To see a mark type, you will have to create a Paraver configuration that matches
|
|
|
|
the type that you have created. The mark `type` value gets converted into a PRV
|
|
|
|
type by adding 100 (as values from 0 to 99 are reserved).
|
|
|
|
|
|
|
|
You can use the `cpu/ovni/mark.cfg` and `thread/ovni/mark.cfg` configurations as
|
|
|
|
a starting point to create your own.
|
|
|
|
|
|
|
|
Go to "Window Properties" (the second button under "Files & Window Properties")
|
|
|
|
and then go to Filter > Events > Event type. Set Function to `=` and click the
|
|
|
|
Types value to display the `[...]` button, which will allow you to choose which
|
|
|
|
type to display.
|
|
|
|
|
|
|
|
In the "Events Selection" window, ensure that only one type is selected, and the
|
|
|
|
"Values" panel shows Function "All", to see all values for the selected type.
|
|
|
|
|
|
|
|
### Setting the title
|
|
|
|
|
|
|
|
In the "Window Properties" adjust the Name so it reflects what you are seeing.
|
|
|
|
This will be shown in the saved images, so it is good to use a proper
|
|
|
|
description.
|
|
|
|
|
|
|
|
### Configure the display method
|
|
|
|
|
|
|
|
By default, the timeline will display the values as "Code color". To switch to a
|
|
|
|
gradient or other methods, left-click in the timeline and go to "Paint As" and
|
|
|
|
select "Gradient" (or others).
|
|
|
|
|
|
|
|
You may also want to adjust the "Drawmode" which determines what happens when
|
|
|
|
there are multiple values under a given pixel. This is specially important when
|
|
|
|
you are viewing the trace with a large time range, before zooming into a given
|
|
|
|
region.
|
|
|
|
|
|
|
|
By default, the "Random not zero" mode is selected, which will select a
|
|
|
|
random value from the ones under each pixel, disregarding the occurrences of each
|
|
|
|
value. This mode will give importance to rare values, so it is usually a safe
|
|
|
|
starting point. The "Last" mode will show the last value in that pixel, which is
|
|
|
|
more or less fair, but will often hide rare values.
|
|
|
|
|
|
|
|
To change in both horizontal (Time) and in vertical (Objects) directions, go to:
|
|
|
|
left click on timeline > Drawmode > Both > Last.
|
|
|
|
|
|
|
|
### Ensure the range is good
|
|
|
|
|
|
|
|
Paraver will only display values in the timeline that are in the Semantic
|
|
|
|
range. If you see a red triangle in the lower left corner then there are values
|
|
|
|
outside the range that are not being displayed. You can click on this button to
|
|
|
|
expand the range to cover all values in the current view.
|
|
|
|
|
|
|
|
The opposite may also happen, where the range is too big for the current values.
|
|
|
|
You can also click on the same spot (even if the triangle is not shown) to
|
|
|
|
shrink the range to cover the values in the view, or go to the Window Properties
|
|
|
|
and modify the "Semantic Minimum" and "Semantic Maximum" values manually.
|
|
|
|
|
|
|
|
### Save the configuration
|
|
|
|
|
|
|
|
Once you finish configuring the timeline, save the configuration by
|
|
|
|
left-clicking the view and then "Save > Configuration...". You can use this
|
|
|
|
configuration in future traces to avoid doing these steps again.
|