Compare commits
No commits in common. "148aaa71a162e255655eb56f6baad1877f1bf2e4" and "bba46ac2003c6504fdf39a8802dae38935aa3f18" have entirely different histories.
148aaa71a1
...
bba46ac200
@ -13,8 +13,9 @@ The ovni project implements a fast instrumentation library that records
|
|||||||
small events (starting at 12 bytes) during the execution of programs to
|
small events (starting at 12 bytes) during the execution of programs to
|
||||||
later investigate how the execution happened.
|
later investigate how the execution happened.
|
||||||
|
|
||||||
|
<!-- FIXME: Add a index for runtime -->
|
||||||
The instrumentation process is split in two stages:
|
The instrumentation process is split in two stages:
|
||||||
[runtime](user/runtime/index.md)
|
[runtime](user/runtime/tracing.md)
|
||||||
tracing and [emulation](user/emulation/index.md).
|
tracing and [emulation](user/emulation/index.md).
|
||||||
|
|
||||||
During runtime, very short binary events are stored on disk which
|
During runtime, very short binary events are stored on disk which
|
||||||
|
@ -4,7 +4,7 @@ Ovni has a model to represent the hardware components as well as the software
|
|||||||
concepts like threads or processes. Each concept is considered to be a *part*.
|
concepts like threads or processes. Each concept is considered to be a *part*.
|
||||||
Here is an example diagram depicting the part hierarchy:
|
Here is an example diagram depicting the part hierarchy:
|
||||||
|
|
||||||
![Part model](part-model.svg)
|
![lalala](part-model.svg "foo bar")
|
||||||
|
|
||||||
Notice how a loom can restrict the CPUs of the node to its child processes.
|
Notice how a loom can restrict the CPUs of the node to its child processes.
|
||||||
|
|
||||||
|
72
doc/user/concepts/trace-model.md
Normal file
72
doc/user/concepts/trace-model.md
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
# Trace model
|
||||||
|
|
||||||
|
An event model is composed by a group of runtime events
|
||||||
|
|
||||||
|
## Trace
|
||||||
|
|
||||||
|
The information generated by a program or later processed by other ovni tools is
|
||||||
|
known as a trace. A runtime trace stores the information as-is in disk from a
|
||||||
|
program execution. While a emulation trace is generated from the runtime trace
|
||||||
|
for visualization with Paraver.
|
||||||
|
|
||||||
|
All the information is always stored inside the same directory, by default
|
||||||
|
`ovni/`, which is known as the trace directory.
|
||||||
|
|
||||||
|
## Event
|
||||||
|
|
||||||
|
An event is a point in time that has some information associated. Events written
|
||||||
|
at runtime by libovni have at MCV, a clock and a optional payload. The list of
|
||||||
|
all events recognized by the emulator can be found [here](../emulation/events.md).
|
||||||
|
|
||||||
|
## State
|
||||||
|
|
||||||
|
A state is a discrete value that can change over time based on the events the
|
||||||
|
emulator receives. Usually a single event causes a single state change, which is
|
||||||
|
then written to the Paraver traces. An example is the thread state, which can
|
||||||
|
change over time based on the events `OH*` that indicate a state transition
|
||||||
|
of the current thread.
|
||||||
|
|
||||||
|
## MCV
|
||||||
|
|
||||||
|
The MCV acronym is short of Model-Class-Value, which is a three character (byte)
|
||||||
|
identification for events.
|
||||||
|
|
||||||
|
## Clock
|
||||||
|
|
||||||
|
A clock is a 64 bit counter, which counts the number of nanoseconds from an
|
||||||
|
arbitrary point in time in the past. Each event has the value of the clock
|
||||||
|
stored inside, to indicate when that event happened. In a given trace there can
|
||||||
|
be multiple clocks which don't refer to the same point in the past and must be
|
||||||
|
corrected so they all produce an ordered sequence of events. The ovnisync
|
||||||
|
program performs this correction by measuring the difference across clocks of
|
||||||
|
different nodes.
|
||||||
|
|
||||||
|
## Event model
|
||||||
|
|
||||||
|
An event model is composed of several components:
|
||||||
|
|
||||||
|
- A set of [events](#event) all with the same model identifier in the
|
||||||
|
[MCV](#mcv)
|
||||||
|
- The emulator code that processes those events.
|
||||||
|
- A human readable name, like `ovni` or `nanos6`.
|
||||||
|
|
||||||
|
## Payload
|
||||||
|
|
||||||
|
Events may have associated additional information which is stored in the stream.
|
||||||
|
|
||||||
|
## Binary stream
|
||||||
|
|
||||||
|
A binary stream is a file named `stream.obs` (.obs stands for Ovni Binary
|
||||||
|
Stream) composed of a header and a concatenated array of events without padding.
|
||||||
|
Notice that each event may have different length.
|
||||||
|
|
||||||
|
## Stream metadata
|
||||||
|
|
||||||
|
The stream metadata is a JSON file named `stream.json` which holds information
|
||||||
|
about the stream.
|
||||||
|
|
||||||
|
## Stream
|
||||||
|
|
||||||
|
A stream is a directory which contains a binary stream and the associated stream
|
||||||
|
metadata file. Each stream is associated with a given part of a system. As of
|
||||||
|
now, libovni can only generate streams associated to [threads](part-model.md#thread).
|
@ -1,123 +0,0 @@
|
|||||||
# Trace concepts
|
|
||||||
|
|
||||||
When using libovni to generate traces or the emulator to process them, there are
|
|
||||||
several concepts to keep in mind.
|
|
||||||
|
|
||||||
## Trace elements
|
|
||||||
|
|
||||||
The information generated by a program or later processed by other ovni tools is
|
|
||||||
known as a trace. A runtime trace stores the information as-is in disk from a
|
|
||||||
program execution. While a emulation trace is generated from the runtime trace
|
|
||||||
for visualization with Paraver.
|
|
||||||
|
|
||||||
Both runtime and emulation traces are always stored inside the same directory,
|
|
||||||
by default `ovni/`, which is known as the *trace directory*.
|
|
||||||
|
|
||||||
Here are the components of a runtime trace, as generated by libovni:
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<img alt="Trace concepts" src="../trace.svg">
|
|
||||||
</p>
|
|
||||||
|
|
||||||
### Stream
|
|
||||||
|
|
||||||
A stream is a directory which contains a binary stream and the associated stream
|
|
||||||
metadata file. Each stream is associated with a given part of a system. As of
|
|
||||||
now, libovni can only generate streams associated to [threads](part-model.md#thread).
|
|
||||||
|
|
||||||
### Stream metadata
|
|
||||||
|
|
||||||
The stream metadata is a JSON file named `stream.json` which holds information
|
|
||||||
about the stream itself.
|
|
||||||
|
|
||||||
### Binary stream
|
|
||||||
|
|
||||||
A binary stream is a file named `stream.obs` (.obs stands for Ovni Binary
|
|
||||||
Stream) composed of a header and a concatenated array of events without padding.
|
|
||||||
Notice that each event may have different length.
|
|
||||||
|
|
||||||
### Event
|
|
||||||
|
|
||||||
An event is a point in time that has some information associated. Events written
|
|
||||||
at runtime by libovni have at MCV, a clock and a optional payload. The list of
|
|
||||||
all events recognized by the emulator can be found [here](../emulation/events.md).
|
|
||||||
|
|
||||||
Events can be displayed by ovnidump, which shows an explanation of what the
|
|
||||||
event means:
|
|
||||||
|
|
||||||
```txt
|
|
||||||
$ ovnidump ovni/loom.hop.nosv-u1000/proc.1121064 | grep -A 10 VTx | head
|
|
||||||
517267929632815 VTx thread.1121064 executes the task 1 with bodyid 0
|
|
||||||
517267930261672 VYc thread.1121064 creates task type 2 with label "task"
|
|
||||||
517267930875858 VTC thread.1121064 creates parallel task 2 with type 2
|
|
||||||
517267930877789 VU[ thread.1121064 starts submitting a task
|
|
||||||
517267930877990 VU] thread.1121064 stops submitting a task
|
|
||||||
517267930878098 VTC thread.1121064 creates parallel task 3 with type 2
|
|
||||||
517267930878196 VU[ thread.1121064 starts submitting a task
|
|
||||||
517267930878349 VU] thread.1121064 stops submitting a task
|
|
||||||
517267930878432 VTC thread.1121064 creates parallel task 4 with type 2
|
|
||||||
517267930878494 VU[ thread.1121064 starts submitting a task
|
|
||||||
```
|
|
||||||
|
|
||||||
There are two types or events: normal and jumbo events, the latter can hold
|
|
||||||
large attached payloads.
|
|
||||||
|
|
||||||
### MCV
|
|
||||||
|
|
||||||
The MCV acronym is the abbreviation of Model-Class-Value, which are a three
|
|
||||||
characters that identify any event. The MCV is shown in the ovnitop and ovnidump
|
|
||||||
tools and allows easy filtering with grep, for a single or related events:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ovnitop ovni | grep VT
|
|
||||||
VTe 20002
|
|
||||||
VTx 20002
|
|
||||||
VTC 200
|
|
||||||
VTc 2
|
|
||||||
VTp 1
|
|
||||||
VTr 1
|
|
||||||
```
|
|
||||||
|
|
||||||
### Clock
|
|
||||||
|
|
||||||
A clock is a 64 bit counter, which counts the number of nanoseconds from an
|
|
||||||
arbitrary point in time in the past. Each event has the value of the clock
|
|
||||||
stored inside, to indicate when that event happened. In a given trace there can
|
|
||||||
be multiple clocks which don't refer to the same point in the past and must be
|
|
||||||
corrected so they all produce an ordered sequence of events. The ovnisync
|
|
||||||
program performs this correction by measuring the difference across clocks of
|
|
||||||
different nodes.
|
|
||||||
|
|
||||||
### Payload
|
|
||||||
|
|
||||||
Events may have associated additional information which is stored in the stream.
|
|
||||||
Normal events can hold up to 16 bytes, otherwise the jumbo events must be used
|
|
||||||
to hold additional payload.
|
|
||||||
|
|
||||||
## Other related concepts
|
|
||||||
|
|
||||||
Apart from the trace itself, there are other concepts to keep in mind when the
|
|
||||||
trace is being processed by the emulator.
|
|
||||||
|
|
||||||
### Event model
|
|
||||||
|
|
||||||
Each event belongs to an event model, as identified by the model character in
|
|
||||||
the MCV. An event model is composed of several components:
|
|
||||||
|
|
||||||
- A set of [events](#event) all with the same model identifier in the
|
|
||||||
[MCV](#mcv)
|
|
||||||
- The emulator code that processes those events.
|
|
||||||
- A human readable name, like `ovni` or `nanos6`.
|
|
||||||
- A semantic version.
|
|
||||||
|
|
||||||
### State
|
|
||||||
|
|
||||||
A state is a discrete value that can change over time based on the events the
|
|
||||||
emulator receives. Usually a single event causes a single state change, which is
|
|
||||||
then written to the Paraver traces. An example is the thread state, which can
|
|
||||||
change over time based on the events `OH*` that indicate a state transition
|
|
||||||
of the current thread.
|
|
||||||
|
|
||||||
In contrast with an event, states have a duration associated which can usually
|
|
||||||
be observed in Paraver. Notice that the trace only contains events, the states
|
|
||||||
are computed at emulation.
|
|
@ -1,474 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
width="116.41666mm"
|
|
||||||
height="105.83334mm"
|
|
||||||
viewBox="0 0 116.41666 105.83334"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1"
|
|
||||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
|
|
||||||
sodipodi:docname="trace.svg"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg">
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#999999"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:showpageshadow="0"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pagecheckerboard="0"
|
|
||||||
inkscape:deskcolor="#d1d1d1"
|
|
||||||
inkscape:document-units="mm"
|
|
||||||
showgrid="true"
|
|
||||||
inkscape:zoom="1.4609989"
|
|
||||||
inkscape:cx="248.80238"
|
|
||||||
inkscape:cy="199.17879"
|
|
||||||
inkscape:window-width="1920"
|
|
||||||
inkscape:window-height="1031"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="24"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="layer1">
|
|
||||||
<inkscape:grid
|
|
||||||
id="grid1"
|
|
||||||
units="px"
|
|
||||||
originx="-39.687498"
|
|
||||||
originy="-15.875"
|
|
||||||
spacingx="0.26458333"
|
|
||||||
spacingy="0.26458334"
|
|
||||||
empcolor="#7a7aff"
|
|
||||||
empopacity="0.25098039"
|
|
||||||
color="#6a6aff"
|
|
||||||
opacity="0.1254902"
|
|
||||||
empspacing="5"
|
|
||||||
dotted="false"
|
|
||||||
gridanglex="30"
|
|
||||||
gridanglez="30"
|
|
||||||
visible="true" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<defs
|
|
||||||
id="defs1">
|
|
||||||
<rect
|
|
||||||
x="45"
|
|
||||||
y="370"
|
|
||||||
width="209.99998"
|
|
||||||
height="35"
|
|
||||||
id="rect15" />
|
|
||||||
</defs>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(-39.687498,-15.875)">
|
|
||||||
<g
|
|
||||||
id="g59"
|
|
||||||
transform="translate(5.5781353,-0.74017783)"
|
|
||||||
style="stroke-width:0.15875;stroke-dasharray:none">
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="100.23113"
|
|
||||||
y="24.896034"
|
|
||||||
id="text22"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan22"
|
|
||||||
style="text-align:center;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="100.23113"
|
|
||||||
y="24.896034">Trace</tspan></text>
|
|
||||||
<rect
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:0.15875;stroke-linecap:square;stroke-dasharray:none"
|
|
||||||
id="rect32"
|
|
||||||
width="15.875"
|
|
||||||
height="7.9375005"
|
|
||||||
x="92.281235"
|
|
||||||
y="19.4142" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g57"
|
|
||||||
transform="translate(-0.84260657,-0.98969722)"
|
|
||||||
style="stroke-width:0.15875;stroke-dasharray:none">
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="106.39689"
|
|
||||||
y="46.186943"
|
|
||||||
id="text24"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan24"
|
|
||||||
style="text-align:center;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="106.39689"
|
|
||||||
y="46.186943">Stream</tspan></text>
|
|
||||||
<rect
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:0.15875;stroke-linecap:square;stroke-dasharray:none"
|
|
||||||
id="rect33"
|
|
||||||
width="21.166666"
|
|
||||||
height="7.9375019"
|
|
||||||
x="96.092606"
|
|
||||||
y="40.6772" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g56"
|
|
||||||
transform="translate(0.32292488,-0.89336269)"
|
|
||||||
style="stroke-width:0.15875;stroke-dasharray:none">
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="78.773026"
|
|
||||||
y="46.090603"
|
|
||||||
id="text23"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan23"
|
|
||||||
style="text-align:center;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="78.773026"
|
|
||||||
y="46.090603">Stream</tspan></text>
|
|
||||||
<rect
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:0.15875;stroke-linecap:square;stroke-dasharray:none"
|
|
||||||
id="rect34"
|
|
||||||
width="21.166666"
|
|
||||||
height="7.9375"
|
|
||||||
x="68.468742"
|
|
||||||
y="40.580864" />
|
|
||||||
</g>
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.15875;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="M 100.80665,26.611522 84.365216,39.687501"
|
|
||||||
id="path35"
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:connection-start="#rect32"
|
|
||||||
inkscape:connection-end="#rect34" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.15875;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 105.80376,26.611522 0.0227,13.075981"
|
|
||||||
id="path36"
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:connection-start="#rect32"
|
|
||||||
inkscape:connection-end="#rect33" />
|
|
||||||
<g
|
|
||||||
id="g54"
|
|
||||||
style="stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
transform="translate(-0.99999828,-3.5391978)">
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="58.792854"
|
|
||||||
y="72.586143"
|
|
||||||
id="text25"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan25"
|
|
||||||
style="text-align:center;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="58.792854"
|
|
||||||
y="72.586143">Metadata</tspan></text>
|
|
||||||
<rect
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:0.15875;stroke-linecap:square;stroke-dasharray:none"
|
|
||||||
id="rect36"
|
|
||||||
width="26.458336"
|
|
||||||
height="7.9375"
|
|
||||||
x="45.979164"
|
|
||||||
y="67.0392" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g55"
|
|
||||||
style="stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
transform="translate(-0.99999828,-3.5391978)">
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="97.157433"
|
|
||||||
y="72.175835"
|
|
||||||
id="text26"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan26"
|
|
||||||
style="text-align:center;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="97.157433"
|
|
||||||
y="72.175835">Binary stream</tspan></text>
|
|
||||||
<rect
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:0.15875;stroke-linecap:square;stroke-dasharray:none"
|
|
||||||
id="rect37"
|
|
||||||
width="34.395832"
|
|
||||||
height="7.9375"
|
|
||||||
x="80.374992"
|
|
||||||
y="67.0392" />
|
|
||||||
</g>
|
|
||||||
<rect
|
|
||||||
style="stroke-width:0.15875;stroke-dasharray:none;fill:none;stroke:none;stroke-linecap:square"
|
|
||||||
id="rect60"
|
|
||||||
width="116.41666"
|
|
||||||
height="105.83334"
|
|
||||||
x="40.687496"
|
|
||||||
y="19.414198"
|
|
||||||
inkscape:label="background"
|
|
||||||
transform="translate(-0.99999735,-3.5391979)" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.15875;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="M 75.847223,47.625001 61.736111,63.500002"
|
|
||||||
id="path37"
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:connection-start="#rect34"
|
|
||||||
inkscape:connection-end="#rect36" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.15875;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="M 82.241318,47.625001 93.706592,63.500002"
|
|
||||||
id="path38"
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:connection-start="#rect34"
|
|
||||||
inkscape:connection-end="#rect37" />
|
|
||||||
<g
|
|
||||||
id="g53"
|
|
||||||
style="stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
transform="translate(-8.2507438,-3.0742007)">
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="62.074863"
|
|
||||||
y="95.933655"
|
|
||||||
id="text27"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan27"
|
|
||||||
style="text-align:center;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="62.074863"
|
|
||||||
y="95.933655">Header</tspan></text>
|
|
||||||
<rect
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:0.15875;stroke-linecap:square;stroke-dasharray:none"
|
|
||||||
id="rect38"
|
|
||||||
width="23.812506"
|
|
||||||
height="7.9375014"
|
|
||||||
x="50.584076"
|
|
||||||
y="90.386703" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g52"
|
|
||||||
transform="translate(-8.2507438,-3.3066989)"
|
|
||||||
style="stroke-width:0.15875;stroke-dasharray:none">
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="91.411552"
|
|
||||||
y="96.101036"
|
|
||||||
id="text28"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan28"
|
|
||||||
style="text-align:center;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="91.411552"
|
|
||||||
y="96.101036">Event</tspan></text>
|
|
||||||
<rect
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:0.15875;stroke-linecap:square;stroke-dasharray:none"
|
|
||||||
id="rect39"
|
|
||||||
width="23.812506"
|
|
||||||
height="7.9375014"
|
|
||||||
x="79.920769"
|
|
||||||
y="90.619202" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g51"
|
|
||||||
style="stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
transform="translate(-8.2507438,-3.0742007)">
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="120.28321"
|
|
||||||
y="95.868538"
|
|
||||||
id="text29"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan29"
|
|
||||||
style="text-align:center;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="120.28321"
|
|
||||||
y="95.868538">Event</tspan></text>
|
|
||||||
<rect
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:0.15875;stroke-linecap:square;stroke-dasharray:none"
|
|
||||||
id="rect40"
|
|
||||||
width="23.812506"
|
|
||||||
height="7.9375014"
|
|
||||||
x="108.79243"
|
|
||||||
y="90.386703" />
|
|
||||||
</g>
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.15875;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="M 89.517356,71.437502 61.29514,87.312503"
|
|
||||||
id="path40"
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:connection-start="#rect37"
|
|
||||||
inkscape:connection-end="#rect38" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.15875;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="M 94.406805,71.437502 85.742383,87.312503"
|
|
||||||
id="path41"
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:connection-start="#rect37"
|
|
||||||
inkscape:connection-end="#rect39" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.15875;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="M 99.218748,71.437502 109.8021,87.312503"
|
|
||||||
id="path42"
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:connection-start="#rect37"
|
|
||||||
inkscape:connection-end="#rect40" />
|
|
||||||
<g
|
|
||||||
id="g46"
|
|
||||||
transform="translate(-68.659367,2.7781237)"
|
|
||||||
style="stroke-width:0.15875;stroke-dasharray:none">
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="123.93869"
|
|
||||||
y="113.98891"
|
|
||||||
id="text30"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan30"
|
|
||||||
style="text-align:center;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="123.93869"
|
|
||||||
y="113.98891">MCV</tspan></text>
|
|
||||||
<rect
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:0.15875;stroke-linecap:square;stroke-dasharray:none"
|
|
||||||
id="rect42"
|
|
||||||
width="15.875001"
|
|
||||||
height="7.9375038"
|
|
||||||
x="116.41666"
|
|
||||||
y="108.47917" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g45"
|
|
||||||
transform="translate(-68.659367,5.4239515)"
|
|
||||||
style="stroke-width:0.15875;stroke-dasharray:none">
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="147.92894"
|
|
||||||
y="111.38029"
|
|
||||||
id="text31"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan31"
|
|
||||||
style="text-align:center;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="147.92894"
|
|
||||||
y="111.38029">Clock</tspan></text>
|
|
||||||
<rect
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:0.15875;stroke-linecap:square;stroke-dasharray:none"
|
|
||||||
id="rect43"
|
|
||||||
width="15.875001"
|
|
||||||
height="7.9375038"
|
|
||||||
x="140.22916"
|
|
||||||
y="105.83334" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g44"
|
|
||||||
transform="translate(-66.112857,13.610614)"
|
|
||||||
style="stroke-width:0.15875;stroke-dasharray:none">
|
|
||||||
<g
|
|
||||||
id="g60"
|
|
||||||
style="stroke-width:0.15875;stroke-dasharray:none">
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="172.85362"
|
|
||||||
y="102.65102"
|
|
||||||
id="text32"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan32"
|
|
||||||
style="text-align:center;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="172.85362"
|
|
||||||
y="102.65102">Payload</tspan></text>
|
|
||||||
<rect
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:0.15875;stroke-linecap:square;stroke-dasharray:none"
|
|
||||||
id="rect44"
|
|
||||||
width="23.812506"
|
|
||||||
height="7.9375014"
|
|
||||||
x="161.36285"
|
|
||||||
y="97.514389" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.15875;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="M 83.366344,95.250004 80.27399,111.2573"
|
|
||||||
id="path47"
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:connection-end="#g45" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.15875;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="M 80.082847,95.250004 60.540101,111.2573"
|
|
||||||
id="path48"
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:connection-end="#g46" />
|
|
||||||
<g
|
|
||||||
id="g58"
|
|
||||||
transform="translate(-1.9073076,-1.4153422)"
|
|
||||||
style="stroke-width:0.15875;stroke-dasharray:none">
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="132.47266"
|
|
||||||
y="46.496338"
|
|
||||||
id="text49"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan49"
|
|
||||||
style="text-align:center;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="132.47266"
|
|
||||||
y="46.496338">...</tspan></text>
|
|
||||||
<rect
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:0.15875;stroke-linecap:square;stroke-dasharray:none"
|
|
||||||
id="rect49"
|
|
||||||
width="18.619415"
|
|
||||||
height="7.9374995"
|
|
||||||
x="123.61564"
|
|
||||||
y="41.102844" />
|
|
||||||
</g>
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.15875;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 110.56031,26.611522 15.69429,13.07598"
|
|
||||||
id="path49"
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:connection-end="#rect49"
|
|
||||||
inkscape:connection-start="#rect32" />
|
|
||||||
<g
|
|
||||||
id="g50"
|
|
||||||
transform="translate(-8.2507438,-2.9293636)"
|
|
||||||
style="stroke-width:0.15875;stroke-dasharray:none">
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="149.35014"
|
|
||||||
y="95.635361"
|
|
||||||
id="text50"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan50"
|
|
||||||
style="text-align:center;text-anchor:middle;stroke-width:0.15875;stroke-dasharray:none"
|
|
||||||
x="149.35014"
|
|
||||||
y="95.635361">...</tspan></text>
|
|
||||||
<rect
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:0.15875;stroke-linecap:square;stroke-dasharray:none"
|
|
||||||
id="rect40-5"
|
|
||||||
width="23.812506"
|
|
||||||
height="7.9375014"
|
|
||||||
x="137.89658"
|
|
||||||
y="90.241867" />
|
|
||||||
</g>
|
|
||||||
<path
|
|
||||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.15875;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 104.06944,71.437502 29.98612,15.875001"
|
|
||||||
id="path50"
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:connection-start="#rect37"
|
|
||||||
inkscape:connection-end="#g50" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.15875;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="M 87.506274,95.250004 103.22625,111.125"
|
|
||||||
id="path60"
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:connection-start="#g52"
|
|
||||||
inkscape:connection-end="#g44" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 19 KiB |
@ -1,56 +0,0 @@
|
|||||||
# Environment variables
|
|
||||||
|
|
||||||
Some environment variables can be used to adjust settings during the execution
|
|
||||||
of libovni, they all begin with the `OVNI_` prefix. Be sure that all threads of
|
|
||||||
the same node use the same environment variables.
|
|
||||||
|
|
||||||
## OVNI_TMPDIR
|
|
||||||
|
|
||||||
During the execution of your program, a per-thread buffer is kept where the new
|
|
||||||
events are being recorded. When this buffer is full, it is written to disk and
|
|
||||||
emptied, an operation known as flush. This may take a while depending on the
|
|
||||||
underliying filesystem.
|
|
||||||
|
|
||||||
Keep in mind that the thread will be blocked until the flush ends, so if your
|
|
||||||
filesystem is slow it would interrupt the execution of your program for a long
|
|
||||||
time. It is advisable to use the fastest filesystem available (see the tmpfs(5)
|
|
||||||
and df(1) manual pages).
|
|
||||||
|
|
||||||
You can select a temporary trace directory where the buffers will be flushed
|
|
||||||
during the execution by setting the environment variable `OVNI_TMPDIR`. The last
|
|
||||||
directory will be created if doesn't exist. In that case, as soon as a process
|
|
||||||
calls `ovni_proc_fini()`, the traces of all its threads will be moved to the
|
|
||||||
final directory at `$PWD/ovni`. Example:
|
|
||||||
|
|
||||||
OVNI_TMPDIR=$(mktemp -u /dev/shm/ovni.XXXXXX) srun ./your-app
|
|
||||||
|
|
||||||
To test the different filesystem speeds, you can use hyperfine and dd. Take a
|
|
||||||
closer look at the max time:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ hyperfine 'dd if=/dev/zero of=/gpfs/projects/bsc15/bsc15557/kk bs=2M count=10'
|
|
||||||
Benchmark 1: dd if=/dev/zero of=/gpfs/projects/bsc15/bsc15557/kk bs=2M count=10
|
|
||||||
Time (mean ± σ): 71.7 ms ± 130.4 ms [User: 0.8 ms, System: 10.2 ms]
|
|
||||||
Range (min … max): 14.7 ms … 1113.2 ms 162 runs
|
|
||||||
|
|
||||||
Warning: Statistical outliers were detected. Consider re-running this
|
|
||||||
benchmark on a quiet PC without any interferences from other programs. It
|
|
||||||
might help to use the '--warmup' or '--prepare' options.
|
|
||||||
|
|
||||||
$ hyperfine 'dd if=/dev/zero of=/tmp/kk bs=2M count=10'
|
|
||||||
Benchmark 1: dd if=/dev/zero of=/tmp/kk bs=2M count=10
|
|
||||||
Time (mean ± σ): 56.2 ms ± 5.7 ms [User: 0.6 ms, System: 14.8 ms]
|
|
||||||
Range (min … max): 45.8 ms … 77.8 ms 63 runs
|
|
||||||
|
|
||||||
$ hyperfine 'dd if=/dev/zero of=/dev/shm/kk bs=2M count=10'
|
|
||||||
Benchmark 1: dd if=/dev/zero of=/dev/shm/kk bs=2M count=10
|
|
||||||
Time (mean ± σ): 11.4 ms ± 0.4 ms [User: 0.5 ms, System: 11.1 ms]
|
|
||||||
Range (min … max): 9.7 ms … 12.5 ms 269 runs
|
|
||||||
```
|
|
||||||
|
|
||||||
## OVNI_TRACEDIR
|
|
||||||
|
|
||||||
By default, the runtime trace will be placed in the `ovni` directory, inside the
|
|
||||||
working directory. You can specify a different location to place the trace by
|
|
||||||
setting the `OVNI_TRACEDIR` environment variable. It accepts a relative or
|
|
||||||
absolute path, which will be created if it doesn't exist.
|
|
Binary file not shown.
Before Width: | Height: | Size: 6.6 KiB |
@ -15,12 +15,14 @@ To initialize libovni follow these steps in all threads:
|
|||||||
ovni function. It can be called multiple times from any thread, but only one
|
ovni function. It can be called multiple times from any thread, but only one
|
||||||
is required.
|
is required.
|
||||||
|
|
||||||
2. **Init the process**. Call `ovni_proc_init()` to initialize the process. It
|
2. **Init the process**. Call `ovni_proc_init()` to initialize the process when
|
||||||
can only be called **once per process** and it must be called before the
|
a new process begins the execution. It can only be called **once per
|
||||||
thread is initialized.
|
process** and it must be called before the thread is initialized.
|
||||||
|
|
||||||
3. **Init the thread**. Call `ovni_thread_init()` to initialize the thread.
|
3. **Init the thread**. Call `ovni_thread_init()` when a new thread begins the
|
||||||
Multiple attempts to initialize the same thread are ignored with a warning.
|
execution (including the main process thread after the process is
|
||||||
|
initialized). Multiple attempts to initialize the thread are ignored with a
|
||||||
|
warning.
|
||||||
|
|
||||||
The `ovni_proc_init()` arguments are as follows:
|
The `ovni_proc_init()` arguments are as follows:
|
||||||
|
|
||||||
@ -30,8 +32,8 @@ 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
|
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
|
useful to run multiple processes some of which run the same "app", so you can
|
||||||
tell which one is which. The `loom` argument defines the
|
tell which one is which. The `loom` defines the
|
||||||
[loom](../concepts/part-model.md#loom) name and maps the process to that
|
[loom](../concepts/part-model.md#loom) name and assignes the process to that
|
||||||
loom. It must be compose of the host name, a dot and a suffix. The PID is the
|
loom. It must be compose of the host name, a dot and a suffix. The PID is the
|
||||||
one obtained by `getpid(2)`.
|
one obtained by `getpid(2)`.
|
||||||
|
|
||||||
@ -57,8 +59,8 @@ the thread stream.
|
|||||||
## Start the execution
|
## Start the execution
|
||||||
|
|
||||||
The current thread must switch to the "Running" state before any event can be
|
The current thread must switch to the "Running" state before any event can be
|
||||||
processed by the emulator. Do so by emitting a [`OHx`
|
processed by the emulator. Do so by emitting a `OHx` event in the stream with
|
||||||
event](../emulation/events.md#OHx) in the stream with the appropriate payload:
|
the appropriate payload:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
static void thread_execute(int32_t cpu, int32_t ctid, uint64_t tag)
|
static void thread_execute(int32_t cpu, int32_t ctid, uint64_t tag)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Mark events
|
# Mark API
|
||||||
|
|
||||||
The mark API allows you to add arbitrary events in a trace to mark regions of
|
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
|
interest while debugging or developing a new program or library. The events are
|
||||||
@ -80,68 +80,6 @@ void ovni_mark_pop(int32_t type, int64_t value);
|
|||||||
|
|
||||||
The value in the pop call must match the previous pushed value.
|
The value in the pop call must match the previous pushed value.
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
## Usage in Paraver
|
## Usage in Paraver
|
||||||
|
|
||||||
Each thread holds a channel for each mark type that you have defined. The
|
Each thread holds a channel for each mark type that you have defined. The
|
||||||
|
@ -1,149 +1,127 @@
|
|||||||
# Trace specification v3
|
# Trace specification
|
||||||
|
|
||||||
!!! Important
|
!!! Important
|
||||||
|
|
||||||
This document refers to the trace specification for
|
This document refers to the trace specification for
|
||||||
the version 3
|
the version 2
|
||||||
|
|
||||||
The ovni instrumentation library libovni stores the information
|
The ovni instrumentation library stores the information collected in a
|
||||||
collected in a runtime trace following the specification of this document.
|
trace following the specification of this document.
|
||||||
|
|
||||||
## Structure
|
|
||||||
|
|
||||||
An ovni runtime trace (or simply, a trace) is composed of one or more
|
|
||||||
[streams](../concepts/trace.md#stream), which are directories containing
|
|
||||||
two mandatory files:
|
|
||||||
|
|
||||||
- `stream.json` the stream metadata in JSON format.
|
|
||||||
- `stream.obs` the binary stream with events.
|
|
||||||
|
|
||||||
Each stream is assigned to a single *part* in the [part
|
|
||||||
model](../concepts/part-model.md), usually assigned to a given thread.
|
|
||||||
|
|
||||||
There are no imposed rules on how to organize the several streams into
|
|
||||||
directories, but libovni uses the following approach for thread streams:
|
|
||||||
|
|
||||||
The complete trace is stored in a top-level directory named `ovni`.
|
The complete trace is stored in a top-level directory named `ovni`.
|
||||||
Inside this directory you will find the loom directories. The name of
|
Inside this directory you will find the loom directories with the prefix
|
||||||
the loom directory is built from the `loom` parameter of `ovni_proc_init()`,
|
`loom.`. The name of the loom is built from the `loom` parameter of
|
||||||
prefixing it with `loom.`.
|
`ovni_proc_init()`, prefixing it with `loom.`.
|
||||||
|
|
||||||
Each loom directory contains one directory per process of that loom. The
|
Each loom directory contains one directory per process of that loom. The
|
||||||
name is composed of the `proc.` prefix and the PID of the process
|
name is composed of the `proc.` prefix and the PID of the process
|
||||||
specified in the `pid` argument to `ovni_proc_init()`.
|
specified in the `pid` argument to `ovni_proc_init()`.
|
||||||
|
|
||||||
Inside each process there is one directory for each thread, composed by
|
Each process directory contains:
|
||||||
the `thread.` prefix and the TID, which are the streams. The files
|
|
||||||
`stream.json` and `stream.obs` reside inside. Example:
|
|
||||||
|
|
||||||
```
|
- The process metadata file `metadata.json`.
|
||||||
ovni/loom.mio.nosv-u1000/proc.89719/thread.89719/stream.json
|
- The thread streams, composed of:
|
||||||
ovni/loom.mio.nosv-u1000/proc.89719/thread.89719/stream.obs
|
- The binary stream like `thread.123.obs`
|
||||||
```
|
- The thread metadata like `thread.123.json`
|
||||||
|
|
||||||
This structure prevents collisions among threads with the same TID among nodes,
|
## Process metadata
|
||||||
while allowing dumping events from a single thread, process or loom with
|
|
||||||
ovnidump.
|
|
||||||
|
|
||||||
## Stream metadata
|
!!! Important
|
||||||
|
|
||||||
The `stream.json` metadata file contains information about the part that
|
Process metadata has version 2
|
||||||
the stream is assigned to. This is generally used to determine the
|
|
||||||
hierarchy of the part model.
|
|
||||||
|
|
||||||
The JSON must be an object (dictionary) with the following mandatory
|
The process metadata file contains important information about the trace
|
||||||
keys:
|
that is invariant during the complete execution, and generally is
|
||||||
|
required to be available prior to processing the events in the trace.
|
||||||
|
|
||||||
|
The metadata is stored in the JSON file `metadata.json` inside each
|
||||||
|
process directory and contains the following keys:
|
||||||
|
|
||||||
- `version`: a number specifying the version of the metadata format.
|
- `version`: a number specifying the version of the metadata format.
|
||||||
Must have the value 3 for this version.
|
Must have the value 2 for this version.
|
||||||
|
- `app_id`: the application ID, used to distinguish between applications
|
||||||
|
running on the same loom.
|
||||||
|
- `rank`: the rank of the MPI process (optional).
|
||||||
|
- `nranks`: number of total MPI processes (optional).
|
||||||
|
- `cpus`: the array of $`N_c`$ CPUs available in the loom. Only one
|
||||||
|
process in the loom must contain this mandatory key. Each element is a
|
||||||
|
dictionary with the keys:
|
||||||
|
- `index`: containing the logical CPU index from 0 to $`N_c - 1`$.
|
||||||
|
- `phyid`: the number of the CPU as given by the operating system
|
||||||
|
(which can exceed $`N_c`$).
|
||||||
|
|
||||||
The rest of information is stored for each model.
|
Here is an example of the `metadata.json` file:
|
||||||
|
|
||||||
In particular, the `ovni` model enforces the use of:
|
```
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"app_id": 1,
|
||||||
|
"rank": 0,
|
||||||
|
"nranks": 4,
|
||||||
|
"cpus": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"phyid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 1,
|
||||||
|
"phyid": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 2,
|
||||||
|
"phyid": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 3,
|
||||||
|
"phyid": 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
- `ovni.part`: the type of part this stream is assigned to, usually
|
## Thread metadata
|
||||||
`thread`.
|
|
||||||
- `ovni.require`: a dictionary of model name and version which will
|
|
||||||
determine which models are enabled at emulation and the required
|
|
||||||
version.
|
|
||||||
- `ovni.finished`: must be 1 to ensure the stream is complete (mandatory
|
|
||||||
in all streams).
|
|
||||||
|
|
||||||
### Thread stream metadata
|
!!! Important
|
||||||
|
|
||||||
For `thread` streams, the following attributes are used.
|
Thread metadata has version 2
|
||||||
|
|
||||||
- `ovni.tid`: the TID of the thread (mandatory, per-thread).
|
The thread metadata stores constant information per thread, like the
|
||||||
- `ovni.pid`: the PID of the process that the thread belongs to (mandatory, per-thread).
|
process metadata. The information is stored in a dictionary, where the
|
||||||
- `ovni.app_id`: the application ID of the process (optional, per-process).
|
name of the emulation models are used as keys. In particular, the
|
||||||
- `ovni.rank`: the rank of the MPI process (optional, per-process).
|
libovni library writes information in the "ovni" key, such as the
|
||||||
- `ovni.nranks`: number of total MPI processes (optional, per-process).
|
model requirements, and other information like the version of libovni
|
||||||
- `ovni.loom`: the name of the loom that the process belongs to (mandatory, per-process).
|
used. Example:
|
||||||
- `ovni.loom_cpus`: the array of N CPUs available in the loom
|
|
||||||
(mandatory, per-loom). Each element is a dictionary with the keys:
|
|
||||||
- `index`: containing the logical CPU index from 0 to N - 1.
|
|
||||||
- `phyid`: the number of the CPU as given by the operating system
|
|
||||||
(which can exceed N).
|
|
||||||
|
|
||||||
Notice that some attributes don't need to be present in all thread
|
|
||||||
streams. For example, per-process requires that at least one thread
|
|
||||||
contains the attribute for each process. Similarly, per-loom requires
|
|
||||||
that at least one thread of the loom emits the attribute.
|
|
||||||
|
|
||||||
The final attribute value will be computed by merging all the values from the
|
|
||||||
children metadata. Simple values like numbers or strings must match exactly if
|
|
||||||
they appear duplicated, arrays are appended.
|
|
||||||
|
|
||||||
Other attributes can be used for other models.
|
|
||||||
|
|
||||||
Here is an example of the `stream.json` file for a thread of a nOS-V
|
|
||||||
program:
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"version": 3,
|
"version": 2,
|
||||||
"ovni": {
|
"ovni": {
|
||||||
"lib": {
|
"lib": {
|
||||||
"version": "1.10.0",
|
"version": "1.4.0",
|
||||||
"commit": "dirty"
|
"commit": "unknown"
|
||||||
},
|
},
|
||||||
"part": "thread",
|
|
||||||
"tid": 89719,
|
|
||||||
"pid": 89719,
|
|
||||||
"loom": "mio.nosv-u1000",
|
|
||||||
"app_id": 1,
|
|
||||||
"require": {
|
"require": {
|
||||||
"ovni": "1.1.0",
|
"ovni": "1.0.0"
|
||||||
"nosv": "2.3.0"
|
}
|
||||||
},
|
|
||||||
"loom_cpus": [
|
|
||||||
{ "index": 0, "phyid": 0 },
|
|
||||||
{ "index": 1, "phyid": 1 },
|
|
||||||
{ "index": 2, "phyid": 2 },
|
|
||||||
{ "index": 3, "phyid": 3 }
|
|
||||||
],
|
|
||||||
"finished": 1
|
|
||||||
},
|
|
||||||
"nosv": {
|
|
||||||
"can_breakdown": false,
|
|
||||||
"lib_version": "2.3.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Binary stream
|
The metadata is written to disk when the thread is first initialized
|
||||||
|
and when the thread finishes.
|
||||||
|
|
||||||
|
## Thread binary streams
|
||||||
|
|
||||||
!!! Important
|
!!! Important
|
||||||
|
|
||||||
Binary streams have version 1
|
Thread binary stream has version 1
|
||||||
|
|
||||||
A binary stream is a binary file named `stream.obs` that contains a
|
Streams are a binary files that contains a succession of events with
|
||||||
succession of events with monotonically increasing clock values. They
|
monotonically increasing clock values. Streams have a small header and
|
||||||
have a small header and the variable size events just after the header.
|
the variable size events just after the header.
|
||||||
|
|
||||||
The header contains the magic 4 bytes of "ovni" and a version number of
|
The header contains the magic 4 bytes of "ovni" and a version number of
|
||||||
4 bytes too. Here is a figure of the data stored in disk on a little
|
4 bytes too. Here is a figure of the data stored in disk:
|
||||||
endian machine:
|
|
||||||
|
|
||||||
![Stream](fig/stream.svg)
|
![Stream](fig/stream.svg)
|
||||||
|
|
||||||
@ -167,7 +145,7 @@ payload:
|
|||||||
- Normal events: with a payload up to 16 bytes
|
- Normal events: with a payload up to 16 bytes
|
||||||
- Jumbo events: with a payload up to $`2^{32}`$ bytes
|
- Jumbo events: with a payload up to $`2^{32}`$ bytes
|
||||||
|
|
||||||
### Normal events
|
## Normal events
|
||||||
|
|
||||||
The normal events are composed of:
|
The normal events are composed of:
|
||||||
|
|
||||||
@ -200,7 +178,7 @@ In the following figure you can see each field annotated:
|
|||||||
|
|
||||||
![Normal event with payload content](fig/event-normal-payload.svg)
|
![Normal event with payload content](fig/event-normal-payload.svg)
|
||||||
|
|
||||||
### Jumbo events
|
## Jumbo events
|
||||||
|
|
||||||
The jumbo events are just like normal events but they can hold large
|
The jumbo events are just like normal events but they can hold large
|
||||||
data. The size of the jumbo data is stored as a 32 bits integer as a
|
data. The size of the jumbo data is stored as a 32 bits integer as a
|
||||||
@ -225,10 +203,10 @@ In the following figure you can see each field annotated:
|
|||||||
|
|
||||||
![Jumbo event](fig/event-jumbo.svg)
|
![Jumbo event](fig/event-jumbo.svg)
|
||||||
|
|
||||||
### Design considerations
|
## Design considerations
|
||||||
|
|
||||||
The binary stream format has been designed to be very simple, so writing
|
The stream format has been designed to be very simple, so writing a
|
||||||
a parser library would take no more than 2 days for a single developer.
|
parser library would take no more than 2 days for a single developer.
|
||||||
|
|
||||||
The size of the events has been designed to be small, with 12 bytes per
|
The size of the events has been designed to be small, with 12 bytes per
|
||||||
event when no payload is used.
|
event when no payload is used.
|
||||||
@ -261,7 +239,11 @@ raw stream in binary, as the MCV codes can be read as ASCII characters:
|
|||||||
This allows a human to detect signs of corruption by visually inspecting
|
This allows a human to detect signs of corruption by visually inspecting
|
||||||
the streams.
|
the streams.
|
||||||
|
|
||||||
### Limitations
|
## Limitations
|
||||||
|
|
||||||
The streams are designed to be read only forward, as they only contain
|
The streams are designed to be read only forward, as they only contain
|
||||||
the size of each event in the header.
|
the size of each event in the header.
|
||||||
|
|
||||||
|
Currently, we only support using the threads as sources of events, using
|
||||||
|
one stream per thread. However, adding support for more streams from
|
||||||
|
multiple sources is planned for the future.
|
||||||
|
94
doc/user/runtime/tracing.md
Normal file
94
doc/user/runtime/tracing.md
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
# Tracing a new program
|
||||||
|
|
||||||
|
Read carefully this document before using libovni to instrument a new
|
||||||
|
component. There are a few rules you must follow to ensure the runtime
|
||||||
|
trace is correct.
|
||||||
|
|
||||||
|
## Trace processes and threads
|
||||||
|
|
||||||
|
- Call `ovni_version_check()` once before calling any ovni function.
|
||||||
|
|
||||||
|
- Call `ovni_proc_init()` when a new process begins the execution.
|
||||||
|
|
||||||
|
- Call `ovni_thread_init()` when a new thread begins the execution
|
||||||
|
(including the main process thread).
|
||||||
|
|
||||||
|
- Call `ovni_thread_require()` with the required model version before
|
||||||
|
emitting events for that model.
|
||||||
|
|
||||||
|
- Call `ovni_flush()` and `ovni_thread_free()` when it finishes (in that
|
||||||
|
order).
|
||||||
|
|
||||||
|
- Call `ovni_proc_fini()` when a process ends, after all threads have
|
||||||
|
finished.
|
||||||
|
|
||||||
|
You can use `ovni_ev_emit()` to record a new event. If you need more
|
||||||
|
than 16 bytes of payload, use `ovni_ev_jumbo_emit()`. See the [trace
|
||||||
|
specification](trace_spec.md) for more details.
|
||||||
|
|
||||||
|
Compile and link with libovni. When you run your program, a new
|
||||||
|
directory ovni will be created in the current directory `$PWD/ovni`
|
||||||
|
which contains the execution trace.
|
||||||
|
|
||||||
|
You can change the trace directory by defining the `OVNI_TRACEDIR`
|
||||||
|
environment variable. The envar accepts a trace directory name, a
|
||||||
|
relative path to the trace directory, or its absolute path. In the
|
||||||
|
first case, the trace directory will be created in the current
|
||||||
|
directory `$PWD`.
|
||||||
|
|
||||||
|
## Rules
|
||||||
|
|
||||||
|
Follow these rules to avoid losing events:
|
||||||
|
|
||||||
|
1. No event may be emitted until the process is initialized with
|
||||||
|
`ovni_proc_init()` and the thread with `ovni_thread_init()`.
|
||||||
|
|
||||||
|
2. When a thread ends the execution, it must call `ovni_flush()` to write the
|
||||||
|
events in the buffer to disk.
|
||||||
|
|
||||||
|
3. All threads must have flushed its buffers before calling `ovni_proc_fini()`.
|
||||||
|
|
||||||
|
## Select a fast directory
|
||||||
|
|
||||||
|
During the execution of your program, a per-thread buffer is kept where the new
|
||||||
|
events are being recorded. When this buffer is full, it is written to disk and
|
||||||
|
emptied, an operation known as flush. This may take a while depending on the
|
||||||
|
underliying filesystem.
|
||||||
|
|
||||||
|
Keep in mind that the thread will be blocked until the flush ends, so if your
|
||||||
|
filesystem is slow it would interrupt the execution of your program for a long
|
||||||
|
time. It is advisable to use the fastest filesystem available (see the tmpfs(5)
|
||||||
|
and df(1) manual pages).
|
||||||
|
|
||||||
|
You can select the trace directory where the buffers will be flushed during the
|
||||||
|
execution by setting the environment variable `OVNI_TMPDIR`. The last directory
|
||||||
|
will be created if doesn't exist. In that case, as soon as a process calls
|
||||||
|
`ovni_proc_fini()`, the traces of all its threads will be moved to the final
|
||||||
|
directory at `$PWD/ovni`. Example:
|
||||||
|
|
||||||
|
OVNI_TMPDIR=$(mktemp -u /dev/shm/ovni.XXXXXX) srun ./your-app
|
||||||
|
|
||||||
|
To test the different filesystem speeds, you can use hyperfine and dd. Take a
|
||||||
|
closer look at the max time:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ hyperfine 'dd if=/dev/zero of=/gpfs/projects/bsc15/bsc15557/kk bs=2M count=10'
|
||||||
|
Benchmark 1: dd if=/dev/zero of=/gpfs/projects/bsc15/bsc15557/kk bs=2M count=10
|
||||||
|
Time (mean ± σ): 71.7 ms ± 130.4 ms [User: 0.8 ms, System: 10.2 ms]
|
||||||
|
Range (min … max): 14.7 ms … 1113.2 ms 162 runs
|
||||||
|
|
||||||
|
Warning: Statistical outliers were detected. Consider re-running this
|
||||||
|
benchmark on a quiet PC without any interferences from other programs. It
|
||||||
|
might help to use the '--warmup' or '--prepare' options.
|
||||||
|
|
||||||
|
$ hyperfine 'dd if=/dev/zero of=/tmp/kk bs=2M count=10'
|
||||||
|
Benchmark 1: dd if=/dev/zero of=/tmp/kk bs=2M count=10
|
||||||
|
Time (mean ± σ): 56.2 ms ± 5.7 ms [User: 0.6 ms, System: 14.8 ms]
|
||||||
|
Range (min … max): 45.8 ms … 77.8 ms 63 runs
|
||||||
|
|
||||||
|
$ hyperfine 'dd if=/dev/zero of=/dev/shm/kk bs=2M count=10'
|
||||||
|
Benchmark 1: dd if=/dev/zero of=/dev/shm/kk bs=2M count=10
|
||||||
|
Time (mean ± σ): 11.4 ms ± 0.4 ms [User: 0.5 ms, System: 11.1 ms]
|
||||||
|
Range (min … max): 9.7 ms … 12.5 ms 269 runs
|
||||||
|
```
|
||||||
|
|
@ -26,10 +26,10 @@ nav:
|
|||||||
- user/installation.md
|
- user/installation.md
|
||||||
- 'Concepts':
|
- 'Concepts':
|
||||||
- user/concepts/part-model.md
|
- user/concepts/part-model.md
|
||||||
- user/concepts/trace.md
|
- user/concepts/trace-model.md
|
||||||
- 'Runtime':
|
- 'Runtime':
|
||||||
- user/runtime/index.md
|
- user/runtime/index.md
|
||||||
- user/runtime/env.md
|
- user/runtime/tracing.md
|
||||||
- user/runtime/mark.md
|
- user/runtime/mark.md
|
||||||
- user/runtime/distributed.md
|
- user/runtime/distributed.md
|
||||||
- user/runtime/kernel.md
|
- user/runtime/kernel.md
|
||||||
|
@ -105,10 +105,6 @@ trace_load(struct trace *trace, const char *tracedir)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove trailing slashes from tracedir */
|
|
||||||
path_remove_trailing(trace->tracedir);
|
|
||||||
tracedir = trace->tracedir;
|
|
||||||
|
|
||||||
/* Try to open the directory to catch permission errors */
|
/* Try to open the directory to catch permission errors */
|
||||||
DIR *dir = opendir(tracedir);
|
DIR *dir = opendir(tracedir);
|
||||||
if (dir == NULL) {
|
if (dir == NULL) {
|
||||||
|
@ -180,7 +180,7 @@ ovni_add_cpu(int index, int phyid)
|
|||||||
if (phyid < 0)
|
if (phyid < 0)
|
||||||
die("cannot use negative CPU id %d", phyid);
|
die("cannot use negative CPU id %d", phyid);
|
||||||
|
|
||||||
if (atomic_load(&rproc.st) != ST_READY)
|
if (rproc.st != ST_READY)
|
||||||
die("process not ready");
|
die("process not ready");
|
||||||
|
|
||||||
if (!rthread.ready)
|
if (!rthread.ready)
|
||||||
@ -199,7 +199,7 @@ ovni_add_cpu(int index, int phyid)
|
|||||||
void
|
void
|
||||||
ovni_proc_set_rank(int rank, int nranks)
|
ovni_proc_set_rank(int rank, int nranks)
|
||||||
{
|
{
|
||||||
if (atomic_load(&rproc.st) != ST_READY)
|
if (rproc.st != ST_READY)
|
||||||
die("process not ready");
|
die("process not ready");
|
||||||
|
|
||||||
if (!rthread.ready)
|
if (!rthread.ready)
|
||||||
@ -273,7 +273,7 @@ ovni_proc_init(int app, const char *loom, int pid)
|
|||||||
|
|
||||||
create_proc_dir(loom, pid);
|
create_proc_dir(loom, pid);
|
||||||
|
|
||||||
atomic_store(&rproc.st, ST_READY);
|
rproc.st = ST_READY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -535,7 +535,7 @@ ovni_thread_init(pid_t tid)
|
|||||||
if (tid == 0)
|
if (tid == 0)
|
||||||
die("cannot use tid=%d", tid);
|
die("cannot use tid=%d", tid);
|
||||||
|
|
||||||
if (atomic_load(&rproc.st) != ST_READY)
|
if (rproc.st != ST_READY)
|
||||||
die("process not ready");
|
die("process not ready");
|
||||||
|
|
||||||
memset(&rthread, 0, sizeof(rthread));
|
memset(&rthread, 0, sizeof(rthread));
|
||||||
@ -770,7 +770,7 @@ ovni_flush(void)
|
|||||||
if (!rthread.ready)
|
if (!rthread.ready)
|
||||||
die("thread is not initialized");
|
die("thread is not initialized");
|
||||||
|
|
||||||
if (atomic_load(&rproc.st) != ST_READY)
|
if (rproc.st != ST_READY)
|
||||||
die("process not ready");
|
die("process not ready");
|
||||||
|
|
||||||
ovni_ev_set_clock(&pre, ovni_clock_now());
|
ovni_ev_set_clock(&pre, ovni_clock_now());
|
||||||
|
@ -15,7 +15,7 @@ unit_test(cpu.c)
|
|||||||
unit_test(loom.c)
|
unit_test(loom.c)
|
||||||
unit_test(mux.c)
|
unit_test(mux.c)
|
||||||
unit_test(prv.c)
|
unit_test(prv.c)
|
||||||
unit_test(stream.c)
|
#unit_test(stream.c) #FIXME
|
||||||
unit_test(task.c)
|
unit_test(task.c)
|
||||||
unit_test(value.c)
|
unit_test(value.c)
|
||||||
unit_test(version.c)
|
unit_test(version.c)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
|
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -11,27 +11,10 @@
|
|||||||
#include "ovni.h"
|
#include "ovni.h"
|
||||||
#include "unittest.h"
|
#include "unittest.h"
|
||||||
|
|
||||||
static void
|
|
||||||
write_dummy_json(const char *path)
|
|
||||||
{
|
|
||||||
const char *json = "{ \"version\" : 3 }";
|
|
||||||
FILE *f = fopen(path, "w");
|
|
||||||
|
|
||||||
if (f == NULL)
|
|
||||||
die("fopen json failed:");
|
|
||||||
|
|
||||||
if (fwrite(json, strlen(json), 1, f) != 1)
|
|
||||||
die("fwrite json failed:");
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_ok(void)
|
test_ok(void)
|
||||||
{
|
{
|
||||||
OK(mkdir("ok", 0755));
|
const char *fname = "stream-ok.obs";
|
||||||
|
|
||||||
const char *fname = "ok/stream.obs";
|
|
||||||
FILE *f = fopen(fname, "w");
|
FILE *f = fopen(fname, "w");
|
||||||
|
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
@ -47,10 +30,8 @@ test_ok(void)
|
|||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
write_dummy_json("ok/stream.json");
|
|
||||||
|
|
||||||
struct stream stream;
|
struct stream stream;
|
||||||
OK(stream_load(&stream, ".", "ok"));
|
OK(stream_load(&stream, ".", fname));
|
||||||
|
|
||||||
if (stream.active)
|
if (stream.active)
|
||||||
die("stream is active");
|
die("stream is active");
|
||||||
@ -61,9 +42,7 @@ test_ok(void)
|
|||||||
static void
|
static void
|
||||||
test_bad(void)
|
test_bad(void)
|
||||||
{
|
{
|
||||||
OK(mkdir("bad", 0755));
|
const char *fname = "stream-bad.obs";
|
||||||
|
|
||||||
const char *fname = "bad/stream.obs";
|
|
||||||
FILE *f = fopen(fname, "w");
|
FILE *f = fopen(fname, "w");
|
||||||
|
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
@ -79,10 +58,8 @@ test_bad(void)
|
|||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
write_dummy_json("bad/stream.json");
|
|
||||||
|
|
||||||
struct stream stream;
|
struct stream stream;
|
||||||
ERR(stream_load(&stream, ".", "bad"));
|
ERR(stream_load(&stream, ".", fname));
|
||||||
|
|
||||||
err("OK");
|
err("OK");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user