Compare commits

...

134 Commits

Author SHA1 Message Date
Raúl Peñacoba Veigas
9826879bcd Add OpenMP support for labels and taskID views
Some checks failed
CI / build:rt (push) Failing after 15s
CI / build:debug (push) Successful in 13s
CI / build:asan (push) Failing after 13s
CI / build:nompi (push) Successful in 13s
CI / build:compilers (push) Successful in 13s
CI / build:local (push) Successful in 23s
Co-authored-by: Rodrigo Arias Mallo <rodrigo.arias@bsc.es>
2024-12-09 16:41:16 +01:00
a7103f8510 Release version 1.11.0 2024-11-08 10:26:10 +01:00
Aleix Boné
d931a68b3e
Set cfg colors for nosv_cond apis 2024-11-08 10:13:01 +01:00
Aleix Boné
a297adab7a
Add tests for nosv_cond 2024-11-08 10:13:00 +01:00
Aleix Boné
b5fd438ce0
Add nosv_cond API events (nosv 3.1.0) 2024-11-08 10:13:00 +01:00
Aleix Boné
a4a5bf0d37
Update nosv 2024-11-08 10:13:00 +01:00
180ac51aea Use fixed clock for sort-into-previous-region test
With large values of clocks, awk starts to lose precision due handling
the time as floating point values, which causes the test to fail. By
always setting the clock of the events to a known value we can just
compare the outcome as-is, without performing any arithmetic operation.

Fixes: https://pm.bsc.es/gitlab/rarias/ovni/-/issues/205
2024-11-06 11:51:57 +01:00
73b19ca1c4 Allow setting manual clock for emu events 2024-11-06 11:51:55 +01:00
31e8802803 Allow partial CPUs in thread metadata 2024-11-05 10:56:51 +01:00
fe860b2e38 Add partial-cpus test 2024-11-05 10:56:29 +01:00
60b575c8f8 Add python3 dependency for openmp 2024-10-29 09:42:03 +01:00
3a20cb717c Update runtimes, clang and ovni commits for CI 2024-10-29 09:41:58 +01:00
3bbfe0f0ec Update changelog 2024-10-25 14:39:41 +02:00
04d984d4fc Make cpu index check more strict 2024-10-25 14:22:37 +02:00
05c4ed4963 Remove info() call leftover in libovni 2024-10-25 14:22:37 +02:00
7cf69d055a Remove ovni as explictly required model
It is already added as a requirement in ovni_thead_init().
2024-10-25 14:22:37 +02:00
4c80cb3ed1 Fix typos in docs and extend CPU index usage 2024-10-25 14:22:32 +02:00
4c5e3ae151 Make all atomic operations explicit 2024-10-25 13:41:15 +02:00
86d0d11869 Add trace diagram and organize concepts 2024-10-25 13:41:15 +02:00
bf8c609dbd Remove trailing slashes from tracedir 2024-10-25 13:41:15 +02:00
706aa4a787 Rename trace-model.md to just trace.md 2024-10-25 13:41:15 +02:00
dd5b85d2c8 Add examples in some trace concepts 2024-10-25 13:41:15 +02:00
53aa3b3679 Add example program for mark API 2024-10-25 13:41:15 +02:00
6c33a2f4c0 Document environment variables 2024-10-25 13:41:15 +02:00
ea77f3d72e Fix unit-stream test 2024-10-25 13:41:15 +02:00
c190d27467 Remove tracing.md 2024-10-25 13:41:15 +02:00
ecf4c5da8c Update trace specification to version 3 2024-10-25 13:41:15 +02:00
6285a47f72 Explain some concepts in the documentation 2024-10-25 13:41:15 +02:00
5d4fa15eb9 Change hyperlinks to point to .md files
Allows mkdocs to discover broken links when the pointed document has
moved.
2024-10-25 13:41:15 +02:00
bb4e4d7e56 Emit rank information after ovni_thread_init 2024-10-25 13:41:15 +02:00
c9bbd542c5 Store rank information in the libovni thread
Prevents threads from finishing while another thread is being
initializing the rank information, causing a race to read the rank and
nranks.
2024-10-25 13:41:15 +02:00
6e99d91dae Use atomics to protect libovni process state
Multiple threads may attempt to initialize or finalize the process, so
we keep the state stored in an atomic integer to protect against bad
usage.
2024-10-25 13:41:15 +02:00
4c2071e906 Make calling ovni_thread_require() optional
When only emitting ovni events, there is no need to explicitly require
the ovni model, as libovni will already pre-populate it for the user.
2024-10-25 13:41:15 +02:00
b49671d530 Always require the current ovni model 2024-10-25 13:41:15 +02:00
5c11c469f2 Make ovni.require a mandatory attribute
We no longer accept streams that don't have the ovni.require attribute.
2024-10-25 13:41:15 +02:00
361290e24f Parse metadata from proc and loom directly
All the metadata keys are known to proc and loom only, making it
self-contained. The metadata.c module is no longer needed.
2024-10-25 13:41:15 +02:00
65d1a5ecec Add merge-cpus-loom test
Ensure we can merge the information of CPUs from multiple threads.
2024-10-25 13:41:15 +02:00
6af367ba76 Fix spawn-task-external test
It is mandatory to call ovni_thread_free().
2024-10-25 13:41:15 +02:00
65907a96f4 Update tmpdir-metadata test 2024-10-25 13:41:15 +02:00
05c1724234 Move thread streams in ovni_thread_free()
The process metadata in metadata.json is no longer needed.
2024-10-25 13:41:15 +02:00
4180300e87 Reject incomplete thread streams 2024-10-25 13:41:15 +02:00
c61f5a8772 Ensure the thread is ready before adding cpus 2024-10-25 13:41:15 +02:00
fdcff58318 Fix unit tests 2024-10-25 13:41:15 +02:00
72e60e97ea Store .obs and .json paths in stream struct 2024-10-25 13:41:15 +02:00
132b2fd536 Store loom CPUs in thread metadata 2024-10-25 13:41:15 +02:00
12835ad23a Store process information in thread metadata 2024-10-25 13:41:15 +02:00
06a2262db9 Load thread tid from metadata 2024-10-25 13:41:15 +02:00
cc5578e306 Store loom name in metadata instead of path 2024-10-25 13:41:15 +02:00
8765588667 Store ovni.part in stream metadata
Allows multiple types of streams for different system parts: thread,
process, cpu, node...
2024-10-25 13:41:15 +02:00
9a8dc382a2 Store stream metadata in stream.json
Place all stream files in its own stream directory.
2024-10-25 13:41:15 +02:00
85859a488d Add more path utility functions 2024-10-25 13:41:15 +02:00
e54e3e684e Store TID and PID in thread metadata 2024-10-25 13:41:15 +02:00
17c74d2e32 Increase version metadata to 3 2024-10-25 13:41:15 +02:00
c60f22f7f7 Update mkdocs to 1.6.0 2024-09-13 09:38:40 +02:00
36cf3121d1 Fix implicit signed conversions
Some checks failed
CI / build:rt (push) Failing after 12s
CI / build:asan (push) Failing after 12s
CI / build:nompi (push) Successful in 59s
CI / build:debug (push) Successful in 1m50s
CI / build:local (push) Successful in 2m2s
CI / build:compilers (push) Successful in 2m27s
2024-09-09 13:44:05 +02:00
c8b95313ff Fix unaligned access to 64 bits payload 2024-09-09 13:44:05 +02:00
e5448af6d8 Rebuild ring buffer pointers after injecting events
The ring buffer pointers are no longer valid as we may have displaced
events around. The pointers of the affected region are reconstructed by
reading the events again, following their size.
2024-09-09 13:43:59 +02:00
49149e452c Check ring buffer order after injecting events
Ensure that we are not reading garbage.
2024-09-09 09:10:04 +02:00
b2d91391b3 Add sort-into-previous-region emu test 2024-09-09 09:10:04 +02:00
13f70be87b Set nOS-V version required for tests to 2.3.1
Includes the required fixes for the kernel ring buffer tests.
2024-09-09 08:51:04 +02:00
71aa33d22f Use string to set ovni.kernel_ringsize 2024-09-09 08:51:04 +02:00
4c3da12ea1 Fix typos in nOS-V kernel test 2024-09-09 08:51:04 +02:00
a47082730a Ensure that nOS-V aborts on ring overflow 2024-09-09 08:51:04 +02:00
99dc3904af Add overflow and normal kernel nOS-V tests 2024-09-09 08:51:04 +02:00
acf18c1bb4 Make nOS-V kernel overflow test configurable 2024-09-09 08:51:04 +02:00
e9788e22ad Add test kernel ring overflow test for nOS-V
There is a problem in the way we are reading the buffer in nOS-V, which
fails when the ring buffer gets full. This regression test ensures it is
fixed.

Reported-by: David Álvarez <david.alvarez@bsc.es>
2024-09-09 08:51:04 +02:00
6cb983a7c4 Update nOS-V commit 2024-09-09 08:51:04 +02:00
7496a6a866 Fix easy cases of unneeded casts 2024-09-09 08:28:08 +02:00
c8750b9dfd Enable -Wconversion and -Wsign-conversion
Prevents implicit conversions to go undetected, as they will have to be
explicit now.
2024-09-09 08:28:02 +02:00
d98ca97624 Fix unaligned load of 4 bytes for typeid
Use memcpy() to move the typeid to an aligned address.
2024-07-29 13:17:37 +02:00
61d57901b1 Enable undefined behavior sanitizer in CI 2024-07-29 13:09:41 +02:00
9c82038561 Add release link to tag 1.10.0 2024-07-26 16:20:34 +02:00
15dfa48d2d Release version 1.10.0 2024-07-26 13:25:43 +02:00
2457e50712 Use always base 10 integer formats with scanf()
The %i printf variant tries to autodetect the base, so 010 becomes 8.
2024-07-24 16:36:54 +02:00
92c36502bc Reduce heat and fibonnacci test sizes 2024-07-24 16:09:47 +02:00
439b716a71 Use int64_t printf formats for mark channels 2024-07-24 16:09:47 +02:00
97282ff051 Increase test timeout to 60 seconds 2024-07-24 16:09:47 +02:00
093c91521a Fix error format strings in mark API 2024-07-24 16:09:44 +02:00
74aa7b4ea6 Update changelog 2024-07-24 15:12:09 +02:00
3d8c84e17c Fix heap when size_t is not unsigned long long
When the width of size_t doesn't match the width of the unsigned long
long type, the number of leading zeros doesn't match, making the
heap_get_move() function return incorrect values. This is the case on
ARMv7 with 32 bits, where size_t is 32 bits but unsigned long long is 64
bits.

We check the size of size_t to select which builtin we need. The sizeof
operator cannot be used at preprocessing, so we rely on the
optimizations to only leave the proper assembly instruction.

Fixes: https://pm.bsc.es/gitlab/rarias/ovni/-/issues/193
2024-07-24 15:12:09 +02:00
91e8367d35 Set timeout to 30 seconds for tests 2024-07-24 15:12:09 +02:00
129020e1c5 Fix format errors in printf-like functions 2024-07-24 15:12:09 +02:00
d03fe10be8 Protect printf-like calls against format errors 2024-07-24 15:12:09 +02:00
3fdbb95080 Fix remaining problems for 32 bits architectures 2024-07-24 15:12:09 +02:00
Miquel Vidal i Pinyol
3103018404 Use format macro constants for fprintf and fscanf family functions 2024-07-24 15:12:09 +02:00
Miquel Vidal i Pinyol
478ed1f5d0 Use proper format specifiers
Allows compiling for architectures with different data type sizes
2024-07-24 15:12:09 +02:00
42feb53c86 Cross compile for ARMv7, Aarch64 and RISC-V 64
Adds CI cross-compilation tests for those architectures. Requires the
host to be able to run thos binaries via binfmt.

See: https://docs.kernel.org/admin-guide/binfmt-misc.html
2024-07-24 15:12:09 +02:00
391d695144 Add mark API to the changelog 2024-07-23 10:35:08 +02:00
038b9d8564 Document usage rules for the mark API 2024-07-23 10:35:08 +02:00
5448b5c0ec Check duplicated mark channel types are the same
Ensure that two threads cannot define the same mark type with different
channel types.
2024-07-23 10:35:08 +02:00
be45235d15 Improve documentation of the mark API 2024-07-23 10:35:08 +02:00
87e4b829c5 Switch the mark tracking for threads to active
In the thread view, the values will still be visible when the thread
goes to Warming or Cooling states, instead of being removed like when
the thread enters the Paused state. The CPU view will continue to track
the running thread (only in the Running state).
2024-07-23 10:35:02 +02:00
1ab605b70d Fix calloc() argument order
Catched by a new gcc 14.1.1 warning.
2024-07-22 16:45:29 +02:00
fbb78ae22d Avoid initialization of mark channels without types
There is no need to create any channel or connect any channel to the PRV
output.
2024-07-22 16:42:23 +02:00
a21dc76d81 Use 100 as example mark type
As the types for mark timelines start at 100, it is likely that it
matches in the first try.
2024-06-21 09:45:54 +02:00
49cecb798a Don't allow zero in PRV for mark channels
As the zero value is not allowed to reach the mark channels, there is no
need to allow it in the PRV end.
2024-06-21 09:39:32 +02:00
e31f0f1ded Add fibonacci and heat RT tests for mark API 2024-06-20 17:39:42 +02:00
43792fb349 Clarify push and pop value in mark API 2024-06-20 11:48:31 +02:00
d6a83a0520 Allow duplicate values in mark channels 2024-06-20 11:41:38 +02:00
c803a7566f Prevent zero values in the mark API
These values cannot be differentiated from a null value, due to a
Paraver limitation.
2024-06-20 11:41:09 +02:00
670edb6ddc Add documentation for the mark API
Includes the runtime usage as well as how to adjust the Paraver
configuration.
2024-06-20 11:08:29 +02:00
f5d1e0a3cb Add example mark configurations 2024-06-20 11:07:49 +02:00
a58b3d194c Add CPU output for mark channels
By default they are configured to track the running thread.
2024-06-19 13:48:18 +02:00
d9180d950b Make mark thread channels show only when running
Implements support for tracking the running thread using the track API.
2024-06-19 13:15:16 +02:00
9da7234684 Pause one thread in mark API emu test.
The Paraver timeline should hide the value of the thread while it is
paused. This will require adding a tracking module with a mux.
2024-06-19 13:13:18 +02:00
610b1223d9 Update version docs for ovni model 1.1.0 2024-06-19 12:26:58 +02:00
6954f05dee Update mark test to for single and stack types 2024-06-19 12:26:35 +02:00
db57136f1b Allow the value zero in marks
When using the mark API to track a counter, it is posible that the value
zero is being emitted as it will be properly displayed using the
gradient view in Paraver.
2024-06-19 12:26:35 +02:00
2c111fd98c Add ovni_mark_set() to the API
Allows emitting a single event to change the value of the mark channel.
The mark type must be defined as single without the MARK_FLAG_STACK
flag.
2024-06-19 12:26:35 +02:00
90f8ae4188 Allow marks without labels defined
The labels are optional, so they shouldn't be required when processing
the mark types.
2024-06-19 12:26:35 +02:00
b4d445b378 Write mark PCF types for thread PVT 2024-06-19 12:26:35 +02:00
ea79c90c89 Connect mark channels to PRV
There must be one channel per thread and type.
2024-06-19 12:26:35 +02:00
1b2f72cc3a Store mark labels into a hash table
Multiple threads can define the same values as long as the labels match.
They will be combined into a single hash table by value.
2024-06-19 12:26:35 +02:00
505245d54c Implement emulator logic to parse mark metadata
The marks are parsed from the metadata definition, then merged from all
threads and a new channel for each mark type is created. The channel
type is specified using a flag when calling ovni_mark_type(), so the
channels is set to single or stack. For now, only ovni_mark_push() and
ovni_mark_pop() are implemented.
2024-06-19 12:26:35 +02:00
93ab5a5833 Add ovni_mark_* API to store custom states
In order to allow easy debugging of some programs and runtimes, it is
often neccessary to add extra information in the timeline views. The
modification of the emulator to accomodate those temporal events is time
consuming and requires knowlegde of the emulator internals.

To improve the situation, a new set of functions are added to libovni
which allow users to define their own views. Up to 100 types of events
can be declared, where each type can have an unlimited number ov values
with an optional label attached.
2024-06-19 12:26:35 +02:00
247ea7e7c3 Add nosv.can_breakdown attribute check
The nosv.can_breakdown attribute states if enough events for the
breakdown model of nOS-V are enabled at runtime. It is used to ensure
that breakdown traces have the progress events enabled along with others
required for proper visualization of traces.

The emulator will panic when the level is not enough, instead of relying
on users to always remember to enable the correct level.
2024-06-18 12:06:42 +02:00
d1e8a62396 Add API to manage metadata in streams
The ovni_attr_* set of functions allows users to write and read metadata
stores in the thread stream. The metadata information is available to
the emulator at the beginning of the emulation.
2024-06-13 11:09:40 +02:00
2ac67cff18 Update CHANGELOG for nOS-V breakdown 2024-06-12 16:52:30 +02:00
eed2273ddf Add nOS-V docs for idle and breakdown views 2024-06-12 16:52:30 +02:00
31d6eb076c Add unknown subsystem state for nOS-V breakdown
It will appear when the emulator knows that a thread is running in the
CPU, but no subsystem has been entered yet. This is common a
instrumentation level lower than 3 in nOS-V.
2024-06-12 16:52:30 +02:00
bb5e406af3 Set a default value for empty task type labels 2024-06-12 16:52:30 +02:00
aab33ccfab Add Nodes RT tests with breakdown enabled 2024-06-12 16:52:30 +02:00
98164afc90 Update nOS-V state colors in paraver CFG 2024-06-12 16:52:30 +02:00
819e83d138 Add RT breakdown tests for nOS-V
The nOS-V version required is now 2.3.0.
2024-06-12 16:52:30 +02:00
16b9b2ba85 Update nOS-V commit for RT tests 2024-06-12 16:51:57 +02:00
9d94189165 Increase nOS-V model version to 2.2.0
The new progressing state events VP{pra} cause a minor version bump in
the nOS-V model.
2024-06-12 10:25:24 +02:00
David Alvarez
9fb53df45d nOS-V Breakdown 2024-06-12 10:15:59 +02:00
92cc779caf Make chan_pop() error more clear
Fixes: https://pm.bsc.es/gitlab/rarias/ovni/-/issues/188
2024-06-11 09:19:35 +02:00
e3d72fb14e Release version 1.9.1
All checks were successful
CI / build:debug (pull_request) Successful in 1m21s
CI / build:local (pull_request) Successful in 1m47s
CI / build:compilers (pull_request) Successful in 1m37s
CI / build:nompi (pull_request) Successful in 1m39s
CI / build:rt (pull_request) Successful in 1m53s
CI / build:asan (pull_request) Successful in 2m21s
CI / build:rt (push) Successful in 13s
CI / build:debug (push) Successful in 13s
CI / build:asan (push) Successful in 13s
CI / build:nompi (push) Successful in 13s
CI / build:local (push) Successful in 21s
CI / build:compilers (push) Successful in 20s
2024-05-10 15:31:38 +02:00
014152fc89 Fix warning with gcc 11.3.1
All checks were successful
CI / build:debug (pull_request) Successful in 1m20s
CI / build:compilers (pull_request) Successful in 1m35s
CI / build:nompi (pull_request) Successful in 1m40s
CI / build:local (pull_request) Successful in 1m48s
CI / build:rt (pull_request) Successful in 1m54s
CI / build:asan (pull_request) Successful in 2m20s
CI / build:rt (push) Successful in 13s
CI / build:debug (push) Successful in 13s
CI / build:asan (push) Successful in 13s
CI / build:nompi (push) Successful in 13s
CI / build:local (push) Successful in 21s
CI / build:compilers (push) Successful in 20s
Reported-by: Kevin Sala <kevin.sala@bsc.es>
2024-05-10 15:25:23 +02:00
3a300c816e Fix breakdown model forbidden value 0 error
All checks were successful
CI / build:local (pull_request) Successful in 2m4s
CI / build:debug (pull_request) Successful in 1m7s
CI / build:rt (pull_request) Successful in 2m32s
CI / build:compilers (pull_request) Successful in 1m12s
CI / build:nompi (pull_request) Successful in 1m17s
CI / build:asan (pull_request) Successful in 2m7s
CI / build:debug (push) Successful in 3s
CI / build:asan (push) Successful in 3s
CI / build:rt (push) Successful in 13s
CI / build:nompi (push) Successful in 12s
CI / build:local (push) Successful in 21s
CI / build:compilers (push) Successful in 20s
When a event causes a new value in the sort module, the first time it
will write all output values, which most of them will be zero. Writting
a zero value is forbidden by default, so we relax the constraint with
the PRV_ZERO flag.
2024-05-09 15:36:58 +02:00
8c8bde4a0f Add emulation test for breakdown zero values 2024-05-09 15:36:58 +02:00
0c64f62d01 Add Nanos6 breakdown test for runtime 2024-05-09 15:36:58 +02:00
d5d5f2fcd4 Add Gitea CI workflow
All checks were successful
CI / build:debug (pull_request) Successful in 1m17s
CI / build:compilers (pull_request) Successful in 1m53s
CI / build:nompi (pull_request) Successful in 2m1s
CI / build:local (pull_request) Successful in 2m14s
CI / build:rt (pull_request) Successful in 2m23s
CI / build:asan (pull_request) Successful in 3m29s
CI / build:rt (push) Successful in 13s
CI / build:debug (push) Successful in 13s
CI / build:asan (push) Successful in 13s
CI / build:nompi (push) Successful in 12s
CI / build:local (push) Successful in 21s
CI / build:compilers (push) Successful in 20s
2024-05-09 15:36:39 +02:00
194 changed files with 6887 additions and 1480 deletions

45
.gitea/workflows/ci.yaml Normal file
View File

@ -0,0 +1,45 @@
name: CI
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:local:
runs-on: native
steps:
- uses: https://gitea.com/ScMi1/checkout@v1.4
- run: nix build -L --no-link .#ovniPackages.local
build:rt:
runs-on: native
steps:
- uses: https://gitea.com/ScMi1/checkout@v1.4
- run: nix build -L --no-link .#ovniPackages.rt
build:debug:
runs-on: native
steps:
- uses: https://gitea.com/ScMi1/checkout@v1.4
- run: nix build -L --no-link .#ovniPackages.debug
build:asan:
runs-on: native
steps:
- uses: https://gitea.com/ScMi1/checkout@v1.4
- run: nix build -L --no-link .#ovniPackages.asan
build:nompi:
runs-on: native
steps:
- uses: https://gitea.com/ScMi1/checkout@v1.4
- run: nix build -L --no-link .#ovniPackages.nompi
build:compilers:
runs-on: native
steps:
- uses: https://gitea.com/ScMi1/checkout@v1.4
- run: nix build -L --no-link .#ovniPackages.compilers

View File

@ -42,6 +42,13 @@ build:asan:
script:
- nix build -L --no-link .#ovniPackages.asan
build:ubsan:
stage: build
tags:
- nix
script:
- nix build -L --no-link .#ovniPackages.ubsan
build:nompi:
stage: build
tags:
@ -55,3 +62,24 @@ build:compilers:
- nix
script:
- nix build -L --no-link .#ovniPackages.compilers
build:armv7:
stage: build
tags:
- nix
script:
- nix build -L --no-link .#ovniPackages.armv7
build:aarch64:
stage: build
tags:
- nix
script:
- nix build -L --no-link .#ovniPackages.aarch64
build:riscv64:
stage: build
tags:
- nix
script:
- nix build -L --no-link .#ovniPackages.riscv64

View File

@ -7,6 +7,61 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Changed
- OpenMP model version increased to 1.2.0.
### Added
- Add support OpenMP label and task ID views.
## [1.11.0] - 2024-11-08
### Added
- Introduce part model.
- Support for `nosv_cond_wait`, `nosv_cond_signal` and `nosv_cond_broadcast` events VA{oOgGkK}.
### Changed
- Enable -Wconversion and -Wsign-conversion.
- Update trace format to version 3.
- The ovni.require metadata key is now mandatory.
- Store process metadata in thread metadata.
- nOS-V model version increased to 2.4.0.
### Fixed
- Fix bug in ovnisort when injecting events in a previously modified section.
## [1.10.0] - 2024-07-26
### Changed
- nOS-V model version increased to 2.3.0.
- Prevent accidental use of nOS-V traces without required events for the
breakdown model using the `nosv.can_breakdown` attribute.
- Increase ovni model version to 1.1.0 for the mark events `OM*`.
### Added
- Add support for nOS-V progressing events VP{pra}.
- Add breakdown model for nOS-V.
- New API to manage stream metadata `ovni_attr_*()`.
- New mark API `ovni_mark_*()` to emit user-defined events.
### Fixed
- Cross-compilation for ARM 32 bits.
## [1.9.1] - 2024-05-10
### Fixed
- Fix breakdown model error that was preventing a zero value to be written in
the PRV trace.
- Fix gcc 11.3.1 -Wstringop-overflow warning.
## [1.9.0] - 2024-04-25
### Added
@ -238,6 +293,9 @@ are used along with some other changes.
- First ovni release.
[unreleased]: https://jungle.bsc.es/git/rarias/ovni
[1.11.0]: https://github.com/rodarima/ovni/releases/tag/1.11.0
[1.10.0]: https://github.com/rodarima/ovni/releases/tag/1.10.0
[1.9.1]: https://github.com/rodarima/ovni/releases/tag/1.9.1
[1.9.0]: https://github.com/rodarima/ovni/releases/tag/1.9.0
[1.8.0]: https://github.com/rodarima/ovni/releases/tag/1.8.0
[1.7.0]: https://github.com/rodarima/ovni/releases/tag/1.7.0

View File

@ -3,13 +3,13 @@
cmake_minimum_required(VERSION 3.20)
project(OVNI LANGUAGES C VERSION 1.9.0)
project(OVNI LANGUAGES C VERSION 1.11.0)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
add_compile_options(-Wall -Wextra -Wformat
-Wmissing-prototypes -Wstrict-prototypes
#-Wconversion -Wsign-conversion
-Wconversion -Wsign-conversion
-Wold-style-definition -pedantic
-Werror
)
@ -67,7 +67,9 @@ set(CMAKE_C_FLAGS_ASAN "${CMAKE_C_FLAGS_DEBUG} \
-fno-omit-frame-pointer"
CACHE STRING "Flags used by the C compiler during AddressSanitizer builds." FORCE)
set(CMAKE_C_FLAGS_UBSAN "${CMAKE_C_FLAGS_DEBUG} -fsanitize=undefined"
set(CMAKE_C_FLAGS_UBSAN "${CMAKE_C_FLAGS_DEBUG} \
-fsanitize=undefined \
-fno-sanitize-recover=all"
CACHE STRING "Flags used by the C compiler during UndefinedBehaviorSanitizer builds." FORCE)
find_program(IWYU NAMES include-what-you-use iwyu)

View File

@ -0,0 +1,44 @@
#ParaverCFG
ConfigFile.Version: 3.4
ConfigFile.NumWindows: 1
################################################################################
< NEW DISPLAYING WINDOW CPU: nOS-V Runtime/Idle/Task breakdown >
################################################################################
window_name CPU: nOS-V Runtime/Idle/Task breakdown
window_type single
window_id 1
window_position_x 0
window_position_y 0
window_width 600
window_height 150
window_comm_lines_enabled false
window_flags_enabled false
window_noncolor_mode true
window_custom_color_enabled true
window_custom_color_palette {6.000000000000:94,0,0},{7.000000000000:153,114,0},{9.000000000000:124,213,228},{10.000000000000:242,239,141},{11.000000000000:0,70,0},{19.000000000000:195,96,151},{20.000000000000:255,162,255},{21.000000000000:203,255,3},{22.000000000000:7,255,12},{23.000000000000:21,224,189},{24.000000000000:255,103,0},{25.000000000000:0,99,162},{26.000000000000:110,77,252},{100.000000000000:0,100,0},{101.000000000000:60,60,60},{102.000000000000:150,150,0}
window_logical_filtered true
window_physical_filtered false
window_comm_fromto true
window_comm_tagsize true
window_comm_typeval true
window_units Microseconds
window_maximum_y 1000.0
window_minimum_y 1.0
window_compute_y_max true
window_level thread
window_scale_relative 1.000000000000
window_end_time_relative 1.000000000000
window_object appl { 1, { All } }
window_begin_time_relative 0.000000000000
window_open true
window_drawmode draw_randnotzero
window_drawmode_rows draw_randnotzero
window_pixel_size 1
window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 17
window_filter_module evt_type_label 1 "CPU: nOS-V Runtime/Idle/Task breakdown"

44
cfg/cpu/nosv/idle.cfg Normal file
View File

@ -0,0 +1,44 @@
#ParaverCFG
ConfigFile.Version: 3.4
ConfigFile.NumWindows: 1
################################################################################
< NEW DISPLAYING WINDOW CPU: nOS-V idle state of the RUNNING thread >
################################################################################
window_name CPU: nOS-V idle state of the RUNNING thread
window_type single
window_id 1
window_position_x 0
window_position_y 0
window_width 600
window_height 150
window_comm_lines_enabled false
window_flags_enabled false
window_noncolor_mode true
window_custom_color_enabled true
window_custom_color_palette {100.000000000000:0,100,0},{101.000000000000:60,60,60},{102.000000000000:150,150,0}
window_logical_filtered true
window_physical_filtered false
window_comm_fromto true
window_comm_tagsize true
window_comm_typeval true
window_units Microseconds
window_maximum_y 1000.0
window_minimum_y 1.0
window_compute_y_max true
window_level thread
window_scale_relative 1.000000000000
window_end_time_relative 1.000000000000
window_object appl { 1, { All } }
window_begin_time_relative 0.000000000000
window_open true
window_drawmode draw_randnotzero
window_drawmode_rows draw_randnotzero
window_pixel_size 1
window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 16
window_filter_module evt_type_label 1 "CPU: nOS-V idle state of the RUNNING thread"

View File

@ -17,7 +17,7 @@ window_comm_lines_enabled true
window_flags_enabled false
window_noncolor_mode true
window_custom_color_enabled true
window_custom_color_palette {6.000000000000:94,0,0},{7.000000000000:153,114,0},{9.000000000000:124,213,228},{10.000000000000:242,239,141},{11.000000000000:0,70,0},{19.000000000000:195,96,151},{20.000000000000:255,162,255},{21.000000000000:203,255,3},{22.000000000000:7,255,12},{23.000000000000:21,224,189},{24.000000000000:255,103,0},{25.000000000000:0,99,162},{26.000000000000:110,77,252}
window_custom_color_palette {6.000000000000:94,0,0},{7.000000000000:153,114,0},{9.000000000000:124,213,228},{10.000000000000:242,239,141},{11.000000000000:0,70,0},{19.000000000000:195,96,151},{20.000000000000:255,162,255},{21.000000000000:203,255,3},{22.000000000000:7,255,12},{23.000000000000:21,165,118},{24.000000000000:255,103,0},{25.000000000000:200,30,5},{26.000000000000:255,10,200},{27.000000000000:98,133,80},{28.000000000000:0,99,162},{29.000000000000:110,77,252}
window_logical_filtered true
window_physical_filtered false
window_comm_fromto true

41
cfg/cpu/openmp/label.cfg Normal file
View File

@ -0,0 +1,41 @@
#ParaverCFG
ConfigFile.Version: 3.4
ConfigFile.NumWindows: 1
################################################################################
< NEW DISPLAYING WINDOW CPU: OpenMP label of the RUNNING thread >
################################################################################
window_name CPU: OpenMP label of the RUNNING thread
window_type single
window_id 1
window_position_x 100
window_position_y 100
window_width 600
window_height 150
window_comm_lines_enabled true
window_flags_enabled false
window_noncolor_mode true
window_logical_filtered true
window_physical_filtered false
window_comm_fromto true
window_comm_tagsize true
window_comm_typeval true
window_units Microseconds
window_maximum_y 1000.0
window_minimum_y 1.0
window_compute_y_max true
window_level thread
window_scale_relative 1.000000000000
window_end_time_relative 1.000000000000
window_object appl { 1, { All } }
window_begin_time_relative 0.000000000000
window_open true
window_drawmode draw_randnotzero
window_drawmode_rows draw_randnotzero
window_pixel_size 1
window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 51
window_filter_module evt_type_label 1 "CPU: OpenMP label of the RUNNING thread"

View File

@ -0,0 +1,41 @@
#ParaverCFG
ConfigFile.Version: 3.4
ConfigFile.NumWindows: 1
################################################################################
< NEW DISPLAYING WINDOW CPU: OpenMP task id of the RUNNING thread >
################################################################################
window_name CPU: OpenMP task id of the RUNNING thread
window_type single
window_id 1
window_position_x 100
window_position_y 100
window_width 600
window_height 150
window_comm_lines_enabled true
window_flags_enabled false
window_noncolor_mode true
window_logical_filtered true
window_physical_filtered false
window_comm_fromto true
window_comm_tagsize true
window_comm_typeval true
window_units Microseconds
window_maximum_y 1000.0
window_minimum_y 1.0
window_compute_y_max true
window_level thread
window_scale_relative 1.000000000000
window_end_time_relative 1.000000000000
window_object appl { 1, { All } }
window_begin_time_relative 0.000000000000
window_open true
window_drawmode draw_randnotzero
window_drawmode_rows draw_randnotzero
window_pixel_size 1
window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 52
window_filter_module evt_type_label 1 "CPU: OpenMP task id of the RUNNING thread"

41
cfg/cpu/ovni/mark.cfg Normal file
View File

@ -0,0 +1,41 @@
#ParaverCFG
ConfigFile.Version: 3.4
ConfigFile.NumWindows: 1
################################################################################
< NEW DISPLAYING WINDOW CPU: Mark value of the RUNNING thread >
################################################################################
window_name CPU: Mark value of the RUNNING thread
window_type single
window_id 1
window_position_x 100
window_position_y 100
window_width 600
window_height 150
window_comm_lines_enabled true
window_flags_enabled false
window_noncolor_mode true
window_logical_filtered true
window_physical_filtered false
window_comm_fromto true
window_comm_tagsize true
window_comm_typeval true
window_units Microseconds
window_maximum_y 1000.0
window_minimum_y 1.0
window_compute_y_max true
window_level thread
window_scale_relative 1.000000000000
window_end_time_relative 1.000000000000
window_object appl { 1, { All } }
window_begin_time_relative 0.000000000000
window_open true
window_drawmode draw_randnotzero
window_drawmode_rows draw_randnotzero
window_pixel_size 1
window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 100
window_filter_module evt_type_label 1 "CPU: Mark value of the RUNNING thread"

View File

@ -17,7 +17,7 @@ window_comm_lines_enabled true
window_flags_enabled false
window_noncolor_mode true
window_custom_color_enabled true
window_custom_color_palette {6.000000000000:94,0,0},{7.000000000000:153,114,0},{9.000000000000:124,213,228},{10.000000000000:242,239,141},{11.000000000000:0,70,0},{19.000000000000:195,96,151},{20.000000000000:255,162,255},{21.000000000000:203,255,3},{22.000000000000:7,255,12},{23.000000000000:21,224,189},{24.000000000000:255,103,0},{25.000000000000:0,99,162},{26.000000000000:110,77,252}
window_custom_color_palette {6.000000000000:94,0,0},{7.000000000000:153,114,0},{9.000000000000:124,213,228},{10.000000000000:242,239,141},{11.000000000000:0,70,0},{19.000000000000:195,96,151},{20.000000000000:255,162,255},{21.000000000000:203,255,3},{22.000000000000:7,255,12},{23.000000000000:21,165,118},{24.000000000000:255,103,0},{25.000000000000:200,30,5},{26.000000000000:255,10,200},{27.000000000000:98,133,80},{28.000000000000:0,99,162},{29.000000000000:110,77,252}
window_logical_filtered true
window_physical_filtered false
window_comm_fromto true

View File

@ -0,0 +1,41 @@
#ParaverCFG
ConfigFile.Version: 3.4
ConfigFile.NumWindows: 1
################################################################################
< NEW DISPLAYING WINDOW Thread: OpenMP label of the ACTIVE thread >
################################################################################
window_name Thread: OpenMP label of the ACTIVE thread
window_type single
window_id 1
window_position_x 100
window_position_y 100
window_width 600
window_height 150
window_comm_lines_enabled true
window_flags_enabled false
window_noncolor_mode true
window_logical_filtered true
window_physical_filtered false
window_comm_fromto true
window_comm_tagsize true
window_comm_typeval true
window_units Microseconds
window_maximum_y 1000.0
window_minimum_y 1.0
window_compute_y_max true
window_level thread
window_scale_relative 1.000000000000
window_end_time_relative 1.000000000000
window_object appl { 1, { All } }
window_begin_time_relative 0.000000000000
window_open true
window_drawmode draw_randnotzero
window_drawmode_rows draw_randnotzero
window_pixel_size 1
window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 51
window_filter_module evt_type_label 1 "Thread: OpenMP label of the ACTIVE thread"

View File

@ -0,0 +1,41 @@
#ParaverCFG
ConfigFile.Version: 3.4
ConfigFile.NumWindows: 1
################################################################################
< NEW DISPLAYING WINDOW Thread: OpenMP task id of the ACTIVE thread >
################################################################################
window_name Thread: OpenMP task id of the ACTIVE thread
window_type single
window_id 1
window_position_x 100
window_position_y 100
window_width 600
window_height 150
window_comm_lines_enabled true
window_flags_enabled false
window_noncolor_mode true
window_logical_filtered true
window_physical_filtered false
window_comm_fromto true
window_comm_tagsize true
window_comm_typeval true
window_units Microseconds
window_maximum_y 1000.0
window_minimum_y 1.0
window_compute_y_max true
window_level thread
window_scale_relative 1.000000000000
window_end_time_relative 1.000000000000
window_object appl { 1, { All } }
window_begin_time_relative 0.000000000000
window_open true
window_drawmode draw_randnotzero
window_drawmode_rows draw_randnotzero
window_pixel_size 1
window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 52
window_filter_module evt_type_label 1 "Thread: OpenMP task id of the ACTIVE thread"

41
cfg/thread/ovni/mark.cfg Normal file
View File

@ -0,0 +1,41 @@
#ParaverCFG
ConfigFile.Version: 3.4
ConfigFile.NumWindows: 1
################################################################################
< NEW DISPLAYING WINDOW Thread: Mark value of the ACTIVE thread >
################################################################################
window_name Thread: Mark value of the ACTIVE thread
window_type single
window_id 1
window_position_x 100
window_position_y 100
window_width 600
window_height 150
window_comm_lines_enabled true
window_flags_enabled false
window_noncolor_mode true
window_logical_filtered true
window_physical_filtered false
window_comm_fromto true
window_comm_tagsize true
window_comm_typeval true
window_units Microseconds
window_maximum_y 1000.0
window_minimum_y 1.0
window_compute_y_max true
window_level thread
window_scale_relative 1.000000000000
window_end_time_relative 1.000000000000
window_object appl { 1, { All } }
window_begin_time_relative 0.000000000000
window_open true
window_drawmode draw_randnotzero
window_drawmode_rows draw_randnotzero
window_pixel_size 1
window_labels_to_draw 1
window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } }
window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } }
window_filter_module evt_type 1 100
window_filter_module evt_type_label 1 "Thread: Mark value of the ACTIVE thread"

View File

@ -65,5 +65,5 @@ to write the duplicated value with no error.
A unique function can be set to each channel which will be called once a channel
becomes dirty with `chan_set_dirty_cb()`. This callback will be called before
`chan_set()`, `chan_push()` or `chan_pop()` returns. The [patch
bay](../patchbay) uses this callback to detect when a channel is modified an run
bay](patchbay.md) uses this callback to detect when a channel is modified an run
other callbacks.

View File

@ -22,7 +22,7 @@ If the model is not enabled, no other function will be called.
The create function is called for each enabled model to allow them to allocate
all the required structures to perform the emulation using the
[extend](../extend) mechanism. All the required channels must be created and
[extend](extend.md) mechanism. All the required channels must be created and
registered in the patch bay in this function, so other models can found them in
the next stage.

View File

@ -1,6 +1,6 @@
# Mux
The emulator provides a mechanism to interconnect [channels](../channels) in a
The emulator provides a mechanism to interconnect [channels](channels.md) in a
similar way as an [analog
multiplexer](https://en.wikipedia.org/wiki/Multiplexer) by using the `mux`
module.
@ -19,7 +19,7 @@ selected. This allows a multiplexer to act as a filter too.
The typical use of multiplexers is to implement the tracking modes of channels.
As an example, the following diagram shows two multiplexers used to implement
the subsystem view of [Nanos6](../nanos6):
the subsystem view of [Nanos6](../user/emulation/nanos6.md):
![Mux example](fig/mux.svg)
@ -51,5 +51,5 @@ Multiplexers allow models to interact with each other in a controlled way. In
the example, the blue channel (*nanos6.thread0.subsystem*) is directly modified by
the Nanos6 model when a new event is received. While the red channels are
controlled by the ovni model. The rest of the channels are automatically updated
in the propagation phase of the [bay](../patchbay) allowing the ovni model to
in the propagation phase of the [bay](patchbay.md) allowing the ovni model to
modify the Nanos6 Paraver view of the subsystems.

View File

@ -16,7 +16,7 @@ A channel can be connected to each row in a trace with `prv_register()`, so the
new values of the channel get written in the trace. Only null and int64 data
values are supported for now.
The emission phase is controlled by the [patch bay](../patchbay) and runs all
The emission phase is controlled by the [patch bay](patchbay.md) and runs all
the emit callbacks at once for all dirty channels.
## Duplicate values

View File

@ -1,6 +1,6 @@
# Patch bay
The patch bay (or simply bay) allows [channels](../channels/) to be registered
The patch bay (or simply bay) allows [channels](channels.md) to be registered
with their name so they are visible to all parts of the emulator and provides a
way to run callbacks when the channels update their values.

View File

@ -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
later investigate how the execution happened.
The instrumentation process is split in two stages: [runtime](runtime)
tracing and [emulation](emulation/).
The instrumentation process is split in two stages:
[runtime](user/runtime/index.md)
tracing and [emulation](user/emulation/index.md).
During runtime, very short binary events are stored on disk which
describe what is happening. Once the execution finishes, the events are

View File

@ -1,4 +1,4 @@
mkdocs==1.4.1
mkdocs==1.6.0
markdown==3.3.7
python-markdown-math==0.8
jinja2==3.1.2

View File

@ -1,31 +0,0 @@
# Overview
The objective of the ovni project is to provide insight into what
happened at execution of a program.
![Instrumentation process](fig/instrumentation.svg)
The key pieces of software involved are instrumented so they emit events
during the execution which allow the reconstruction of the execution
later on.
During the execution phase, the information gathered in the events is
kept very short and simple, so the overhead is kept at minimum to avoid
disturbing the execution process. Here is an example of a single event
emitted during the execution phase, informing the current thread to
finish the execution:
00 4f 48 65 52 c0 27 b4 d3 ec 01 00
During the emulation phase, the events are read and processed in the
emulator, reconstructing the execution. State transitions are recorded
in a Paraver trace. Here is an example of the same thread ceasing the
execution:
2:0:1:1:1:50105669:1:0
Finally, loading the trace in the Paraver program, we can generate a
timeline visualization of the state change. Here is the example for the
same state transition of the thread stopping the execution:
![Visualization](fig/visualization.png)

View File

@ -0,0 +1,62 @@
# Part model
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*.
Here is an example diagram depicting the part hierarchy:
![Part model](part-model.svg)
Notice how a loom can restrict the CPUs of the node to its child processes.
## Software parts
These are not physical parts, but they abstract common concepts.
### Thread
A thread in ovni is directly mapped to a [POSIX
thread](https://en.wikipedia.org/wiki/Pthreads) and they are identified by a
`TID` which must be unique in a [node](#node). Threads in ovni have [a model with
an internal state](../emulation/ovni.md/#thread_model) that tries to tracks the
state of the real thread.
### Process
A process is directly mapped to a UNIX
[process](https://en.wikipedia.org/wiki/Process_(computing)) and they are
identified by a `PID` number which must be unique in a [node](#node).
### Loom
A loom has no direct mapping to a usual concept. It consists of a set of
[CPUs](#cpu) from the same node and a set of processes that can *only run in
those CPUs*. Each CPUs must belong to one and only one loom. It is often used
to group CPUs that belong to the same process when running workloads with
multiple processes (like with MPI).
Each loom has a virtual CPU which collects running threads that are not
exclusively assigned to a physical CPU, so we cannot determine on which CPU they
are running.
## Hardware parts
These parts have a physical object assigned.
### CPU
A CPU is a hardware thread that can execute at most one thread at a time. Each
CPU must have a physical ID that is unique in a node. In ovni there is also a
virtual CPU, which simply is used to collect threads that are not tied to an
specific physical CPU, so it cannot be easily determined where they are running.
### Node
A *node* refers to a compute node, often a physical machine with memory and
network which may contain one or more
[sockets](https://en.wikipedia.org/wiki/CPU_socket), where each socket has one
or more CPUs.
### System
A system represents the complete set of hardware parts and software parts that
are known to ovni in a given trace.

View File

@ -0,0 +1,516 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="306.91663mm"
height="127.00001mm"
viewBox="0 0 306.91663 127.00001"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
sodipodi:docname="part-model.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="false"
inkscape:zoom="0.73049944"
inkscape:cx="629.70616"
inkscape:cy="280.62992"
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="-74.083327"
originy="-89.958345"
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="false" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-74.083328,-89.958344)">
<rect
style="fill:none;stroke:none;stroke-width:0.264999;stroke-linecap:square;stroke-dasharray:none;stroke-dashoffset:0"
id="rect33"
width="306.91663"
height="127.00001"
x="74.083328"
y="89.958344" />
<rect
style="fill:#ffeeaa;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none;stroke-dashoffset:0"
id="rect32"
width="121.70832"
height="84.666679"
x="253.99998"
y="127.00001" />
<text
xml:space="preserve"
style="font-size:6.35px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="290.19363"
y="202.25124"
id="text32"><tspan
sodipodi:role="line"
id="tspan32"
style="font-size:6.35px;stroke-width:0.264583"
x="290.19363"
y="202.25124">Hardware parts</tspan></text>
<rect
style="fill:#eeffaa;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none;stroke-dashoffset:0"
id="rect31"
width="169.33333"
height="84.666679"
x="79.374992"
y="127.00001" />
<rect
style="fill:#fff6d5;stroke:#000000;stroke-width:0.3;stroke-linecap:square;stroke-dasharray:none;stroke-dashoffset:0"
id="rect27"
width="47.625004"
height="21.166676"
x="269.87497"
y="148.16667"
ry="2.645834" />
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none"
id="rect1"
width="21.166662"
height="10.583329"
x="84.566666"
y="174.52502"
ry="0" />
<text
xml:space="preserve"
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="87.947342"
y="181.39488"
id="text1"><tspan
sodipodi:role="line"
id="tspan1"
style="stroke-width:0.264583"
x="87.947342"
y="181.39488">Thread</tspan></text>
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none"
id="rect3"
width="21.166664"
height="10.583337"
x="111.12499"
y="153.45834"
ry="0" />
<text
xml:space="preserve"
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="113.57446"
y="160.26309"
id="text3"><tspan
sodipodi:role="line"
id="tspan3"
style="stroke-width:0.264583"
x="113.57446"
y="160.26309">Process</tspan></text>
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none"
id="rect4"
width="21.166664"
height="10.583333"
x="111.12499"
y="174.62502"
ry="0" />
<text
xml:space="preserve"
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="114.50567"
y="181.49487"
id="text4"><tspan
sodipodi:role="line"
id="tspan4"
style="stroke-width:0.264583"
x="114.50567"
y="181.49487">Thread</tspan></text>
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none"
id="rect5"
width="21.166658"
height="10.583333"
x="137.58333"
y="174.62502"
ry="0" />
<text
xml:space="preserve"
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="140.964"
y="181.49487"
id="text5"><tspan
sodipodi:role="line"
id="tspan5"
style="stroke-width:0.264583"
x="140.964"
y="181.49487">Thread</tspan></text>
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none"
id="rect6"
width="21.166672"
height="10.583333"
x="169.33331"
y="174.62502"
ry="0" />
<text
xml:space="preserve"
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="172.71399"
y="181.49487"
id="text6"><tspan
sodipodi:role="line"
id="tspan6"
style="stroke-width:0.264583"
x="172.71399"
y="181.49487">Thread</tspan></text>
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none"
id="rect7"
width="20.966642"
height="10.38336"
x="195.99167"
y="153.55833"
ry="0" />
<text
xml:space="preserve"
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="198.24112"
y="160.16312"
id="text7"><tspan
sodipodi:role="line"
id="tspan7"
style="stroke-width:0.264583"
x="198.24112"
y="160.16312">Process</tspan></text>
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none"
id="rect8"
width="21.16667"
height="10.583333"
x="195.79164"
y="174.62502"
ry="0" />
<text
xml:space="preserve"
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="199.17232"
y="181.49487"
id="text8"><tspan
sodipodi:role="line"
id="tspan8"
style="stroke-width:0.264583"
x="199.17232"
y="181.49487">Thread</tspan></text>
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none"
id="rect9"
width="21.166666"
height="10.583333"
x="222.24997"
y="174.62502"
ry="0" />
<text
xml:space="preserve"
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="225.63065"
y="181.49487"
id="text9"><tspan
sodipodi:role="line"
id="tspan9"
style="stroke-width:0.264583"
x="225.63065"
y="181.49487">Thread</tspan></text>
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none"
id="rect10"
width="21.166658"
height="10.583337"
x="153.45833"
y="132.29167"
ry="0" />
<text
xml:space="preserve"
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="158.21979"
y="139.09644"
id="text10"><tspan
sodipodi:role="line"
id="tspan10"
style="stroke-width:0.264583"
x="158.21979"
y="139.09644">Loom</tspan></text>
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none"
id="rect11"
width="21.166651"
height="10.58334"
x="306.91666"
y="132.29167"
ry="0" />
<text
xml:space="preserve"
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="311.88068"
y="139.16154"
id="text11"><tspan
sodipodi:role="line"
id="tspan11"
style="stroke-width:0.264583"
x="311.88068"
y="139.16154">Node</tspan></text>
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none"
id="rect12"
width="15.875001"
height="10.583341"
x="275.16666"
y="153.45834"
ry="0" />
<text
xml:space="preserve"
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="278.86566"
y="160.291"
id="text12"><tspan
sodipodi:role="line"
id="tspan12"
style="stroke-width:0.264583"
x="278.86566"
y="160.291">CPU</tspan></text>
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none"
id="rect13"
width="15.874983"
height="10.583341"
x="296.33334"
y="153.45834"
ry="0" />
<text
xml:space="preserve"
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="300.03235"
y="160.291"
id="text13"><tspan
sodipodi:role="line"
id="tspan13"
style="stroke-width:0.264583"
x="300.03235"
y="160.291">CPU</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 121.70832,164.04168 0,10.58334"
id="path15"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect3"
inkscape:connection-end="#rect4" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 206.45046,163.94169 -0.0505,10.68333"
id="path16"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect7"
inkscape:connection-end="#rect8" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 212.94006,163.94169 13.30366,10.68333"
id="path17"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-end="#rect9"
inkscape:connection-start="#rect7" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 199.96086,163.94169 -13.40463,10.68333"
id="path18"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect7"
inkscape:connection-end="#rect6" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 128.32291,164.04168 13.22917,10.58334"
id="path19"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect3"
inkscape:connection-end="#rect5" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 115.03723,164.04168 -13.21614,10.48334"
id="path20"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect3"
inkscape:connection-end="#rect1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 153.45833,142.87501 -21.16667,10.58333"
id="path21"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect10"
inkscape:connection-end="#rect3" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 174.62499,142.86254 21.44212,10.69579"
id="path22"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect10"
inkscape:connection-end="#rect7" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 314.19269,142.87501 -6.61457,10.58333"
id="path24"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect11"
inkscape:connection-end="#rect13" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 308.90102,142.87501 291.04166,153.8654"
id="path25"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect11"
inkscape:connection-end="#rect12" />
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none"
id="rect25"
width="15.875013"
height="10.583337"
x="322.79163"
y="153.45834"
ry="0" />
<text
xml:space="preserve"
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="326.49063"
y="160.291"
id="text25"><tspan
sodipodi:role="line"
id="tspan25"
style="stroke-width:0.264583"
x="326.49063"
y="160.291">CPU</tspan></text>
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none"
id="rect26"
width="15.874991"
height="10.583337"
x="343.95831"
y="153.45834"
ry="0" />
<text
xml:space="preserve"
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="347.65732"
y="160.291"
id="text26"><tspan
sodipodi:role="line"
id="tspan26"
style="stroke-width:0.264583"
x="347.65732"
y="160.291">CPU</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 320.80727,142.87501 6.61457,10.58333"
id="path26"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect11"
inkscape:connection-end="#rect25" />
<path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 326.09894,142.87501 17.85937,10.99039"
id="path27"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect11"
inkscape:connection-end="#rect26" />
<path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.265;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 174.62499,139.70001 95.24998,19.05"
id="path28"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect10" />
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.2;stroke-linecap:square;stroke-dasharray:none"
id="rect29"
width="21.166666"
height="10.583335"
x="216.95831"
y="95.250008"
ry="0" />
<text
xml:space="preserve"
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="219.6889"
y="101.67236"
id="text29"><tspan
sodipodi:role="line"
id="tspan29"
style="stroke-width:0.264583"
x="219.6889"
y="101.67236">System</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 238.12498,104.89952 68.79168,28.32598"
id="path29"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect29"
inkscape:connection-end="#rect11" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 218.47022,105.83334 -45.35713,26.45833"
id="path30"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect29"
inkscape:connection-end="#rect10" />
<text
xml:space="preserve"
style="font-size:6.35px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
x="140.81671"
y="202.25124"
id="text31"><tspan
sodipodi:role="line"
id="tspan31"
style="font-size:6.35px;stroke-width:0.264583"
x="140.81671"
y="202.25124">Software parts</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 18 KiB

123
doc/user/concepts/trace.md Normal file
View File

@ -0,0 +1,123 @@
# 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.

474
doc/user/concepts/trace.svg Normal file
View File

@ -0,0 +1,474 @@
<?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>

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,7 +1,7 @@
# Emulator events
This is a exhaustive list of the events recognized by the emulator.
Built on Mar 20 2024.
Built on Nov 13 2024.
## Model nanos6
@ -395,7 +395,7 @@ List of events for the model *mpi* with identifier **`M`** at version `1.0.0`:
## Model ovni
List of events for the model *ovni* with identifier **`O`** at version `1.0.0`:
List of events for the model *ovni* with identifier **`O`** at version `1.1.0`:
<dl>
<dt><a id="OAr" href="#OAr"><pre>OAr(i32 cpu, i32 tid)</pre></a></dt>
<dd>changes the affinity of thread %{tid} to CPU %{cpu}</dd>
@ -427,11 +427,17 @@ List of events for the model *ovni* with identifier **`O`** at version `1.0.0`:
<dd>enters unordered event region</dd>
<dt><a id="OU]" href="#OU]"><pre>OU]</pre></a></dt>
<dd>leaves unordered event region</dd>
<dt><a id="OM[" href="#OM["><pre>OM[(i64 value, i32 type)</pre></a></dt>
<dd>push mark with value %{value} from type %{type}</dd>
<dt><a id="OM]" href="#OM]"><pre>OM](i64 value, i32 type)</pre></a></dt>
<dd>pop mark with value %{value} from type %{type}</dd>
<dt><a id="OM=" href="#OM="><pre>OM=(i64 value, i32 type)</pre></a></dt>
<dd>set mark with value %{value} from type %{type}</dd>
</dl>
## Model openmp
List of events for the model *openmp* with identifier **`P`** at version `1.1.0`:
List of events for the model *openmp* with identifier **`P`** at version `1.2.0`:
<dl>
<dt><a id="PBb" href="#PBb"><pre>PBb</pre></a></dt>
<dd>begins plain barrier</dd>
@ -557,6 +563,18 @@ List of events for the model *openmp* with identifier **`P`** at version `1.1.0`
<dd>begins initialization</dd>
<dt><a id="PCI" href="#PCI"><pre>PCI</pre></a></dt>
<dd>ceases initialization</dd>
<dt><a id="POc" href="#POc"><pre>POc+(u32 typeid, str label)</pre></a></dt>
<dd>creates a type %{typeid} with label &quot;%{label}&quot;</dd>
<dt><a id="PPc" href="#PPc"><pre>PPc(u32 taskid, u32 typeid)</pre></a></dt>
<dd>creates the task %{taskid} with type %{typeid}</dd>
<dt><a id="PPx" href="#PPx"><pre>PPx(u32 taskid)</pre></a></dt>
<dd>executes the task %{taskid}</dd>
<dt><a id="PPe" href="#PPe"><pre>PPe(u32 taskid)</pre></a></dt>
<dd>ends the task %{taskid}</dd>
<dt><a id="PQx" href="#PQx"><pre>PQx(u32 typeid)</pre></a></dt>
<dd>begins worksharing with type %{typeid}</dd>
<dt><a id="PQe" href="#PQe"><pre>PQe(u32 typeid)</pre></a></dt>
<dd>ends worksharing with type %{typeid}</dd>
</dl>
## Model tampi
@ -615,7 +633,7 @@ List of events for the model *tampi* with identifier **`T`** at version `1.0.0`:
## Model nosv
List of events for the model *nosv* with identifier **`V`** at version `2.1.0`:
List of events for the model *nosv* with identifier **`V`** at version `2.4.0`:
<dl>
<dt><a id="VTc" href="#VTc"><pre>VTc(u32 taskid, u32 typeid)</pre></a></dt>
<dd>creates task %{taskid} with type %{typeid}</dd>
@ -709,6 +727,18 @@ List of events for the model *nosv* with identifier **`V`** at version `2.1.0`:
<dd>enters nosv_barrier_wait()</dd>
<dt><a id="VAB" href="#VAB"><pre>VAB</pre></a></dt>
<dd>leaves nosv_barrier_wait()</dd>
<dt><a id="VAo" href="#VAo"><pre>VAo</pre></a></dt>
<dd>enters nosv_cond_wait()</dd>
<dt><a id="VAO" href="#VAO"><pre>VAO</pre></a></dt>
<dd>leaves nosv_cond_wait()</dd>
<dt><a id="VAg" href="#VAg"><pre>VAg</pre></a></dt>
<dd>enters nosv_cond_signal()</dd>
<dt><a id="VAG" href="#VAG"><pre>VAG</pre></a></dt>
<dd>leaves nosv_cond_signal()</dd>
<dt><a id="VAk" href="#VAk"><pre>VAk</pre></a></dt>
<dd>enters nosv_cond_broadcast()</dd>
<dt><a id="VAK" href="#VAK"><pre>VAK</pre></a></dt>
<dd>leaves nosv_cond_broadcast()</dd>
<dt><a id="VHa" href="#VHa"><pre>VHa</pre></a></dt>
<dd>enters nosv_attach()</dd>
<dt><a id="VHA" href="#VHA"><pre>VHA</pre></a></dt>
@ -721,4 +751,10 @@ List of events for the model *nosv* with identifier **`V`** at version `2.1.0`:
<dd>begins execution as delegate</dd>
<dt><a id="VHD" href="#VHD"><pre>VHD</pre></a></dt>
<dd>ceases execution as delegate</dd>
<dt><a id="VPp" href="#VPp"><pre>VPp</pre></a></dt>
<dd>sets progress state to Progressing</dd>
<dt><a id="VPr" href="#VPr"><pre>VPr</pre></a></dt>
<dd>sets progress state to Resting</dd>
<dt><a id="VPa" href="#VPa"><pre>VPa</pre></a></dt>
<dd>sets progress state to Absorbing</dd>
</dl>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -47,7 +47,7 @@ the following elements:
- A single byte model identification (for example `O`).
- A set of runtime events with that model identification (see the [list
of events](events)).
of events](events.md)).
- Rules that determine which sequences of events are valid.
- The emulation hooks that process each event and modify the state of
the emulator.

View File

@ -60,4 +60,47 @@ For more details, see [this MR][1].
The subsystem view provides a simplified view on what is the nOS-V
runtime doing over time. The view follows the same rules described in
the [subsystem view of Nanos6](../nanos6/#subsystem_view).
the [subsystem view of Nanos6](nanos6.md/#subsystem_view).
## Idle view
The idle view shows the progress state of the running threads:
*Progressing* and *Resting*. The *Progressing* state is shown when they
are making useful progress and the *Resting* state when they are waiting
for work. When workers start running, by definition, they begin in the
Progressing state and there are some situations that make them
transition to Resting:
- When workers are waiting in the delegation lock after some spins or
when instructed to go to sleep.
- When the server is trying to serve tasks, but there are no more tasks
available.
They will go back to Progressing as soon as they receive work. The
specific points at which they do so can be read in [nOS-V source
code](https://gitlab.bsc.es/nos-v/nos-v) by looking at the
`instr_worker_resting()` and `instr_worker_progressing()` trace points.
This view is intended to detect parts of the execution time on which the
workers don't have work, typically because the application doesn't have
enough parallelism or the scheduler is unable to serve work fast enough.
## Breakdown view
The breakdown view displays a summary of what is happening in all CPUs
by mixing in a single timeline the subsystem, idle and task type views.
Specifically, it shows how many CPUs are resting as defined by the idle
view, how many are inside a given task by showing the task type label,
and how many are in a particular subsystem of the runtime.
!!! Important
You must specify *ovni.level = 3* or higher in *nosv.toml* and pass
the *-b* option to ovniemu to generate the breakdown view.
Notice that the vertical axis shows the **number**
of CPUs in that state, not the physical CPUs like other views.
Here is an example of the Heat mini-app:
![Breakdown example](fig/breakdown-nosv.png)

View File

@ -8,21 +8,20 @@ refer to the
The [LLVM OpenMP Runtime](https://openmp.llvm.org/design/Runtimes.html) provides
an implementation of the OpenMP specification as a component of the LLVM
compiler infrastructure. We have modified the LLVM OpenMP runtime to run on top
compiler infrastructure. We have modified the LLVM OpenMP runtime (libomp) to run on top
of the [nOS-V](https://gitlab.bsc.es/nos-v/nos-v) runtime as part of the
[OmpSs-2 LLVM compiler](https://pm.bsc.es/llvm-ompss), named **OpenMP-V**.
[OmpSs-2 LLVM compiler](https://pm.bsc.es/llvm-ompss), named **libompv**.
We have added instrumentation events to OpenMP-V designed to be enabled along
We have added instrumentation events to libompv designed to be enabled along
the [nOS-V instrumentation](nosv.md). This document describes all the
instrumentation features included in our modified OpenMP-V runtime to identify
instrumentation features included in our modified libompv runtime to identify
what is happening. This data is useful for both users and developers of the
OpenMP runtime to analyze issues and undesired behaviors.
!!! Note
Instrumenting the original OpenMP runtime from the LLVM project is planned
but is not yet posible. For now you must use the modified OpenMP-V runtime
with nOS-V.
Instrumenting libomp is planned but is not yet posible.
For now you must use libompv.
## Enable the instrumentation
@ -33,25 +32,25 @@ To generate runtime traces, you will have to:
documentation](https://github.com/bsc-pm/nos-v/blob/master/docs/user/tracing.md).
Typically you should use the `--with-ovni` option at configure time to specify
where ovni is installed.
2. **Build OpenMP-V with ovni and nOS-V support:** Use the `PKG_CONFIG_PATH`
2. **Build libompv with ovni and nOS-V support:** Use the `PKG_CONFIG_PATH`
environment variable to specify the nOS-V and ovni installation
when configuring CMake.
3. **Enable the instrumentation in nOS-V at runtime:** Refer to the
[nOS-V documentation](https://github.com/bsc-pm/nos-v/blob/master/docs/user/tracing.md)
to find out how to enable the tracing at runtime. Typically you can just set
`NOSV_CONFIG_OVERRIDE="instrumentation.version=ovni"`.
4. **Enable the instrumentation of OpenMP-V at runtime:** Set the environment
4. **Enable the instrumentation of libompv at runtime:** Set the environment
variable `OMP_OVNI=1`.
Currently there is only support for the subsystem view, which is documented
below. The view is complemented with the information of [nOS-V views](nosv.md),
as OpenMP-V uses nOS-V tasks to run the workers.
Next sections describe each of the views included for analysis.
## Subsystem view
![Subsystem view example](fig/openmp-subsystem.png)
This view illustrates the activities of each thread with different states:
The view is complemented with the information of [nOS-V views](nosv.md),
as libompv uses nOS-V tasks to run the workers.
Subsystem illustrates the activities of each thread with different states:
- **Work-distribution subsystem**: Related to work-distribution constructs,
[in Chapter 11][workdis].
@ -135,9 +134,9 @@ This view illustrates the activities of each thread with different states:
- **Fork call**: Preparing a parallel section using the fork-join model.
Only called from the master thread.
- **Init**: Initializing the OpenMP-V runtime.
- **Init**: Initializing the libompv runtime.
- **Internal microtask**: Running a internal OpenMP-V function as a microtask.
- **Internal microtask**: Running a internal libompv function as a microtask.
- **User microtask**: Running user code as a microtask in a worker thread.
@ -156,9 +155,31 @@ This view illustrates the activities of each thread with different states:
[critical]: https://www.openmp.org/wp-content/uploads/OpenMP-API-Specification-5-2.pdf#section.15.2
[barrier]: https://www.openmp.org/wp-content/uploads/OpenMP-API-Specification-5-2.pdf#section.15.3
## Label view
The label view displays the text in the `label()` clause of OpenMP
tasks and work distribution constructs (static and dynamic for, single
and section). When the label is not provided, the source file and source
line location is used instead.
When nesting multiple tasks or work distribution constructs, only the
innermost label is shown.
Note that in this view, the numeric event value is a hash function of
the type label, so two distinct tasks (declared in different parts of
the code) with the same label will share the event value and have the
same color.
## Task ID view
The task ID view represents the numeric ID of the OpenMP task that is
currently running on each thread. The ID is a monotonically increasing
identifier assigned on task creation. Lower IDs correspond to tasks
created at an earlier point than higher IDs.
## Limitations
As the compiler generates the code that perform the calls to the OpenMP-V
As the compiler generates the code that perform the calls to the libompv
runtime, there are some parts of the execution that are complicated to
instrument by just placing a pair of events to delimite a function.

View File

@ -60,4 +60,4 @@ will set all the channels to an error state.
The emulator automatically switches the channels from one thread to
another when a thread is switched from the CPU. So the different models
don't need to worry about thread transitions. See the
[channels](../channels) section for more information.
[channels](../../dev/channels.md) section for more information.

View File

@ -27,10 +27,14 @@ Track changes in emulator model versions.
## Ovni
- ovni 1.1.0
- Add support for mark events `OM[`, `OM]` and `OM=`
- ovni 1.0.0: Initial version
## OpenMP
- openmp 1.2.0:
- Add support for labels and task ID views
- openmp 1.1.0: Initial version
## TAMPI
@ -39,9 +43,15 @@ Track changes in emulator model versions.
## nOS-V
- nosv 2.4.0
- Add support for `nosv_cond_wait`, `nosv_cond_signal` and `nosv_cond_broadcast` events VA{oOgGkK}.
- nosv 2.3.0
- Add `nosv.can_breakdown` attribute to metadata for breakdown checks.
- nosv 2.2.0
- Add support for progress events `VP{pra}`.
- nosv 2.1.0
- Add support for `nosv_mutex_lock`, `nosv_mutex_trylock` and `nosv_mutex_unlock` events VA{lLtTuU}.
- Add support for `nosv_barrier_wait` event VA{bB}.
- Add support for `nosv_mutex_lock`, `nosv_mutex_trylock` and `nosv_mutex_unlock` events `VA{lLtTuU}`.
- Add support for `nosv_barrier_wait` event `VA{bB}`.
- nosv 2.0.0
- Add support for parallel tasks, adding a new `bodyid` argument in `VT*` events.
- Remove support for old attach events `VH{aA}`.

56
doc/user/runtime/env.md Normal file
View File

@ -0,0 +1,56 @@
# 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
underlying 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.

After

Width:  |  Height:  |  Size: 6.6 KiB

123
doc/user/runtime/index.md Normal file
View File

@ -0,0 +1,123 @@
# 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 following 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.
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.
3. **Init the thread**. Call `ovni_thread_init()` to initialize the thread.
Multiple attempts to initialize the same thread are ignored with a warning.
Must be called by all threads.
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
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 composed 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. The `ovni` model is implicitly required when calling
`ovni_thread_init()`, so there is no need to add it again.
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.
When emitting the CPUs with:
```c
void ovni_add_cpu(int index, int phyid);
```
The `index` will be used to identify the CPU in the loom and goes from 0 to N -
1, where N is the number of CPUs in the loom. It must match the index that is
used in affinity events when a thread switches to another CPU. The `phyid` is
only displayed in Paraver and is usually the same as the index, but it can be
different if there are multiple looms per node.
## Start the execution
The current thread must switch to the "Running" state before any event can be
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
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_flush()` 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 it to be consistent.

218
doc/user/runtime/mark.md Normal file
View File

@ -0,0 +1,218 @@
# Mark events
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.
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.
### 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);
```
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.
### Emit events
All mark channels begin with the default value *null*, which is not shown in
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.
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);
```
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
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.

View File

@ -1,127 +1,149 @@
# Trace specification
# Trace specification v3
!!! Important
This document refers to the trace specification for
the version 2
the version 3
The ovni instrumentation library stores the information collected in a
trace following the specification of this document.
The ovni instrumentation library libovni stores the information
collected in a runtime 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`.
Inside this directory you will find the loom directories with the prefix
`loom.`. The name of the loom is built from the `loom` parameter of
`ovni_proc_init()`, prefixing it with `loom.`.
Inside this directory you will find the loom directories. The name of
the loom directory is built from the `loom` parameter of `ovni_proc_init()`,
prefixing it with `loom.`.
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
specified in the `pid` argument to `ovni_proc_init()`.
Each process directory contains:
Inside each process there is one directory for each thread, composed by
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`.
- The thread streams, composed of:
- The binary stream like `thread.123.obs`
- The thread metadata like `thread.123.json`
```
ovni/loom.mio.nosv-u1000/proc.89719/thread.89719/stream.json
ovni/loom.mio.nosv-u1000/proc.89719/thread.89719/stream.obs
```
## Process metadata
This structure prevents collisions among threads with the same TID among nodes,
while allowing dumping events from a single thread, process or loom with
ovnidump.
!!! Important
## Stream metadata
Process metadata has version 2
The `stream.json` metadata file contains information about the part that
the stream is assigned to. This is generally used to determine the
hierarchy of the part model.
The process metadata file contains important information about the trace
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:
The JSON must be an object (dictionary) with the following mandatory
keys:
- `version`: a number specifying the version of the metadata format.
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`$).
Must have the value 3 for this version.
Here is an example of the `metadata.json` file:
The rest of information is stored for each model.
```
{
"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
}
]
}
```
In particular, the `ovni` model enforces the use of:
## Thread metadata
- `ovni.part`: the type of part this stream is assigned to, usually
`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).
!!! Important
### Thread stream metadata
Thread metadata has version 2
For `thread` streams, the following attributes are used.
The thread metadata stores constant information per thread, like the
process metadata. The information is stored in a dictionary, where the
name of the emulation models are used as keys. In particular, the
libovni library writes information in the "ovni" key, such as the
model requirements, and other information like the version of libovni
used. Example:
- `ovni.tid`: the TID of the thread (mandatory, per-thread).
- `ovni.pid`: the PID of the process that the thread belongs to (mandatory, per-thread).
- `ovni.app_id`: the application ID of the process (optional, per-process).
- `ovni.rank`: the rank of the MPI process (optional, per-process).
- `ovni.nranks`: number of total MPI processes (optional, per-process).
- `ovni.loom`: the name of the loom that the process belongs to (mandatory, per-process).
- `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
{
"version": 2,
"version": 3,
"ovni": {
"lib": {
"version": "1.4.0",
"commit": "unknown"
"version": "1.10.0",
"commit": "dirty"
},
"part": "thread",
"tid": 89719,
"pid": 89719,
"loom": "mio.nosv-u1000",
"app_id": 1,
"require": {
"ovni": "1.0.0"
}
"ovni": "1.1.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"
}
}
```
The metadata is written to disk when the thread is first initialized
and when the thread finishes.
## Thread binary streams
## Binary stream
!!! Important
Thread binary stream has version 1
Binary streams have version 1
Streams are a binary files that contains a succession of events with
monotonically increasing clock values. Streams have a small header and
the variable size events just after the header.
A binary stream is a binary file named `stream.obs` that contains a
succession of events with monotonically increasing clock values. They
have a small header and the variable size events just after the header.
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:
4 bytes too. Here is a figure of the data stored in disk on a little
endian machine:
![Stream](fig/stream.svg)
@ -145,7 +167,7 @@ payload:
- Normal events: with a payload up to 16 bytes
- Jumbo events: with a payload up to $`2^{32}`$ bytes
## Normal events
### Normal events
The normal events are composed of:
@ -178,7 +200,7 @@ In the following figure you can see each field annotated:
![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
data. The size of the jumbo data is stored as a 32 bits integer as a
@ -203,10 +225,10 @@ In the following figure you can see each field annotated:
![Jumbo event](fig/event-jumbo.svg)
## Design considerations
### Design considerations
The stream format has been designed to be very simple, so writing a
parser library would take no more than 2 days for a single developer.
The binary stream format has been designed to be very simple, so writing
a 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
event when no payload is used.
@ -239,11 +261,7 @@ 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
the streams.
## Limitations
### Limitations
The streams are designed to be read only forward, as they only contain
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.

View File

@ -1,94 +0,0 @@
# 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) 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
```

View File

@ -15,29 +15,33 @@
nosv = prev.nosv.override {
useGit = true;
gitBranch = "master";
gitCommit = "c698c16c0518e6afc68fb32ee6f1a0f65ca69327";
gitCommit = "3ca2f67993f85aa73c53f810ff12148189eae642";
};
nanos6 = prev.nanos6.override {
useGit = true;
gitBranch = "master";
gitCommit = "21fccec383a4136daf5919093a6ffcdc8c139bfe";
gitCommit = "f39ea57c67a613d098050e2bb251116a021e91e5";
};
nodes = prev.nodes.override {
useGit = true;
gitBranch = "master";
gitCommit = "70ce0ed0a20842d8eb3124aa5db5916fb6fc238f";
gitCommit = "c97d7ca6f885500121a94c75df429c788e8d6cf8";
};
clangOmpss2Unwrapped = prev.clangOmpss2Unwrapped.override {
useGit = true;
gitBranch = "master";
gitCommit = "b813108e2810c235480688ed7d1b0f1faf76e804";
gitCommit = "b7af30b36be3e7e90b33c5f01a3f7e3656df785f";
};
openmp = prev.openmp.overrideAttrs (old: {
# Newer version of LLVM OpenMP requires python3
nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ final.python3 ];
});
# Use a fixed commit for libovni
ovniFixed = prev.ovni.override {
useGit = true;
gitBranch = "master";
gitCommit = "68fc8b0eba299c3a7fa3833ace2c94933a26749e";
gitCommit = "3bbfe0f0ecdf58e3f46ebafdf2540680f990b76b";
};
# Build with the current source
ovniLocal = prev.ovni.overrideAttrs (old: rec {
@ -134,6 +138,38 @@
export ASAN_OPTIONS=detect_leaks=0
'';
});
ubsan = rt.overrideAttrs (old: {
pname = "ovni-ubsan";
cmakeFlags = old.cmakeFlags ++ [ "-DCMAKE_BUILD_TYPE=Ubsan" ];
});
armv7 = (pkgs.pkgsCross.armv7l-hf-multiplatform.ovniLocal.overrideAttrs (old: {
pname = "ovni-armv7";
buildInputs = [];
nativeBuildInputs = [ pkgs.pkgsCross.armv7l-hf-multiplatform.buildPackages.cmake ];
cmakeFlags = old.cmakeFlags ++ [ "-DUSE_MPI=OFF" ];
})).overrideDerivation (old: {
doCheck = true;
});
aarch64 = (pkgs.pkgsCross.aarch64-multiplatform.ovniLocal.overrideAttrs (old: {
pname = "ovni-aarch64";
buildInputs = [];
nativeBuildInputs = [ pkgs.pkgsCross.aarch64-multiplatform.buildPackages.cmake ];
cmakeFlags = old.cmakeFlags ++ [ "-DUSE_MPI=OFF" ];
})).overrideDerivation (old: {
doCheck = true;
});
riscv64 = (pkgs.pkgsCross.riscv64.ovniLocal.overrideAttrs (old: {
pname = "ovni-riscv64";
buildInputs = [];
nativeBuildInputs = [ pkgs.pkgsCross.riscv64.buildPackages.cmake ];
cmakeFlags = old.cmakeFlags ++ [ "-DUSE_MPI=OFF" ];
})).overrideDerivation (old: {
doCheck = true;
});
};
};
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: MIT */
#ifndef OVNI_H
@ -18,7 +18,7 @@ extern "C" {
#include <string.h>
#include <sys/types.h>
#define OVNI_METADATA_VERSION 2
#define OVNI_METADATA_VERSION 3
#define OVNI_TRACEDIR "ovni"
#define OVNI_MAX_HOSTNAME 512
@ -31,6 +31,9 @@ extern "C" {
#define OVNI_STREAM_EXT ".obs"
/* Version of the ovni model for events */
#define OVNI_MODEL_VERSION "1.1.0"
/* Follow https://semver.org rules for versioning */
#define OVNI_LIB_VERSION "@PROJECT_VERSION@"
#define OVNI_GIT_COMMIT "@OVNI_GIT_COMMIT@"
@ -130,6 +133,28 @@ void ovni_ev_jumbo_emit(struct ovni_ev *ev, const uint8_t *buf, uint32_t bufsize
void ovni_flush(void);
/* Attributes */
int ovni_attr_has(const char *key);
void ovni_attr_set_double(const char *key, double num);
void ovni_attr_set_boolean(const char *key, int value);
void ovni_attr_set_str(const char *key, const char *value);
void ovni_attr_set_json(const char *key, const char *json);
double ovni_attr_get_double(const char *key);
int ovni_attr_get_boolean(const char *key);
const char *ovni_attr_get_str(const char *key);
char *ovni_attr_get_json(const char *key);
void ovni_attr_flush(void);
/* Mark */
enum ovni_mark_flags {
OVNI_MARK_STACK = 1, /*< Use push/pop instead of set */
};
void ovni_mark_type(int32_t type, long flags, const char *title);
void ovni_mark_label(int32_t type, int64_t value, const char *label);
void ovni_mark_push(int32_t type, int64_t value);
void ovni_mark_pop(int32_t type, int64_t value);
void ovni_mark_set(int32_t type, int64_t value);
#ifdef __cplusplus
}
#endif

View File

@ -23,10 +23,14 @@ markdown_extensions:
nav:
- index.md
- 'User guide':
- user/concepts.md
- user/installation.md
- 'Concepts':
- user/concepts/part-model.md
- user/concepts/trace.md
- 'Runtime':
- user/runtime/tracing.md
- user/runtime/index.md
- user/runtime/env.md
- user/runtime/mark.md
- user/runtime/distributed.md
- user/runtime/kernel.md
- user/runtime/trace_spec.md

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: MIT */
#include "common.h"
@ -45,7 +45,7 @@ vaerr(const char *prefix, const char *func, const char *errstr, va_list ap)
vfprintf(stderr, errstr, ap);
int len = strlen(errstr);
int len = (int) strlen(errstr);
if (len > 0) {
char last = errstr[len - 1];
@ -103,7 +103,7 @@ mkpath(const char *path, mode_t mode, int is_dir)
char *copypath = strdup(path);
/* Remove trailing slash */
int last = strlen(path) - 1;
int last = (int) strlen(path) - 1;
while (last > 0 && copypath[last] == '/')
copypath[last--] = '\0';

View File

@ -6,6 +6,7 @@
#include <stdio.h>
#include <sys/types.h>
#include <inttypes.h>
extern int is_debug_enabled;
@ -18,8 +19,8 @@ int mkpath(const char *path, mode_t mode, int is_dir);
void progname_set(char *name);
const char *progname_get(void);
void enable_debug(void);
void verr(const char *prefix, const char *func, const char *errstr, ...);
void vdie(const char *prefix, const char *func, const char *errstr, ...);
void verr(const char *prefix, const char *func, const char *errstr, ...) __attribute__((format(printf, 3, 4)));
void vdie(const char *prefix, const char *func, const char *errstr, ...) __attribute__((format(printf, 3, 4)));
/* clang-format off */

View File

@ -30,7 +30,6 @@ add_library(emu STATIC
stream.c
trace.c
loom.c
metadata.c
mux.c
sort.c
path.c
@ -49,9 +48,11 @@ add_library(emu STATIC
value.c
ovni/event.c
ovni/setup.c
ovni/mark.c
nanos6/setup.c
nanos6/event.c
nanos6/breakdown.c
nosv/breakdown.c
nosv/setup.c
nosv/event.c
nodes/setup.c

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "bay.h"
@ -106,7 +106,7 @@ bay_add_cb(struct bay *bay, enum bay_cb_type type,
cb->func = func;
cb->arg = arg;
cb->bchan = bchan;
cb->type = type;
cb->type = (int) type;
cb->enabled = 0;
if (enabled)
@ -168,7 +168,7 @@ propagate_chan(struct bay_chan *bchan, enum bay_cb_type type)
struct bay_cb *cur = NULL;
/* New callbacks cannot be added while propagating a bay_chan */
DL_FOREACH(bchan->cb[type], cur) {
dbg("calling cb %p", cur->func);
dbg("calling cb %"PRIxPTR, (uintptr_t) cur->func);
if (cur->func(bchan->chan, cur->arg) != 0) {
err("callback failed for %s", bchan->chan->name);
return -1;

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2023-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "body.h"

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "chan.h"
@ -15,9 +15,11 @@ chan_init(struct chan *chan, enum chan_type type, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
int n = ARRAYLEN(chan->name);
size_t n = ARRAYLEN(chan->name);
int ret = vsnprintf(chan->name, n, fmt, ap);
if (ret >= n)
if (ret < 0)
die("vsnprintf failed");
else if ((size_t) ret >= n)
die("channel name too long");
va_end(ap);
@ -155,7 +157,7 @@ chan_push(struct chan *chan, struct value value)
/** Remove one value from the stack. Fails if the top of the stack
* doesn't match the expected value.
*
* @param expected The expected value on the top of the stack.
* @param evalue The expected value on the top of the stack.
*
* @return On success returns 0, otherwise returns -1.
*/
@ -182,10 +184,10 @@ chan_pop(struct chan *chan, struct value evalue)
struct value *value = &stack->values[stack->n - 1];
if (!value_is_equal(value, &evalue)) {
err("%s: unexpected value %s (expected %s)",
err("%s: expected value %s different from top of stack %s",
chan->name,
value_str(*value),
value_str(evalue));
value_str(evalue),
value_str(*value));
return -1;
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef CHAN_H
@ -70,7 +70,7 @@ chan_read(struct chan *chan, struct value *value)
return 0;
}
void chan_init(struct chan *chan, enum chan_type type, const char *fmt, ...);
void chan_init(struct chan *chan, enum chan_type type, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
USE_RET int chan_set(struct chan *chan, struct value value);
USE_RET int chan_push(struct chan *chan, struct value value);
USE_RET int chan_pop(struct chan *chan, struct value expected);

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "clkoff.h"
@ -59,7 +59,7 @@ cparse(struct clkoff *table, FILE *file)
if (buf[0] == '\n')
continue;
int ret = sscanf(buf, "%ld %s %lf %lf %lf",
int ret = sscanf(buf, "%" SCNd64 "%s %lf %lf %lf",
&e.index, e.name,
&e.median, &e.mean, &e.stdev);
@ -95,7 +95,7 @@ cindex(struct clkoff *table)
return -1;
}
table->index = calloc(table->nentries, sizeof(struct clkoff_entry *));
table->index = calloc((size_t) table->nentries, sizeof(struct clkoff_entry *));
if (table->index == NULL) {
err("calloc failed");

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "cpu.h"
@ -17,7 +17,7 @@
#include "utlist.h"
#include "value.h"
static const char chan_fmt[] = "cpu%ld.%s";
static const char chan_fmt[] = "cpu%"PRIi64".%s";
static const char *chan_name[CPU_CHAN_MAX] = {
[CPU_CHAN_NRUN] = "nrunning",
[CPU_CHAN_PID] = "pid_running",
@ -78,14 +78,14 @@ cpu_set_loom(struct cpu *cpu, struct loom *loom)
static int
set_name(struct cpu *cpu)
{
size_t i = loom_get_gindex(cpu->loom);
size_t j = cpu_get_phyid(cpu);
size_t i = (size_t) loom_get_gindex(cpu->loom);
size_t j = (size_t) cpu_get_phyid(cpu);
int n;
if (cpu->is_virtual)
n = snprintf(cpu->name, PATH_MAX, "vCPU %ld.*", i);
n = snprintf(cpu->name, PATH_MAX, "vCPU %zu.*", i);
else
n = snprintf(cpu->name, PATH_MAX, " CPU %ld.%ld", i, j);
n = snprintf(cpu->name, PATH_MAX, " CPU %zu.%zu", i, j);
if (n >= PATH_MAX) {
err("cpu name too long");
@ -162,7 +162,7 @@ cpu_connect(struct cpu *cpu, struct bay *bay, struct recorder *rec)
if (type < 0)
continue;
long row = cpu->gindex;
long row = (long) cpu->gindex;
long flags = prv_flags[i];
if (prv_register(prv, row, type, bay, c, flags)) {
err("prv_register failed");
@ -176,7 +176,7 @@ cpu_connect(struct cpu *cpu, struct bay *bay, struct recorder *rec)
struct pcf_value *
cpu_add_to_pcf_type(struct cpu *cpu, struct pcf_type *type)
{
return pcf_add_value(type, cpu->gindex + 1, cpu->name);
return pcf_add_value(type, (int) cpu->gindex + 1, cpu->name);
}
static struct thread *
@ -215,12 +215,12 @@ cpu_update(struct cpu *cpu)
}
}
cpu->nth_running = running;
cpu->nth_active = active;
cpu->nth_running = (size_t) running;
cpu->nth_active = (size_t) active;
/* Only virtual cpus can be oversubscribed */
if (cpu->nth_running > 1 && !cpu->is_virtual) {
err("physical cpu %s has %d threads running at the same time",
err("physical cpu %s has %zd threads running at the same time",
cpu->name, cpu->nth_running);
return -1;
}
@ -248,7 +248,7 @@ cpu_update(struct cpu *cpu)
err("chan_set pid failed");
return -1;
}
dbg("cpu%ld sets th_running to %s",
dbg("cpu%"PRIi64" sets th_running to %s",
cpu->gindex, value_str(gid_running));
if (chan_set(&cpu->chan[CPU_CHAN_THRUN], gid_running) != 0) {
err("chan_set gid_running failed");
@ -265,7 +265,7 @@ cpu_update(struct cpu *cpu)
}
/* Update nth_running number in the channel */
if (chan_set(&cpu->chan[CPU_CHAN_NRUN], value_int64(running)) != 0) {
if (chan_set(&cpu->chan[CPU_CHAN_NRUN], value_int64((int64_t) running)) != 0) {
err("chan_set nth_running failed");
return -1;
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "emu.h"
@ -118,18 +118,18 @@ panic(struct emu *emu)
if (emu->ev != NULL) {
err("event: ");
err(" mcv=%s", emu->ev->mcv);
err(" rclock=%ld", emu->ev->rclock);
err(" sclock=%ld", emu->ev->sclock);
err(" dclock=%ld", emu->ev->dclock);
err(" payload_size=%ld", emu->ev->payload_size);
err(" rclock=%"PRIi64, emu->ev->rclock);
err(" sclock=%"PRIi64, emu->ev->sclock);
err(" dclock=%"PRIi64, emu->ev->dclock);
err(" payload_size=%zd", emu->ev->payload_size);
err(" is_jumbo=%d", emu->ev->is_jumbo);
}
if (emu->stream != NULL) {
err("stream: ");
err(" relpath=%s", emu->stream->relpath);
err(" offset=%ld", emu->stream->offset);
err(" clock_offset=%ld", emu->stream->clock_offset);
err(" offset=%"PRIi64, emu->stream->offset);
err(" clock_offset=%"PRIi64, emu->stream->clock_offset);
}
err("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
}
@ -156,7 +156,7 @@ emu_step(struct emu *emu)
return -1;
}
dbg("----- mvc=%s dclock=%ld -----", emu->ev->mcv, emu->ev->dclock);
dbg("----- mcv=%s dclock=%"PRIi64" -----", emu->ev->mcv, emu->ev->dclock);
emu_stat_update(&emu->stat, &emu->player);

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "emu_ev.h"
@ -13,11 +13,11 @@ emu_ev(struct emu_ev *ev, const struct ovni_ev *oev,
ev->v = oev->header.value;
ev->mcv[3] = '\0';
ev->rclock = oev->header.clock;
ev->rclock = (int64_t) oev->header.clock;
ev->sclock = sclock;
ev->dclock = dclock;
ev->payload_size = ovni_payload_size(oev);
ev->payload_size = (size_t) ovni_payload_size(oev);
if (ev->payload_size > 0) {
ev->has_payload = 1;

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef EMU_PRV_H
@ -19,6 +19,8 @@ enum emu_prv_types {
PRV_NOSV_SUBSYSTEM = 13,
PRV_NOSV_RANK = 14,
PRV_NOSV_BODYID = 15,
PRV_NOSV_IDLE = 16,
PRV_NOSV_BREAKDOWN = 17,
PRV_TAMPI_SUBSYSTEM = 20,
PRV_MPI_FUNCTION = 25,
PRV_NODES_SUBSYSTEM = 30,
@ -31,7 +33,11 @@ enum emu_prv_types {
PRV_NANOS6_BREAKDOWN = 41,
PRV_KERNEL_CS = 45,
PRV_OPENMP_SUBSYSTEM = 50,
PRV_RESERVED = 100,
PRV_OPENMP_LABEL = 51,
PRV_OPENMP_TASKID = 52,
PRV_OVNI_MARK = 100,
/* User marks [100, 200) */
PRV_RESERVED = 200,
};
#endif /* EMU_PRV_H */

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "emu_stat.h"
@ -54,11 +54,9 @@ emu_stat_report(struct emu_stat *stat, struct player *player, int last)
double speed = stat->average ? avgspeed : instspeed;
if (last) {
int tmin = (int) (time_elapsed / 60.0);
int tsec = (int) ((time_elapsed / 60.0 - tmin) * 60.0);
info("%5.1f%% done at avg %.0f kev/s \n",
progress * 100.0, avgspeed * 1e-3, tmin, tsec);
info("processed %ld input events in %.2f s\n",
progress * 100.0, avgspeed * 1e-3);
info("processed %"PRIi64" input events in %.2f s\n",
nprocessed, time_elapsed);
} else {
int tmin = (int) (time_left / 60.0);

View File

@ -104,7 +104,7 @@ parse_arg(struct ev_spec *spec, char *arg)
}
/* Copy name */
size_t n = snprintf(argspec->name, sizeof(argspec->name), "%s", name);
size_t n = (size_t) snprintf(argspec->name, sizeof(argspec->name), "%s", name);
if (n >= sizeof(argspec->name)) {
err("argument name too long: %s", name);
return -1;
@ -363,8 +363,9 @@ print_arg(struct ev_arg *arg, const char *fmt, struct cursor *c, struct emu_ev *
#define CASE(TYPE) \
do { \
TYPE *data = (TYPE *) &payload[arg->offset]; \
n = snprintf(c->out, c->len, fmt, *data); \
TYPE data; \
memcpy(&data, &payload[arg->offset], sizeof(data)); \
n = snprintf(c->out, (size_t) c->len, fmt, data); \
if (n >= c->len) { \
err("no space for argument"); \
return -1; \
@ -386,8 +387,8 @@ print_arg(struct ev_arg *arg, const char *fmt, struct cursor *c, struct emu_ev *
char *data = (char *) &payload[arg->offset];
/* Here we trust the input string to
* contain a nil at the end */
int n = snprintf(c->out, c->len, fmt, data);
if (n >= c->len) {
int n = snprintf(c->out, (size_t) c->len, fmt, data);
if (n >= (int) c->len) {
err("no space for string argument");
return -1;
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "loom.h"
@ -8,15 +8,13 @@
#include "cpu.h"
#include "path.h"
#include "proc.h"
#include "stream.h"
#include "uthash.h"
static const char *loom_prefix = "loom.";
static void
set_hostname(char host[PATH_MAX], const char name[PATH_MAX])
{
/* Skip prefix */
const char *start = name + strlen(loom_prefix);
const char *start = name;
/* Copy until dot or end */
int i;
@ -30,10 +28,19 @@ set_hostname(char host[PATH_MAX], const char name[PATH_MAX])
host[i] = '\0';
}
int
loom_matches(const char *path)
const char *
loom_name(struct stream *s)
{
return path_has_prefix(path, loom_prefix);
JSON_Object *meta = stream_metadata(s);
const char *loom = json_object_dotget_string(meta, "ovni.loom");
if (loom == NULL) {
err("cannot get attribute ovni.loom for stream: %s",
s->relpath);
return NULL;
}
return loom;
}
int
@ -41,11 +48,6 @@ loom_init_begin(struct loom *loom, const char *name)
{
memset(loom, 0, sizeof(struct loom));
if (!path_has_prefix(name, loom_prefix)) {
err("loom name must start with '%s': %s", loom_prefix, name);
return -1;
}
if (strchr(name, '/') != NULL) {
err("loom name cannot contain '/': %s", name);
return -1;
@ -68,6 +70,99 @@ loom_init_begin(struct loom *loom, const char *name)
return 0;
}
/* Merges the metadata CPUs with the ones in the loom */
static int
load_cpus(struct loom *loom, JSON_Object *meta)
{
JSON_Array *cpuarray = json_object_dotget_array(meta, "ovni.loom_cpus");
/* It may not have the CPUs defined */
if (cpuarray == NULL)
return 0;
size_t ncpus = json_array_get_count(cpuarray);
if (ncpus == 0) {
err("empty 'cpus' array in metadata");
return -1;
}
for (size_t i = 0; i < ncpus; i++) {
JSON_Object *jcpu = json_array_get_object(cpuarray, i);
if (jcpu == NULL) {
err("json_array_get_object() failed for cpu");
return -1;
}
/* Cast from double */
int index = (int) json_object_get_number(jcpu, "index");
int phyid = (int) json_object_get_number(jcpu, "phyid");
/* The index can exceed ncpus-1 when CPUs are partially
* defined, but it cannot be negative. */
if (index < 0) {
err("cpu index %d out of bounds", index);
return -1;
}
struct cpu *cpu = loom_find_cpu(loom, phyid);
if (cpu) {
/* Ensure they have the same index */
if (cpu->index != index) {
err("mismatch index in existing cpu: %d", index);
return -1;
}
/* Duplicated, ignore */
continue;
}
/* If we reach this point, there shouldn't be a CPU with the
* same index either, as otherwise the phyid should have matched
* before. So it is an error. */
if (loom_get_cpu(loom, index) != NULL) {
err("cpu index %d redefined with another phyid", index);
return -1;
}
cpu = calloc(1, sizeof(struct cpu));
if (cpu == NULL) {
err("calloc failed:");
return -1;
}
cpu_init_begin(cpu, index, phyid, 0);
if (loom_add_cpu(loom, cpu) != 0) {
err("loom_add_cpu() failed");
return -1;
}
}
return 0;
}
/** Merges the given metadata with the one stored.
*
* It is an error to provide metadata that doesn't match with the already stored
* in the process.
*
* Precondition: The stream ovni.part must be "thread".
* Precondition: The stream version must be ok.
*/
int
loom_load_metadata(struct loom *loom, struct stream *s)
{
JSON_Object *meta = stream_metadata(s);
if (load_cpus(loom, meta) != 0) {
err("cannot load loom cpus");
return -1;
}
return 0;
}
void
loom_set_gindex(struct loom *loom, int64_t gindex)
{
@ -97,10 +192,8 @@ loom_get_cpu(struct loom *loom, int index)
if (index == -1)
return &loom->vcpu;
if (index < 0 || (size_t) index >= loom->ncpus) {
err("cpu index out of bounds");
if (index < 0 || (size_t) index >= loom->ncpus)
return NULL;
}
return loom->cpus_array[index];
}
@ -181,6 +274,44 @@ by_phyid(struct cpu *c1, struct cpu *c2)
return 0;
}
int
loom_set_rank_min(struct loom *loom)
{
if (loom->rank_min != INT_MAX) {
err("rank_min already set");
return -1;
}
/* Ensure that all processes have a rank */
for (struct proc *p = loom->procs; p; p = p->hh.next) {
if (p->rank >= 0) {
loom->rank_enabled = 1;
break;
}
}
if (!loom->rank_enabled) {
dbg("loom %s has no rank information", loom->name);
return 0;
}
/* Ensure that all processes have a rank */
for (struct proc *p = loom->procs; p; p = p->hh.next) {
if (p->rank < 0) {
err("process %s has no rank information", p->id);
return -1;
}
/* Compute rank_min for CPU sorting */
if (p->rank < loom->rank_min)
loom->rank_min = p->rank;
}
dbg("loom %s has rank_min %d", loom->name, loom->rank_min);
return 0;
}
void
loom_sort(struct loom *loom)
{
@ -198,22 +329,22 @@ loom_sort(struct loom *loom)
int
loom_init_end(struct loom *loom)
{
/* Set rank enabled */
for (struct proc *p = loom->procs; p; p = p->hh.next) {
if (p->rank >= 0) {
loom->rank_enabled = 1;
break;
}
/* rank_min must be set */
if (loom->rank_enabled && loom->rank_min == INT_MAX) {
err("rank_min not set");
return -1;
}
/* Ensure that all processes have a rank */
if (loom->rank_enabled) {
for (struct proc *p = loom->procs; p; p = p->hh.next) {
if (p->rank < 0) {
err("process %s has no rank information", p->id);
return -1;
}
}
/* It is not valid to define a loom without CPUs */
if (loom->ncpus == 0) {
err("loom %s has no physical CPUs", loom->name);
return -1;
}
/* Or without processes */
if (loom->nprocs == 0) {
err("loom %s has no processes", loom->name);
return -1;
}
/* Populate cpus_array */
@ -222,6 +353,7 @@ loom_init_end(struct loom *loom)
err("calloc failed:");
return -1;
}
for (struct cpu *c = loom->cpus; c; c = c->hh.next) {
int index = cpu_get_index(c);
if (index < 0 || (size_t) index >= loom->ncpus) {
@ -277,34 +409,6 @@ loom_add_proc(struct loom *loom, struct proc *proc)
return -1;
}
if (!proc->metadata_loaded) {
err("process %d hasn't loaded metadata", pid);
return -1;
}
if (loom->rank_enabled && proc->rank < 0) {
err("missing rank in process %d", pid);
return -1;
}
/* Check previous ranks if any */
if (!loom->rank_enabled && proc->rank >= 0) {
loom->rank_enabled = 1;
for (struct proc *p = loom->procs; p; p = p->hh.next) {
if (p->rank < 0) {
err("missing rank in process %d", p->pid);
return -1;
}
if (p->rank < loom->rank_min)
loom->rank_min = p->rank;
}
}
if (loom->rank_enabled && proc->rank < loom->rank_min)
loom->rank_min = proc->rank;
HASH_ADD_INT(loom->procs, pid, proc);
loom->nprocs++;

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef LOOM_H
@ -12,9 +12,10 @@
#include "cpu.h"
#include "extend.h"
struct proc;
struct stream;
struct loom {
size_t gindex;
int64_t gindex;
int is_init;
char name[PATH_MAX];
@ -50,8 +51,10 @@ struct loom {
struct extend ext;
};
USE_RET int loom_matches(const char *relpath);
USE_RET const char *loom_name(struct stream *s);
USE_RET int loom_init_begin(struct loom *loom, const char *name);
USE_RET int loom_load_metadata(struct loom *loom, struct stream *s);
USE_RET int loom_set_rank_min(struct loom *loom);
USE_RET int loom_init_end(struct loom *loom);
USE_RET int loom_add_cpu(struct loom *loom, struct cpu *cpu);
USE_RET int64_t loom_get_gindex(struct loom *loom);

View File

@ -1,159 +0,0 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "metadata.h"
#include <stdlib.h>
#include <string.h>
#include "cpu.h"
#include "loom.h"
#include "ovni.h"
#include "parson.h"
#include "proc.h"
#include "thread.h"
static JSON_Object *
load_json(const char *path)
{
JSON_Value *vmeta = json_parse_file_with_comments(path);
if (vmeta == NULL) {
err("json_parse_file_with_comments() failed");
return NULL;
}
JSON_Object *meta = json_value_get_object(vmeta);
if (meta == NULL) {
err("json_value_get_object() failed");
return NULL;
}
return meta;
}
static int
check_version(JSON_Object *meta)
{
JSON_Value *version_val = json_object_get_value(meta, "version");
if (version_val == NULL) {
err("missing attribute \"version\"");
return -1;
}
int version = (int) json_number(version_val);
if (version != OVNI_METADATA_VERSION) {
err("metadata version mismatch %d (expected %d)",
version, OVNI_METADATA_VERSION);
return -1;
}
return 0;
}
static int
has_cpus(JSON_Object *meta)
{
/* Only check for the "cpus" key, if it has zero elements is an error
* that will be reported later */
if (json_object_get_array(meta, "cpus") != NULL)
return 1;
return 0;
}
static int
load_cpus(struct loom *loom, JSON_Object *meta)
{
JSON_Array *cpuarray = json_object_get_array(meta, "cpus");
if (cpuarray == NULL) {
err("cannot find 'cpus' array");
return -1;
}
size_t ncpus = json_array_get_count(cpuarray);
if (ncpus == 0) {
err("empty 'cpus' array in metadata");
return -1;
}
if (loom->ncpus > 0) {
err("loom %s already has cpus", loom->id);
return -1;
}
for (size_t i = 0; i < ncpus; i++) {
JSON_Object *jcpu = json_array_get_object(cpuarray, i);
if (jcpu == NULL) {
err("json_array_get_object() failed for cpu");
return -1;
}
/* Cast from double */
int index = (int) json_object_get_number(jcpu, "index");
int phyid = (int) json_object_get_number(jcpu, "phyid");
struct cpu *cpu = calloc(1, sizeof(struct cpu));
if (cpu == NULL) {
err("calloc failed:");
return -1;
}
cpu_init_begin(cpu, index, phyid, 0);
if (loom_add_cpu(loom, cpu) != 0) {
err("loom_add_cpu() failed");
return -1;
}
}
return 0;
}
int
metadata_load_proc(const char *path, struct loom *loom, struct proc *proc)
{
JSON_Object *meta = load_json(path);
if (meta == NULL) {
err("cannot load proc metadata from file %s", path);
return -1;
}
if (check_version(meta) != 0) {
err("version check failed");
return -1;
}
/* The appid is populated from the metadata */
if (proc_load_metadata(proc, meta) != 0) {
err("cannot load process attributes");
return -1;
}
if (has_cpus(meta) && load_cpus(loom, meta) != 0) {
err("cannot load loom cpus");
return -1;
}
return 0;
}
int
metadata_load_thread(const char *path, struct thread *thread)
{
JSON_Object *meta = load_json(path);
if (meta == NULL) {
err("cannot load thread metadata from file %s", path);
return -1;
}
if (check_version(meta) != 0) {
err("version check failed");
return -1;
}
if (thread_load_metadata(thread, meta) != 0) {
err("cannot load thread attributes");
return -1;
}
return 0;
}

View File

@ -1,15 +0,0 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef METADATA_H
#define METADATA_H
#include "common.h"
struct loom;
struct proc;
struct thread;
USE_RET int metadata_load_proc(const char *path, struct loom *loom, struct proc *proc);
USE_RET int metadata_load_thread(const char *path, struct thread *thread);
#endif /* METADATA_H */

View File

@ -235,13 +235,6 @@ model_finish(struct model *model, struct emu *emu)
static int
should_enable(int have[3], struct model_spec *spec, struct thread *t)
{
static int compat = 0;
/* Enable all models if we are in compatibility model. Don't check other
* threads metadata */
if (compat)
return 1;
if (t->meta == NULL) {
err("missing metadata for thread %s", t->id);
return -1;
@ -249,12 +242,8 @@ should_enable(int have[3], struct model_spec *spec, struct thread *t)
JSON_Object *require = json_object_dotget_object(t->meta, "ovni.require");
if (require == NULL) {
warn("missing 'ovni.require' key in thread %s", t->id);
warn("loading trace in compatibility mode");
warn("all models will be enabled (expect slowdown)");
warn("use ovni_thread_require() to enable only required models");
compat = 1;
return 1;
err("missing 'ovni.require' key in thread %s", t->id);
return -1;
}
/* May not have the current model */

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "model_cpu.h"
@ -27,7 +27,7 @@ get_model_cpu(struct cpu *cpu, int id)
static int
init_chan(struct model_cpu *cpu, const struct model_chan_spec *spec, int64_t gindex)
{
cpu->track = calloc(spec->nch, sizeof(struct track));
cpu->track = calloc((size_t) spec->nch, sizeof(struct track));
if (cpu->track == NULL) {
err("calloc failed:");
return -1;
@ -40,7 +40,8 @@ init_chan(struct model_cpu *cpu, const struct model_chan_spec *spec, int64_t gin
const char *ch_name = spec->ch_names[i];
int track_mode = spec->track[i];
if (track_init(track, cpu->bay, TRACK_TYPE_TH, track_mode, "%s.cpu%ld.%s",
if (track_init(track, cpu->bay, TRACK_TYPE_TH, track_mode,
"%s.cpu%"PRIi64".%s",
name, gindex, ch_name) != 0) {
err("track_init failed");
return -1;
@ -107,7 +108,7 @@ connect_cpu(struct emu *emu, struct cpu *scpu, int id)
struct chan *sel = cpu_get_th_chan(scpu);
int64_t nthreads = emu->system.nthreads;
int64_t nthreads = (int64_t) emu->system.nthreads;
if (track_set_select(track, sel, NULL, nthreads) != 0) {
err("track_select failed");
return -1;

View File

@ -21,7 +21,7 @@ model_evspec_init(struct model_evspec *evspec, struct model_spec *spec)
}
/* Preallocate a contiguous map, as we know the size */
evspec->alloc = calloc(evspec->nevents, sizeof(struct ev_spec));
evspec->alloc = calloc((size_t) evspec->nevents, sizeof(struct ev_spec));
if (evspec->alloc == NULL) {
err("calloc failed:");
return -1;
@ -64,7 +64,7 @@ model_evspec_init(struct model_evspec *evspec, struct model_spec *spec)
}
struct ev_spec *
model_evspec_find(struct model_evspec *evspec, char mcv[4])
model_evspec_find(struct model_evspec *evspec, char *mcv)
{
struct ev_spec *s = NULL;
HASH_FIND_STR(evspec->spec, mcv, s);

View File

@ -19,6 +19,6 @@ struct model_evspec {
};
USE_RET int model_evspec_init(struct model_evspec *evspec, struct model_spec *spec);
USE_RET struct ev_spec *model_evspec_find(struct model_evspec *evspec, char mcv[4]);
USE_RET struct ev_spec *model_evspec_find(struct model_evspec *evspec, char *mcv);
#endif /* MODEL_EVSPEC_H */

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "model_pvt.h"
@ -35,7 +35,7 @@ create_values(const struct model_pvt_spec *pvt,
return 0;
for (const struct pcf_value_label *p = q; p->label != NULL; p++) {
if (pcf_add_value(t, p->value, p->label) == NULL) {
if (pcf_add_value(t, (int) p->value, p->label) == NULL) {
err("pcf_add_value failed");
return -1;
}
@ -66,7 +66,7 @@ create_type(const struct model_pvt_spec *pvt,
return -1;
}
struct pcf_type *pcftype = pcf_add_type(pcf, type, label);
struct pcf_type *pcftype = pcf_add_type(pcf, (int) type, label);
if (pcftype == NULL) {
err("pcf_add_type failed");
return -1;
@ -106,7 +106,7 @@ connect_cpu_prv(struct emu *emu, struct cpu *scpu, struct prv *prv, int id)
for (int i = 0; i < spec->nch; i++) {
struct chan *out = track_get_output(&cpu->track[i]);
long type = spec->pvt->type[i];
long row = scpu->gindex;
long row = (long) scpu->gindex;
long flags = flags_arr ? flags_arr[i] : 0;
if (prv_register(prv, row, type, &emu->bay, out, flags)) {
err("prv_register failed");
@ -158,7 +158,7 @@ connect_thread_prv(struct emu *emu, struct thread *sth, struct prv *prv, int id)
for (int i = 0; i < spec->nch; i++) {
struct chan *out = track_get_output(&th->track[i]);
long type = spec->pvt->type[i];
long row = sth->gindex;
long row = (long) sth->gindex;
long flags = flags_arr ? flags_arr[i] : 0;
if (prv_register(prv, row, type, &emu->bay, out, flags)) {
err("prv_register failed");
@ -178,7 +178,7 @@ model_pvt_connect_thread(struct emu *emu, const struct model_thread_spec *spec)
/* Get cpu PRV */
struct pvt *pvt = recorder_find_pvt(&emu->recorder, "thread");
if (pvt == NULL) {
err("cannot find cpu pvt");
err("cannot find thread pvt");
return -1;
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "model_thread.h"
@ -19,10 +19,10 @@
static int
init_chan(struct model_thread *th, const struct model_chan_spec *spec, int64_t gindex)
{
const char *fmt = "%s.thread%ld.%s";
const char *fmt = "%s.thread%"PRIi64".%s";
const char *prefix = spec->prefix;
th->ch = calloc(spec->nch, sizeof(struct chan));
th->ch = calloc((size_t) spec->nch, sizeof(struct chan));
if (th->ch == NULL) {
err("calloc failed:");
return -1;
@ -30,7 +30,7 @@ init_chan(struct model_thread *th, const struct model_chan_spec *spec, int64_t g
for (int i = 0; i < spec->nch; i++) {
struct chan *c = &th->ch[i];
int type = spec->ch_stack[i];
enum chan_type type = spec->ch_stack[i] ? CHAN_STACK : CHAN_SINGLE;
const char *ch_name = spec->ch_names[i];
chan_init(c, type, fmt, prefix, gindex, ch_name);
@ -45,7 +45,7 @@ init_chan(struct model_thread *th, const struct model_chan_spec *spec, int64_t g
}
}
th->track = calloc(spec->nch, sizeof(struct track));
th->track = calloc((size_t) spec->nch, sizeof(struct track));
if (th->track == NULL) {
err("calloc failed:");
return -1;

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "mux.h"
@ -25,7 +25,7 @@ default_select(struct mux *mux,
int64_t index = key.i;
if (index < 0 || index >= mux->ninputs) {
err("index out of bounds %ld", index);
err("index out of bounds %"PRIi64, index);
return -1;
}
@ -177,7 +177,7 @@ mux_init(struct mux *mux,
mux->select = select;
mux->output = output;
mux->ninputs = ninputs;
mux->inputs = calloc(ninputs, sizeof(struct mux_input));
mux->inputs = calloc((size_t) ninputs, sizeof(struct mux_input));
mux->def = value_null();
if (mux->inputs == NULL) {
@ -214,7 +214,7 @@ mux_set_input(struct mux *mux, int64_t index, struct chan *chan)
struct mux_input *input = &mux->inputs[index];
if (input->chan != NULL) {
err("input %d already has a channel", index);
err("input %"PRIi64" already has a channel", index);
return -1;
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2023-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "breakdown.h"
@ -32,8 +32,8 @@ static int
create_cpu(struct bay *bay, struct breakdown_cpu *bcpu, int64_t gindex)
{
enum chan_type t = CHAN_SINGLE;
chan_init(&bcpu->tr, t, "nanos6.cpu%ld.breakdown.tr", gindex);
chan_init(&bcpu->tri, t, "nanos6.cpu%ld.breakdown.tri", gindex);
chan_init(&bcpu->tr, t, "nanos6.cpu%"PRIi64".breakdown.tr", gindex);
chan_init(&bcpu->tri, t, "nanos6.cpu%"PRIi64".breakdown.tri", gindex);
/* Register all channels in the bay */
if (bay_register(bay, &bcpu->tr) != 0) {
@ -59,12 +59,12 @@ model_nanos6_breakdown_create(struct emu *emu)
/* Count phy cpus */
struct system *sys = &emu->system;
int64_t nphycpus = sys->ncpus - sys->nlooms;
int64_t nphycpus = (int64_t) (sys->ncpus - sys->nlooms);
bemu->nphycpus = nphycpus;
/* Create a new Paraver trace */
struct recorder *rec = &emu->recorder;
bemu->pvt = recorder_add_pvt(rec, "nanos6-breakdown", nphycpus);
bemu->pvt = recorder_add_pvt(rec, "nanos6-breakdown", (long) nphycpus);
if (bemu->pvt == NULL) {
err("recorder_add_pvt failed");
return -1;
@ -131,7 +131,7 @@ select_tr(struct mux *mux, struct value value, struct mux_input **input)
int64_t i = in_body;
char *inputs[] = { "subsystem", "task_type" };
dbg("selecting input %ld (%s)", i, inputs[i]);
dbg("selecting input %"PRIi64" (%s)", i, inputs[i]);
*input = mux_get_input(mux, i);
return 0;
@ -239,8 +239,13 @@ model_nanos6_breakdown_connect(struct emu *emu)
long type = PRV_NANOS6_BREAKDOWN;
long flags = PRV_SKIPDUP;
/* We may emit zero at the start, when an input changes and all
* the other sort output channels write a zero in the output,
* before the last value is set in prv.c. */
flags |= PRV_ZERO;
struct chan *out = sort_get_output(&bemu->sort, i);
if (prv_register(prv, i, type, bay, out, flags)) {
if (prv_register(prv, (long) i, type, bay, out, flags)) {
err("prv_register failed");
return -1;
}
@ -263,7 +268,7 @@ model_nanos6_breakdown_finish(struct emu *emu,
struct pcf *pcf = pvt_get_pcf(bemu->pvt);
long typeid = PRV_NANOS6_BREAKDOWN;
char label[] = "CPU: Nanos6 Runtime/Idle/Task breakdown";
struct pcf_type *pcftype = pcf_add_type(pcf, typeid, label);
struct pcf_type *pcftype = pcf_add_type(pcf, (int) typeid, label);
const struct pcf_value_label *v = NULL;
/* Emit subsystem values */
@ -297,12 +302,12 @@ model_nanos6_breakdown_finish(struct emu *emu,
struct prf *prf = pvt_get_prf(bemu->pvt);
for (int64_t row = 0; row < bemu->nphycpus; row++) {
char name[128];
if (snprintf(name, 128, "~CPU %4ld", bemu->nphycpus - row) >= 128) {
if (snprintf(name, 128, "~CPU %4" PRIi64, bemu->nphycpus - row) >= 128) {
err("label too long");
return -1;
}
if (prf_add(prf, row, name) != 0) {
if (prf_add(prf, (long) row, name) != 0) {
err("prf_add failed for %s", name);
return -1;
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "nanos6_priv.h"
@ -299,7 +299,7 @@ update_task_state(struct emu *emu)
static int
expand_transition_value(struct emu *emu, int was_running, int runs_now, char *tr_p)
{
char tr = emu->ev->v;
char tr = (char) emu->ev->v;
/* Ensure we don't clobber the value */
if (tr == 'X' || tr == 'E') {
@ -419,7 +419,7 @@ update_task(struct emu *emu)
struct task *next = bnext == NULL ? NULL : body_get_task(bnext);
/* Update the subsystem channel */
if (update_task_ss_channel(emu, emu->ev->v) != 0) {
if (update_task_ss_channel(emu, (char) emu->ev->v) != 0) {
err("update_task_ss_channel failed");
return -1;
}
@ -467,7 +467,7 @@ create_task(struct emu *emu)
* task, so we relax the model to allow this for now. */
flags |= TASK_FLAG_RELAX_NESTING;
if (task_create(info, type_id, task_id, flags) != 0) {
if (task_create(info, type_id, task_id, (uint32_t) flags) != 0) {
err("task_create failed");
return -1;
}
@ -521,7 +521,8 @@ pre_type(struct emu *emu)
}
const uint8_t *data = &emu->ev->payload->jumbo.data[0];
uint32_t typeid = *(uint32_t *) data;
uint32_t typeid;
memcpy(&typeid, data, 4); /* May be unaligned */
data += 4;
const char *label = (const char *) data;

View File

@ -402,7 +402,7 @@ finish_pvt(struct emu *emu, const char *name)
}
struct pcf *pcf = pvt_get_pcf(pvt);
long typeid = pvt_type[CH_TYPE];
struct pcf_type *pcftype = pcf_find_type(pcf, typeid);
struct pcf_type *pcftype = pcf_find_type(pcf, (int) typeid);
for (struct proc *p = sys->procs; p; p = p->gnext) {
struct nanos6_proc *proc = EXT(p, model_id);

342
src/emu/nosv/breakdown.c Normal file
View File

@ -0,0 +1,342 @@
/* Copyright (c) 2023-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "breakdown.h"
#include <stdint.h>
#include <stdio.h>
#include "bay.h"
#include "chan.h"
#include "common.h"
#include "cpu.h"
#include "emu.h"
#include "emu_args.h"
#include "emu_prv.h"
#include "extend.h"
#include "model_cpu.h"
#include "mux.h"
#include "nosv_priv.h"
#include "proc.h"
#include "pv/pcf.h"
#include "pv/prf.h"
#include "pv/prv.h"
#include "pv/pvt.h"
#include "recorder.h"
#include "sort.h"
#include "system.h"
#include "thread.h"
#include "task.h"
#include "track.h"
#include "value.h"
static int
create_cpu(struct bay *bay, struct nosv_breakdown_cpu *bcpu, int64_t gindex)
{
enum chan_type t = CHAN_SINGLE;
chan_init(&bcpu->tr, t, "nosv.cpu%"PRIi64".breakdown.tr", gindex);
chan_init(&bcpu->tri, t, "nosv.cpu%"PRIi64".breakdown.tri", gindex);
/* Register all channels in the bay */
if (bay_register(bay, &bcpu->tr) != 0) {
err("bay_register tr failed");
return -1;
}
if (bay_register(bay, &bcpu->tri) != 0) {
err("bay_register tri failed");
return -1;
}
return 0;
}
static int
check_thread_metadata(struct thread *th)
{
if (th->meta == NULL) {
err("thread has no metadata");
return -1;
}
JSON_Value *val = json_object_dotget_value(th->meta, "nosv.can_breakdown");
if (val == NULL) {
err("missing nosv.can_breakdown attribute");
return -1;
}
if (!json_value_get_boolean(val)) {
err("nosv.can_breakdown is false, missing events to enable breakdown");
return -1;
}
return 0;
}
int
model_nosv_breakdown_create(struct emu *emu)
{
if (emu->args.breakdown == 0)
return 0;
struct nosv_emu *memu = EXT(emu, 'V');
struct nosv_breakdown_emu *bemu = &memu->breakdown;
/* Count phy cpus */
struct system *sys = &emu->system;
int64_t nphycpus = (int64_t) (sys->ncpus - sys->nlooms);
bemu->nphycpus = nphycpus;
/* Create a new Paraver trace */
struct recorder *rec = &emu->recorder;
bemu->pvt = recorder_add_pvt(rec, "nosv-breakdown", (long) nphycpus);
if (bemu->pvt == NULL) {
err("recorder_add_pvt failed");
return -1;
}
if (sort_init(&bemu->sort, &emu->bay, nphycpus, "nosv.breakdown.sort") != 0) {
err("sort_init failed");
return -1;
}
for (struct cpu *cpu = sys->cpus; cpu; cpu = cpu->next) {
if (cpu->is_virtual)
continue;
struct nosv_cpu *mcpu = EXT(cpu, 'V');
struct nosv_breakdown_cpu *bcpu = &mcpu->breakdown;
if (create_cpu(&emu->bay, bcpu, cpu->gindex) != 0) {
err("create_cpu failed");
return -1;
}
}
for (struct thread *th = emu->system.threads; th; th = th->gnext) {
if (check_thread_metadata(th) != 0) {
err("bad nosv metadata in thread: %s", th->id);
return -1;
}
}
return 0;
}
static int
select_tr(struct mux *mux, struct value value, struct mux_input **input)
{
/* Only select the task if we are in ST_TASK_BODY and the task_type has
* a non-null value */
int64_t in_body = (value.type == VALUE_INT64 && value.i == ST_TASK_BODY);
if (in_body) {
struct value tt;
struct mux_input *ttinput = mux_get_input(mux, 1);
if (chan_read(ttinput->chan, &tt) != 0) {
err("chan_read failed");
return -1;
}
/* Only show task type if we have a task */
if (tt.type == VALUE_NULL)
in_body = 0;
}
if (!in_body) {
/* Only select ss if not NULL */
struct value ss;
struct mux_input *ssinput = mux_get_input(mux, 0);
if (chan_read(ssinput->chan, &ss) != 0) {
err("chan_read failed");
return -1;
}
/* Don't select anything, so the default output is shown */
if (ss.type == VALUE_NULL) {
dbg("not selecting anything");
*input = NULL;
return 0;
}
}
int64_t i = in_body;
char *inputs[] = { "subsystem", "task_type" };
dbg("selecting input %"PRIi64" (%s)", i, inputs[i]);
*input = mux_get_input(mux, i);
return 0;
}
static int
select_idle(struct mux *mux, struct value value, struct mux_input **input)
{
dbg("selecting tri output for value %s", value_str(value));
if (value.type == VALUE_INT64 && value.i == ST_PROGRESSING) {
dbg("selecting input 0 (tr)");
*input = mux_get_input(mux, 0);
} else {
dbg("selecting input 1 (idle)");
*input = mux_get_input(mux, 1);
}
return 0;
}
static int
connect_cpu(struct bay *bay, struct nosv_cpu *mcpu)
{
struct nosv_breakdown_cpu *bcpu = &mcpu->breakdown;
/* Channel aliases */
struct chan *ss = &mcpu->m.track[CH_SUBSYSTEM].ch;
struct chan *tt = &mcpu->m.track[CH_TYPE].ch;
struct chan *idle = &mcpu->m.track[CH_IDLE].ch;
struct chan *tr = &bcpu->tr;
struct chan *tri = &bcpu->tri;
/* Connect mux0 using ss as select */
if (mux_init(&bcpu->mux0, bay, ss, tr, select_tr, 2) != 0) {
err("mux_init failed");
return -1;
}
if (mux_set_input(&bcpu->mux0, 0, ss) != 0) {
err("mux_set_input ss failed");
return -1;
}
if (mux_set_input(&bcpu->mux0, 1, tt) != 0) {
err("mux_set_input tt failed");
return -1;
}
/* Emit unknown subsystem on NULL */
mux_set_default(&bcpu->mux0, value_int64(ST_UNKNOWN_SS));
/* Connect mux 1 using idle as select */
if (mux_init(&bcpu->mux1, bay, idle, tri, select_idle, 2) != 0) {
err("mux_init failed");
return -1;
}
if (mux_set_input(&bcpu->mux1, 0, tr) != 0) {
err("mux_set_input tr failed");
return -1;
}
if (mux_set_input(&bcpu->mux1, 1, idle) != 0) {
err("mux_set_input idle failed");
return -1;
}
return 0;
}
int
model_nosv_breakdown_connect(struct emu *emu)
{
if (emu->args.breakdown == 0)
return 0;
struct nosv_emu *memu = EXT(emu, 'V');
struct nosv_breakdown_emu *bemu = &memu->breakdown;
struct bay *bay = &emu->bay;
struct system *sys = &emu->system;
int64_t i = 0;
for (struct cpu *cpu = sys->cpus; cpu; cpu = cpu->next) {
if (cpu->is_virtual)
continue;
struct nosv_cpu *mcpu = EXT(cpu, 'V');
struct nosv_breakdown_cpu *bcpu = &mcpu->breakdown;
/* Connect tr and tri channels and muxes */
if (connect_cpu(bay, mcpu) != 0) {
err("connect_cpu failed");
return -1;
}
/* Connect tri to sort */
if (sort_set_input(&bemu->sort, i, &bcpu->tri) != 0) {
err("sort_set_input failed");
return -1;
}
/* Connect out to PRV */
struct prv *prv = pvt_get_prv(bemu->pvt);
long type = PRV_NOSV_BREAKDOWN;
long flags = PRV_SKIPDUP | PRV_ZERO;
struct chan *out = sort_get_output(&bemu->sort, i);
if (prv_register(prv, (long) i, type, bay, out, flags)) {
err("prv_register failed");
return -1;
}
i++;
}
return 0;
}
int
model_nosv_breakdown_finish(struct emu *emu,
const struct pcf_value_label **labels)
{
if (emu->args.breakdown == 0)
return 0;
struct nosv_emu *memu = EXT(emu, 'V');
struct nosv_breakdown_emu *bemu = &memu->breakdown;
struct pcf *pcf = pvt_get_pcf(bemu->pvt);
long typeid = PRV_NOSV_BREAKDOWN;
char label[] = "CPU: nOS-V Runtime/Idle/Task breakdown";
struct pcf_type *pcftype = pcf_add_type(pcf, (int) typeid, label);
const struct pcf_value_label *v = NULL;
/* Emit subsystem values */
for (v = labels[CH_SUBSYSTEM]; v->label; v++) {
if (pcf_add_value(pcftype, v->value, v->label) == NULL) {
err("pcf_add_value ss failed");
return -1;
}
}
/* Emit idle values */
for (v = labels[CH_IDLE]; v->label; v++) {
if (pcf_add_value(pcftype, v->value, v->label) == NULL) {
err("pcf_add_value idle failed");
return -1;
}
}
/* Emit task_type values */
struct system *sys = &emu->system;
for (struct proc *p = sys->procs; p; p = p->gnext) {
struct nosv_proc *proc = EXT(p, 'V');
struct task_info *info = &proc->task_info;
if (task_create_pcf_types(pcftype, info->types) != 0) {
err("task_create_pcf_types failed");
return -1;
}
}
/* Also populate the row labels */
struct prf *prf = pvt_get_prf(bemu->pvt);
for (int64_t row = 0; row < bemu->nphycpus; row++) {
char name[128];
if (snprintf(name, 128, "~CPU %4"PRIi64, bemu->nphycpus - row) >= 128) {
err("label too long");
return -1;
}
if (prf_add(prf, (long) row, name) != 0) {
err("prf_add failed for %s", name);
return -1;
}
}
return 0;
}

56
src/emu/nosv/breakdown.h Normal file
View File

@ -0,0 +1,56 @@
/* Copyright (c) 2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef BREAKDOWN_H
#define BREAKDOWN_H
/*
* The breakdown model is implemented on top of the CPU subsystem, task_type and
* idle channels. The first mux0 selects the task type when the subsystem
* matches "Task body" otherwise forwards the subsystem as-is to tr. The second
* mux1 selects tr only when the CPU is not Idle, otherwise sets the output tri
* as Idle.
*
* +--------+
* | |
* | v
* | +------+
* subsystem -+-->--| |
* | mux0 | +------+
* task_type ---->--| |-->-- tr -->--| |
* +------+ | mux1 |-->-- tri
* idle --------->-------------------+->--| |
* | +------+
* | ^
* | |
* +--------+
*
* Then the sort module takes the output tri of each CPU and sorts the values
* which are propagated to the PRV directly.
*
* +------+ +-----+
* cpu0.tri --->---| |--->---| |
* ... | sort | ... | PRV |
* cpuN.tri --->---| |--->---| |
* +------+ +-----+
*/
#include <stdint.h>
#include "chan.h"
#include "mux.h"
#include "sort.h"
struct nosv_breakdown_cpu {
struct mux mux0;
struct chan tr;
struct mux mux1;
struct chan tri;
};
struct nosv_breakdown_emu {
int64_t nphycpus;
struct sort sort;
struct pvt *pvt;
};
#endif /* BREAKDOWN_H */

View File

@ -16,7 +16,7 @@
#include "thread.h"
#include "value.h"
enum { PUSH = 1, POP = 2, IGN = 3 };
enum { PUSH = 1, POP = 2, SET = 3, IGN = 4 };
#define CHSS CH_SUBSYSTEM
@ -67,6 +67,12 @@ static const int ss_table[256][256][3] = {
['U'] = { CHSS, POP, ST_API_MUTEX_UNLOCK },
['b'] = { CHSS, PUSH, ST_API_BARRIER_WAIT },
['B'] = { CHSS, POP, ST_API_BARRIER_WAIT },
['o'] = { CHSS, PUSH, ST_API_COND_WAIT },
['O'] = { CHSS, POP, ST_API_COND_WAIT },
['g'] = { CHSS, PUSH, ST_API_COND_SIGNAL },
['G'] = { CHSS, POP, ST_API_COND_SIGNAL },
['k'] = { CHSS, PUSH, ST_API_COND_BCAST },
['K'] = { CHSS, POP, ST_API_COND_BCAST },
},
/* FIXME: Move thread type to another channel, like nanos6 */
['H'] = {
@ -77,6 +83,11 @@ static const int ss_table[256][256][3] = {
['d'] = { CHSS, PUSH, ST_DELEGATE },
['D'] = { CHSS, POP, ST_DELEGATE },
},
['P'] = {
['p'] = { CH_IDLE, SET, ST_PROGRESSING },
['r'] = { CH_IDLE, SET, ST_RESTING },
['a'] = { CH_IDLE, SET, ST_ABSORBING },
},
};
static int
@ -94,6 +105,8 @@ simple(struct emu *emu)
return chan_push(ch, value_int64(st));
} else if (action == POP) {
return chan_pop(ch, value_int64(st));
} else if (action == SET) {
return chan_set(ch, value_int64(st));
} else if (action == IGN) {
return 0; /* do nothing */
} else {
@ -317,7 +330,7 @@ update_task_state(struct emu *emu)
static int
expand_transition_value(struct emu *emu, int was_running, int runs_now, char *tr_p)
{
char tr = emu->ev->v;
char tr = (char) emu->ev->v;
/* Ensure we don't clobber the value */
if (tr == 'X' || tr == 'E') {
@ -434,7 +447,7 @@ update_task(struct emu *emu)
struct body *next = task_get_running(stack);
/* Update the subsystem channel */
if (update_task_ss_channel(emu, emu->ev->v) != 0) {
if (update_task_ss_channel(emu, (char) emu->ev->v) != 0) {
err("update_task_ss_channel failed");
return -1;
}
@ -502,7 +515,7 @@ pre_task(struct emu *emu)
switch (emu->ev->v) {
case 'C':
case 'c':
ret = create_task(emu, emu->ev->v);
ret = create_task(emu, (char) emu->ev->v);
break;
case 'x':
case 'e':
@ -539,7 +552,8 @@ pre_type(struct emu *emu)
}
const uint8_t *data = &emu->ev->payload->jumbo.data[0];
uint32_t typeid = *(uint32_t *) data;
uint32_t typeid;
memcpy(&typeid, data, 4); /* May be unaligned */
data += 4;
const char *label = (const char *) data;
@ -574,6 +588,7 @@ process_ev(struct emu *emu)
case 'M':
case 'H':
case 'A':
case 'P':
return simple(emu);
case 'T':
return pre_task(emu);

View File

@ -4,6 +4,7 @@
#ifndef NOSV_PRIV_H
#define NOSV_PRIV_H
#include "breakdown.h"
#include "emu.h"
#include "task.h"
#include "model_cpu.h"
@ -18,10 +19,12 @@ enum nosv_chan {
CH_APPID,
CH_SUBSYSTEM,
CH_RANK,
CH_IDLE,
CH_MAX,
};
enum nosv_ss_values {
ST_UNKNOWN_SS = 2,
ST_SCHED_HUNGRY = 6,
ST_SCHED_SERVING,
ST_SCHED_SUBMITTING,
@ -41,6 +44,9 @@ enum nosv_ss_values {
ST_API_MUTEX_TRYLOCK,
ST_API_MUTEX_UNLOCK,
ST_API_BARRIER_WAIT,
ST_API_COND_WAIT,
ST_API_COND_SIGNAL,
ST_API_COND_BCAST,
ST_WORKER,
ST_DELEGATE,
@ -56,16 +62,36 @@ struct nosv_thread {
struct nosv_cpu {
struct model_cpu m;
struct nosv_breakdown_cpu breakdown;
};
struct nosv_proc {
struct task_info task_info;
};
struct nosv_emu {
int connected;
int event;
struct nosv_breakdown_emu breakdown;
};
enum nosv_progress {
/* Can mix with subsystem values */
ST_PROGRESSING = 100,
ST_RESTING,
ST_ABSORBING,
};
int model_nosv_probe(struct emu *emu);
int model_nosv_create(struct emu *emu);
int model_nosv_connect(struct emu *emu);
int model_nosv_event(struct emu *emu);
int model_nosv_finish(struct emu *emu);
int model_nosv_breakdown_create(struct emu *emu);
int model_nosv_breakdown_connect(struct emu *emu);
int model_nosv_breakdown_finish(struct emu *emu,
const struct pcf_value_label **labels);
#endif /* NOSV_PRIV_H */

View File

@ -5,6 +5,7 @@
#include <stddef.h>
#include <stdlib.h>
#include "chan.h"
#include "cpu.h"
#include "common.h"
#include "emu.h"
#include "emu_args.h"
@ -64,6 +65,9 @@ static struct ev_decl model_evlist[] = {
PAIR_E("VAt", "VAT", "nosv_mutex_trylock()")
PAIR_E("VAu", "VAU", "nosv_mutex_unlock()")
PAIR_E("VAb", "VAB", "nosv_barrier_wait()")
PAIR_E("VAo", "VAO", "nosv_cond_wait()")
PAIR_E("VAg", "VAG", "nosv_cond_signal()")
PAIR_E("VAk", "VAK", "nosv_cond_broadcast()")
/* FIXME: VHA and VHa are not subsystems */
{ "VHa", "enters nosv_attach()" },
@ -72,12 +76,16 @@ static struct ev_decl model_evlist[] = {
PAIR_B("VHw", "VHW", "execution as worker")
PAIR_B("VHd", "VHD", "execution as delegate")
{ "VPp", "sets progress state to Progressing" },
{ "VPr", "sets progress state to Resting" },
{ "VPa", "sets progress state to Absorbing" },
{ NULL, NULL },
};
struct model_spec model_nosv = {
.name = model_name,
.version = "2.1.0",
.version = "2.4.0",
.evlist = model_evlist,
.model = model_id,
.create = model_nosv_create,
@ -96,6 +104,7 @@ static const char *chan_name[CH_MAX] = {
[CH_APPID] = "appid",
[CH_SUBSYSTEM] = "subsystem",
[CH_RANK] = "rank",
[CH_IDLE] = "idle",
};
static const int chan_stack[CH_MAX] = {
@ -121,6 +130,7 @@ static const int pvt_type[CH_MAX] = {
[CH_APPID] = PRV_NOSV_APPID,
[CH_SUBSYSTEM] = PRV_NOSV_SUBSYSTEM,
[CH_RANK] = PRV_NOSV_RANK,
[CH_IDLE] = PRV_NOSV_IDLE,
};
static const char *pcf_prefix[CH_MAX] = {
@ -130,9 +140,11 @@ static const char *pcf_prefix[CH_MAX] = {
[CH_APPID] = "nOS-V task AppID",
[CH_SUBSYSTEM] = "nOS-V subsystem",
[CH_RANK] = "nOS-V task MPI rank",
[CH_IDLE] = "nOS-V idle state",
};
static const struct pcf_value_label nosv_ss_values[] = {
{ ST_UNKNOWN_SS, "Unknown subsystem" },
{ ST_SCHED_HUNGRY, "Scheduler: Hungry" },
{ ST_SCHED_SERVING, "Scheduler: Serving" },
{ ST_SCHED_SUBMITTING, "Scheduler: Submitting" },
@ -152,6 +164,9 @@ static const struct pcf_value_label nosv_ss_values[] = {
{ ST_API_MUTEX_TRYLOCK,"API: Mutex trylock" },
{ ST_API_MUTEX_UNLOCK, "API: Mutex unlock" },
{ ST_API_BARRIER_WAIT, "API: Barrier wait" },
{ ST_API_COND_WAIT, "API: Cond wait" },
{ ST_API_COND_SIGNAL, "API: Cond signal" },
{ ST_API_COND_BCAST, "API: Cond broadcast" },
{ ST_WORKER, "Thread: Worker" },
{ ST_DELEGATE, "Thread: Delegate" },
{ EV_SCHED_SEND, "EV Scheduler: Send task" },
@ -160,8 +175,16 @@ static const struct pcf_value_label nosv_ss_values[] = {
{ -1, NULL },
};
static const struct pcf_value_label nosv_worker_idle[] = {
{ ST_PROGRESSING, "Progressing" },
{ ST_RESTING, "Resting" },
{ ST_ABSORBING, "Absorbing noise" },
{ -1, NULL },
};
static const struct pcf_value_label *pcf_labels[CH_MAX] = {
[CH_SUBSYSTEM] = nosv_ss_values,
[CH_IDLE] = nosv_worker_idle,
};
static const long prv_flags[CH_MAX] = {
@ -171,6 +194,7 @@ static const long prv_flags[CH_MAX] = {
[CH_APPID] = PRV_SKIPDUPNULL, /* Switch to task of same appid */
[CH_SUBSYSTEM] = PRV_SKIPDUPNULL,
[CH_RANK] = PRV_SKIPDUPNULL, /* Switch to task of same rank */
[CH_IDLE] = PRV_SKIPDUPNULL,
};
static const struct model_pvt_spec pvt_spec = {
@ -189,6 +213,7 @@ static const int th_track[CH_MAX] = {
[CH_APPID] = TRACK_TH_RUN,
[CH_SUBSYSTEM] = TRACK_TH_ACT,
[CH_RANK] = TRACK_TH_RUN,
[CH_IDLE] = TRACK_TH_RUN,
};
static const int cpu_track[CH_MAX] = {
@ -198,6 +223,7 @@ static const int cpu_track[CH_MAX] = {
[CH_APPID] = TRACK_TH_RUN,
[CH_SUBSYSTEM] = TRACK_TH_RUN,
[CH_RANK] = TRACK_TH_RUN,
[CH_IDLE] = TRACK_TH_RUN,
};
/* ----------------- chan_spec ------------------ */
@ -279,6 +305,19 @@ model_nosv_create(struct emu *emu)
}
}
struct nosv_emu *e = calloc(1, sizeof(struct nosv_emu));
if (e == NULL) {
err("calloc failed:");
return -1;
}
extend_set(&emu->ext, model_id, e);
if (model_nosv_breakdown_create(emu) != 0) {
err("model_nosv_breakdown_create failed");
return -1;
}
return 0;
}
@ -295,6 +334,28 @@ model_nosv_connect(struct emu *emu)
return -1;
}
if (emu->args.breakdown && model_nosv_breakdown_connect(emu) != 0) {
err("model_nosv_breakdown_connect failed");
return -1;
}
for (struct thread *th = emu->system.threads; th; th = th->gnext) {
struct nosv_thread *mth = EXT(th, model_id);
struct chan *idle = &mth->m.ch[CH_IDLE];
/* By default set all threads as Progressing */
if (chan_set(idle, value_int64(ST_PROGRESSING)) != 0) {
err("chan_push idle failed");
return -1;
}
}
for (struct cpu *cpu = emu->system.cpus; cpu; cpu = cpu->next) {
struct nosv_cpu *mcpu = EXT(cpu, model_id);
struct mux *mux = &mcpu->m.track[CH_IDLE].mux;
/* Emit Resting when a CPU has no running threads */
mux_set_default(mux, value_int64(ST_RESTING));
}
return 0;
}
@ -341,8 +402,12 @@ finish_pvt(struct emu *emu, const char *name)
return -1;
}
struct pcf *pcf = pvt_get_pcf(pvt);
long typeid = pvt_type[CH_TYPE];
int typeid = pvt_type[CH_TYPE];
struct pcf_type *pcftype = pcf_find_type(pcf, typeid);
if (pcftype == NULL) {
err("cannot find %s pcf type %d", name, typeid);
return -1;
}
for (struct proc *p = sys->procs; p; p = p->gnext) {
struct nosv_proc *proc = EXT(p, model_id);
@ -370,6 +435,11 @@ model_nosv_finish(struct emu *emu)
return -1;
}
if (model_nosv_breakdown_finish(emu, pcf_labels) != 0) {
err("model_nosv_breakdown_finish failed");
return -1;
}
/* When running in linter mode perform additional checks */
if (emu->args.linter_mode && end_lint(emu) != 0) {
err("end_lint failed");

View File

@ -8,6 +8,9 @@
#include "emu_ev.h"
#include "extend.h"
#include "model_thread.h"
#include "ovni.h"
#include "proc.h"
#include "task.h"
#include "thread.h"
#include "value.h"
@ -95,7 +98,7 @@ static const int fn_table[256][256][3] = {
};
static int
process_ev(struct emu *emu)
simple(struct emu *emu)
{
if (!emu->thread->is_running) {
err("current thread %d not running", emu->thread->tid);
@ -122,6 +125,263 @@ process_ev(struct emu *emu)
return -1;
}
static int
create_task(struct emu *emu)
{
if (emu->ev->payload_size != 8) {
err("unexpected payload size");
return -1;
}
uint32_t taskid = emu->ev->payload->u32[0];
uint32_t typeid = emu->ev->payload->u32[1];
if (taskid == 0) {
err("taskid cannot be 0");
return -1;
}
if (typeid == 0) {
err("typeid cannot be 0");
return -1;
}
struct openmp_proc *proc = EXT(emu->proc, 'P');
struct task_info *info = &proc->task_info;
/* OpenMP submits inline tasks without pausing the previous
* task, so we relax the model to allow this for now. */
uint32_t flags = TASK_FLAG_RELAX_NESTING;
if (task_create(info, typeid, taskid, flags) != 0) {
err("task_create failed");
return -1;
}
dbg("task created with taskid %u", taskid);
return 0;
}
static int
update_task(struct emu *emu)
{
if (emu->ev->payload_size < 4) {
err("missing task id in payload");
return -1;
}
uint32_t taskid = emu->ev->payload->u32[0];
if (taskid == 0) {
err("taskid cannot be 0");
return -1;
}
struct openmp_thread *th = EXT(emu->thread, 'P');
struct openmp_proc *proc = EXT(emu->proc, 'P');
struct task_info *info = &proc->task_info;
struct task_stack *stack = &th->task_stack;
struct task *task = task_find(info->tasks, taskid);
if (task == NULL) {
err("cannot find task with id %u", taskid);
return -1;
}
/* OpenMP doesn't have parallel tasks */
uint32_t body_id = 1;
if (emu->ev->v == 'x') {
if (task_execute(stack, task, body_id) != 0) {
err("cannot change task state to running");
return -1;
}
if (chan_push(&th->m.ch[CH_TASKID], value_int64(task->id)) != 0) {
err("chan_push taskid failed");
return -1;
}
if (chan_push(&th->m.ch[CH_LABEL], value_int64(task->type->gid)) != 0) {
err("chan_push task label failed");
return -1;
}
} else if (emu->ev->v == 'e') {
if (task_end(stack, task, body_id) != 0) {
err("cannot change task state to end");
return -1;
}
if (chan_pop(&th->m.ch[CH_TASKID], value_int64(task->id)) != 0) {
err("chan_pop taskid failed");
return -1;
}
if (chan_pop(&th->m.ch[CH_LABEL], value_int64(task->type->gid)) != 0) {
err("chan_pop task label failed");
return -1;
}
} else {
err("unexpected task event %c", emu->ev->v);
return -1;
}
return 0;
}
static int
pre_task(struct emu *emu)
{
int ret = 0;
switch (emu->ev->v) {
case 'c':
ret = create_task(emu);
break;
case 'x':
case 'e':
ret = update_task(emu);
break;
default:
err("unexpected task event value");
return -1;
}
if (ret != 0) {
err("cannot update task state");
return -1;
}
return 0;
}
static int
pre_type(struct emu *emu)
{
uint8_t value = emu->ev->v;
if (value != 'c') {
err("unexpected event value %c", value);
return -1;
}
if (!emu->ev->is_jumbo) {
err("expecting a jumbo event");
return -1;
}
const uint8_t *data = &emu->ev->payload->jumbo.data[0];
uint32_t typeid;
memcpy(&typeid, data, 4); /* May be unaligned */
data += 4;
const char *label = (const char *) data;
struct openmp_proc *proc = EXT(emu->proc, 'P');
struct task_info *info = &proc->task_info;
/* It will be used for tasks and worksharings. */
if (task_type_create(info, typeid, label) != 0) {
err("task_type_create failed");
return -1;
}
return 0;
}
static int
update_ws_state(struct emu *emu, uint8_t action)
{
if (emu->ev->payload_size < 4) {
err("missing worksharing id in payload");
return -1;
}
uint32_t typeid = emu->ev->payload->u32[0];
if (typeid == 0) {
err("worksharing type id cannot be 0");
return -1;
}
struct openmp_thread *th = EXT(emu->thread, 'P');
struct openmp_proc *proc = EXT(emu->proc, 'P');
struct task_info *info = &proc->task_info;
/* Worksharings share the task type */
struct task_type *ttype = task_type_find(info->types, typeid);
if (ttype == NULL) {
err("cannot find ws with type %"PRIu32, typeid);
return -1;
}
if (action == 'x') {
if (chan_push(&th->m.ch[CH_LABEL], value_int64(ttype->gid)) != 0) {
err("chan_push worksharing label failed");
return -1;
}
} else {
if (chan_pop(&th->m.ch[CH_LABEL], value_int64(ttype->gid)) != 0) {
err("chan_pop worksharing label failed");
return -1;
}
}
return 0;
}
static int
pre_worksharing(struct emu *emu)
{
int ret = 0;
switch (emu->ev->v) {
case 'x':
case 'e':
ret = update_ws_state(emu, emu->ev->v);
break;
default:
err("unexpected ws event value %c", emu->ev->v);
return -1;
}
if (ret != 0) {
err("cannot update worksharing channels");
return -1;
}
return 0;
}
static int
process_ev(struct emu *emu)
{
if (!emu->thread->is_running) {
err("current thread %d not running", emu->thread->tid);
return -1;
}
switch (emu->ev->c) {
case 'B':
case 'I':
case 'W':
case 'T':
case 'A':
case 'M':
case 'H':
case 'C':
return simple(emu);
case 'P':
return pre_task(emu);
case 'O':
return pre_type(emu);
case 'Q':
return pre_worksharing(emu);
}
err("unknown event category");
return -1;
}
int
model_openmp_event(struct emu *emu)
{

View File

@ -5,6 +5,7 @@
#define OPENMP_PRIV_H
#include "emu.h"
#include "task.h"
#include "model_cpu.h"
#include "model_thread.h"
@ -12,6 +13,8 @@
enum openmp_chan {
CH_SUBSYSTEM = 0,
CH_LABEL,
CH_TASKID,
CH_MAX,
};
@ -55,12 +58,18 @@ enum openmp_function_values {
struct openmp_thread {
struct model_thread m;
struct task_stack task_stack;
};
struct openmp_cpu {
struct model_cpu m;
};
struct openmp_proc {
/* Shared among tasks and ws */
struct task_info task_info;
};
int model_openmp_probe(struct emu *emu);
int model_openmp_create(struct emu *emu);
int model_openmp_connect(struct emu *emu);

View File

@ -15,8 +15,10 @@
#include "model_cpu.h"
#include "model_pvt.h"
#include "model_thread.h"
#include "proc.h"
#include "pv/pcf.h"
#include "pv/prv.h"
#include "pv/pvt.h"
#include "system.h"
#include "thread.h"
#include "track.h"
@ -65,12 +67,22 @@ static struct ev_decl model_evlist[] = {
PAIR_B("PCf", "PCF", "fork call")
PAIR_B("PCi", "PCI", "initialization")
/* Task or worksharing type */
{ "POc+(u32 typeid, str label)", "creates a type %{typeid} with label \"%{label}\"" },
{ "PPc(u32 taskid, u32 typeid)", "creates the task %{taskid} with type %{typeid}" },
{ "PPx(u32 taskid)", "executes the task %{taskid}" },
{ "PPe(u32 taskid)", "ends the task %{taskid}" },
{ "PQx(u32 typeid)", "begins worksharing with type %{typeid}" },
{ "PQe(u32 typeid)", "ends worksharing with type %{typeid}" },
{ NULL, NULL },
};
struct model_spec model_openmp = {
.name = model_name,
.version = "1.1.0",
.version = "1.2.0",
.evlist = model_evlist,
.model = model_id,
.create = model_openmp_create,
@ -84,24 +96,34 @@ struct model_spec model_openmp = {
static const char *chan_name[CH_MAX] = {
[CH_SUBSYSTEM] = "subsystem",
[CH_LABEL] = "label",
[CH_TASKID] = "task ID",
};
static const int chan_stack[CH_MAX] = {
[CH_SUBSYSTEM] = 1,
[CH_LABEL] = 1,
[CH_TASKID] = 1,
};
static const int chan_dup[CH_MAX] = {
[CH_SUBSYSTEM] = 1,
[CH_LABEL] = 1, /* Two tasks nested with same type */
[CH_TASKID] = 1,
};
/* ----------------- pvt ------------------ */
static const int pvt_type[CH_MAX] = {
[CH_SUBSYSTEM] = PRV_OPENMP_SUBSYSTEM,
[CH_LABEL] = PRV_OPENMP_LABEL,
[CH_TASKID] = PRV_OPENMP_TASKID,
};
static const char *pcf_prefix[CH_MAX] = {
[CH_SUBSYSTEM] = "OpenMP subsystem",
[CH_LABEL] = "OpenMP label",
[CH_TASKID] = "OpenMP task ID",
};
static const struct pcf_value_label openmp_subsystem_values[] = {
@ -149,7 +171,9 @@ static const struct pcf_value_label *pcf_labels[CH_MAX] = {
};
static const long prv_flags[CH_MAX] = {
[CH_SUBSYSTEM] = PRV_EMITDUP,
[CH_SUBSYSTEM] = PRV_SKIPDUPNULL,
[CH_LABEL] = PRV_SKIPDUPNULL,
[CH_TASKID] = PRV_SKIPDUPNULL,
};
static const struct model_pvt_spec pvt_spec = {
@ -163,10 +187,14 @@ static const struct model_pvt_spec pvt_spec = {
static const int th_track[CH_MAX] = {
[CH_SUBSYSTEM] = TRACK_TH_ACT,
[CH_LABEL] = TRACK_TH_ACT,
[CH_TASKID] = TRACK_TH_ACT,
};
static const int cpu_track[CH_MAX] = {
[CH_SUBSYSTEM] = TRACK_TH_RUN,
[CH_LABEL] = TRACK_TH_RUN,
[CH_TASKID] = TRACK_TH_RUN,
};
/* ----------------- chan_spec ------------------ */
@ -213,9 +241,24 @@ model_openmp_probe(struct emu *emu)
return model_version_probe(&model_openmp, emu);
}
static int
init_proc(struct proc *sysproc)
{
struct openmp_proc *proc = calloc(1, sizeof(struct openmp_proc));
if (proc == NULL) {
err("calloc failed:");
return -1;
}
extend_set(&sysproc->ext, model_id, proc);
return 0;
}
int
model_openmp_create(struct emu *emu)
{
if (model_thread_create(emu, &th_spec) != 0) {
err("model_thread_init failed");
return -1;
@ -226,6 +269,15 @@ model_openmp_create(struct emu *emu)
return -1;
}
struct system *sys = &emu->system;
for (struct proc *p = sys->procs; p; p = p->gnext) {
if (init_proc(p) != 0) {
err("init_proc failed");
return -1;
}
}
return 0;
}
@ -245,6 +297,44 @@ model_openmp_connect(struct emu *emu)
return 0;
}
static int
create_pcf_type(struct system *sys, struct pcf *pcf, long typeid)
{
struct pcf_type *pcftype = pcf_find_type(pcf, (int) typeid);
for (struct proc *p = sys->procs; p; p = p->gnext) {
struct openmp_proc *proc = EXT(p, model_id);
struct task_info *info = &proc->task_info;
if (task_create_pcf_types(pcftype, info->types) != 0) {
err("task_create_pcf_types failed");
return -1;
}
}
return 0;
}
static int
finish_pvt(struct emu *emu, const char *name)
{
struct system *sys = &emu->system;
/* Emit task types for all channel types and processes */
struct pvt *pvt = recorder_find_pvt(&emu->recorder, name);
if (pvt == NULL) {
err("cannot find pvt with name '%s'", name);
return -1;
}
struct pcf *pcf = pvt_get_pcf(pvt);
if (create_pcf_type(sys, pcf, pvt_type[CH_LABEL]) != 0) {
err("create_pcf_type failed");
return -1;
}
return 0;
}
static int
end_lint(struct emu *emu)
{
@ -278,6 +368,17 @@ end_lint(struct emu *emu)
int
model_openmp_finish(struct emu *emu)
{
/* Fill task types */
if (finish_pvt(emu, "thread") != 0) {
err("finish_pvt thread failed");
return -1;
}
if (finish_pvt(emu, "cpu") != 0) {
err("finish_pvt cpu failed");
return -1;
}
/* When running in linter mode perform additional checks */
if (emu->args.linter_mode && end_lint(emu) != 0) {
err("end_lint failed");

View File

@ -16,6 +16,7 @@
#include "proc.h"
#include "thread.h"
#include "value.h"
#include "mark.h"
static int
pre_thread_execute(struct emu *emu, struct thread *th)
@ -228,7 +229,7 @@ pre_affinity_set(struct emu *emu)
}
if (emu->ev->payload_size != 4) {
err("unexpected payload size %d", emu->ev->payload_size);
err("unexpected payload size %zd", emu->ev->payload_size);
return -1;
}
@ -264,7 +265,7 @@ static int
pre_affinity_remote(struct emu *emu)
{
if (emu->ev->payload_size != 8) {
err("unexpected payload size %d", emu->ev->payload_size);
err("unexpected payload size %zd", emu->ev->payload_size);
return -1;
}
@ -389,18 +390,18 @@ pre_burst(struct emu *emu)
for (int i = 0; i < n; i++)
deltas[i] = th->burst_time[i + 1] - th->burst_time[i];
qsort(deltas, n, sizeof(int64_t), compare_int64);
qsort(deltas, (size_t) n, sizeof(int64_t), compare_int64);
double avg = 0.0;
double maxdelta = 0;
for (int i = 0; i < n; i++) {
if (deltas[i] > maxdelta)
maxdelta = deltas[i];
avg += deltas[i];
if ((double) deltas[i] > maxdelta)
maxdelta = (double) deltas[i];
avg += (double) deltas[i];
}
avg /= (double) n;
double median = deltas[n / 2];
double median = (double) deltas[n / 2];
info("%s burst stats: median/avg/max = %3.0f/%3.0f/%3.0f ns",
emu->loom->id, median, avg, maxdelta);
@ -436,7 +437,7 @@ pre_flush(struct emu *emu)
double flush_ms = (double) flush_ns * 1e-6;
/* Avoid last flush warnings */
if (flush_ms > 10.0 && emu->thread->is_running)
warn("large flush of %.1f ms at dclock=%ld ns in tid=%d",
warn("large flush of %.1f ms at dclock=%"PRIi64" ns in tid=%d",
flush_ms,
emu->ev->dclock,
emu->thread->tid);
@ -477,6 +478,8 @@ model_ovni_event(struct emu *emu)
case 'U':
/* Ignore sorting events */
return 0;
case 'M':
return mark_event(emu);
default:
err("unknown ovni event category %c",
emu->ev->c);

668
src/emu/ovni/mark.c Normal file
View File

@ -0,0 +1,668 @@
#include "mark.h"
#include "chan.h"
#include "cpu.h"
#include "emu.h"
#include "emu_ev.h"
#include "emu_prv.h"
#include "inttypes.h"
#include "ovni.h"
#include "ovni_priv.h"
#include "parson.h"
#include "pv/pcf.h"
#include "pv/prv.h"
#include "pv/pvt.h"
#include "thread.h"
#include "track.h"
#include "uthash.h"
#include <errno.h>
struct mark_label {
int64_t value;
char label[MAX_PCF_LABEL];
UT_hash_handle hh; /* Indexed by value */
};
struct mark_type {
long type;
long prvtype;
long index; /* From 0 to ntypes - 1 */
enum chan_type ctype;
struct mark_label *labels; /* Hash table of labels */
char title[MAX_PCF_LABEL];
UT_hash_handle hh; /* Indexed by type */
};
static int
parse_number(const char *str, int64_t *result)
{
errno = 0;
char *endptr = NULL;
int64_t n = strtoll(str, &endptr, 10);
if (errno != 0 || endptr == str || endptr[0] != '\0') {
err("failed to parse number: %s", str);
return -1;
}
*result = n;
return 0;
}
static struct mark_label *
find_label(struct mark_type *t, int64_t value)
{
struct mark_label *l;
HASH_FIND(hh, t->labels, &value, sizeof(value), l);
return l;
}
static int
add_label(struct mark_type *t, int64_t value, const char *label)
{
struct mark_label *l = find_label(t, value);
if (l != NULL) {
if (strcmp(l->label, label) == 0) {
/* Already exists with the same label, all good */
return 0;
} else {
err("mark value %" PRIi64 " already defined with label %s", value, l->label);
return -1;
}
}
l = calloc(1, sizeof(*l));
if (l == NULL) {
err("calloc failed:");
return -1;
}
l->value = value;
int len = snprintf(l->label, MAX_PCF_LABEL, "%s", label);
if (len >= MAX_PCF_LABEL) {
err("mark label too long: %s", label);
return -1;
}
HASH_ADD(hh, t->labels, value, sizeof(value), l);
return 0;
}
static int
parse_labels(struct mark_type *t, JSON_Object *labels)
{
/* It may happen that we call this function several times with
* overlapping subsets of values. The only restriction is that we don't
* define two values with different label. */
size_t n = json_object_get_count(labels);
for (size_t i = 0; i < n; i++) {
const char *valuestr = json_object_get_name(labels, i);
if (valuestr == NULL) {
err("json_object_get_name failed");
return -1;
}
int64_t value;
if (parse_number(valuestr, &value) != 0) {
err("parse_number failed");
return -1;
}
JSON_Value *labelval = json_object_get_value_at(labels, i);
if (labelval == NULL) {
err("json_object_get_value_at failed");
return -1;
}
const char *label = json_value_get_string(labelval);
if (label == NULL) {
err("json_value_get_string() for label failed");
return -1;
}
if (add_label(t, value, label) != 0) {
err("add_label() failed");
return -1;
}
}
return 0;
}
static struct mark_type *
find_mark_type(struct ovni_mark_emu *m, long type)
{
struct mark_type *t;
HASH_FIND_LONG(m->types, &type, t);
return t;
}
static struct mark_type *
create_mark_type(struct ovni_mark_emu *m, long type, enum chan_type ctype, const char *title)
{
struct mark_type *t = find_mark_type(m, type);
if (t != NULL) {
err("mark type %ld already defined", type);
return NULL;
}
t = calloc(1, sizeof(*t));
if (t == NULL) {
err("calloc failed:");
return NULL;
}
t->type = type;
t->ctype = ctype;
t->prvtype = type + PRV_OVNI_MARK;
t->index = m->ntypes;
int len = snprintf(t->title, MAX_PCF_LABEL, "%s", title);
if (len >= MAX_PCF_LABEL) {
err("mark title too long: %s", title);
return NULL;
}
HASH_ADD_LONG(m->types, type, t);
m->ntypes++;
return t;
}
static int
parse_mark(struct ovni_mark_emu *m, const char *typestr, JSON_Value *markval)
{
errno = 0;
char *endptr = NULL;
long type = strtol(typestr, &endptr, 10);
if (errno != 0 || endptr == typestr || endptr[0] != '\0') {
err("failed to parse type number: %s", typestr);
return -1;
}
if (type < 0 || type >= 100) {
err("mark type should be in [0, 100) range: %ld", type);
return -1;
}
JSON_Object *mark = json_value_get_object(markval);
if (mark == NULL) {
err("json_value_get_object() failed");
return -1;
}
const char *title = json_object_get_string(mark, "title");
if (title == NULL) {
err("json_object_get_string() for title failed");
return -1;
}
const char *chan_type = json_object_get_string(mark, "chan_type");
if (chan_type == NULL) {
err("json_object_get_string() for chan_type failed");
return -1;
}
enum chan_type ctype;
if (strcmp(chan_type, "single") == 0) {
ctype = CHAN_SINGLE;
} else if (strcmp(chan_type, "stack") == 0) {
ctype = CHAN_STACK;
} else {
err("chan_type %s not understood", chan_type);
return -1;
}
struct mark_type *t = find_mark_type(m, type);
if (t == NULL) {
t = create_mark_type(m, type, ctype, title);
if (t == NULL) {
err("cannot create mark type");
return -1;
}
} else {
/* It may already exist as defined by other threads, so ensure
* they have the same title. */
if (strcmp(t->title, title) != 0) {
err("mark with type %ld already registered with another title", type);
err(" old: %s", t->title);
err(" new: %s", title);
return -1;
}
/* And also the same channel type */
if (t->ctype != ctype) {
err("mark with type %ld already registered with another channel type", type);
err(" old: %s", t->ctype == CHAN_SINGLE ? "single" : "stack");
err(" new: %s", ctype == CHAN_SINGLE ? "single" : "stack");
return -1;
}
}
/* The labels are optional */
if (json_object_has_value(mark, "labels")) {
JSON_Object *labels = json_object_get_object(mark, "labels");
if (labels == NULL) {
err("json_object_get_object() for labels failed");
return -1;
}
/* Now populate the mark type with all value labels */
if (parse_labels(t, labels) != 0) {
err("cannot parse labels");
return -1;
}
}
return 0;
}
static int
scan_thread(struct ovni_mark_emu *memu, struct thread *t)
{
JSON_Object *obj = json_object_dotget_object(t->meta, "ovni.mark");
/* No marks in this thread */
if (obj == NULL)
return 0;
size_t n = json_object_get_count(obj);
for (size_t i = 0; i < n; i++) {
const char *typestr = json_object_get_name(obj, i);
if (typestr == NULL) {
err("json_object_get_name failed");
return -1;
}
JSON_Value *markval = json_object_get_value_at(obj, i);
if (markval == NULL) {
err("json_object_get_value_at failed");
return -1;
}
if (parse_mark(memu, typestr, markval) != 0) {
err("cannot parse mark");
return -1;
}
}
return 0;
}
static int
create_thread_chan(struct ovni_mark_emu *m, struct bay *bay, struct thread *th)
{
struct ovni_thread *oth = EXT(th, 'O');
struct ovni_mark_thread *t = &oth->mark;
/* Create as many channels as required */
t->channels = calloc((size_t) m->ntypes, sizeof(struct chan));
if (t->channels == NULL) {
err("calloc failed:");
return -1;
}
t->nchannels = m->ntypes;
struct mark_type *type;
for (type = m->types; type; type = type->hh.next) {
/* TODO: We may use a vector of thread channels in every type to
* avoid the double hash access in events */
long i = type->index;
struct chan *ch = &t->channels[i];
chan_init(ch, type->ctype, "thread%"PRIi64".mark%ld",
th->gindex, type->type);
/* Allow duplicates */
chan_prop_set(ch, CHAN_ALLOW_DUP, 1);
if (bay_register(bay, ch) != 0) {
err("bay_register failed");
return -1;
}
}
/* Setup tracking */
t->track = calloc((size_t) m->ntypes, sizeof(struct track));
if (t->track == NULL) {
err("calloc failed:");
return -1;
}
for (type = m->types; type; type = type->hh.next) {
long i = type->index;
struct track *track = &t->track[i];
/* For now only tracking to active thread is supported */
if (track_init(track, bay, TRACK_TYPE_TH, TRACK_TH_ACT,
"thread%"PRIi64".mark%ld",
th->gindex, type->type) != 0) {
err("track_init failed");
return -1;
}
}
return 0;
}
static int
init_cpu(struct ovni_mark_emu *m, struct bay *bay, struct cpu *cpu)
{
struct ovni_cpu *ocpu = EXT(cpu, 'O');
struct ovni_mark_cpu *c = &ocpu->mark;
/* Setup tracking */
c->track = calloc((size_t) m->ntypes, sizeof(struct track));
if (c->track == NULL) {
err("calloc failed:");
return -1;
}
struct mark_type *type;
for (type = m->types; type; type = type->hh.next) {
long i = type->index;
struct track *track = &c->track[i];
/* For now only tracking to running thread is supported */
if (track_init(track, bay, TRACK_TYPE_TH, TRACK_TH_RUN,
"cpu%"PRIi64".mark%ld",
cpu->gindex, type->type) != 0) {
err("track_init failed");
return -1;
}
}
return 0;
}
/* Scans streams for marks and creates the mark channels */
int
mark_create(struct emu *emu)
{
struct ovni_emu *oemu = EXT(emu, 'O');
struct ovni_mark_emu *memu = &oemu->mark;
memset(memu, 0, sizeof(*memu));
for (struct thread *th = emu->system.threads; th; th = th->gnext) {
if (scan_thread(memu, th) != 0) {
err("scan_thread failed");
return -1;
}
}
if (memu->ntypes == 0)
return 0;
for (struct thread *th = emu->system.threads; th; th = th->gnext) {
if (create_thread_chan(memu, &emu->bay, th) != 0) {
err("create_thread_chan failed");
return -1;
}
}
for (struct cpu *cpu = emu->system.cpus; cpu; cpu = cpu->next) {
if (init_cpu(memu, &emu->bay, cpu) != 0) {
err("init_cpu failed");
return -1;
}
}
return 0;
}
static int
connect_thread_prv(struct emu *emu, struct thread *sth, struct prv *prv)
{
struct ovni_emu *oemu = EXT(emu, 'O');
struct ovni_mark_emu *memu = &oemu->mark;
struct ovni_thread *oth = EXT(sth, 'O');
struct ovni_mark_thread *mth = &oth->mark;
for (struct mark_type *type = memu->types; type; type = type->hh.next) {
/* TODO: We may use a vector of thread channels in every type to
* avoid the double hash access in events */
long i = type->index;
struct chan *ch = &mth->channels[i];
struct track *track = &mth->track[i];
struct chan *sel = &sth->chan[TH_CHAN_STATE];
/* Connect the input and sel channel to the mux */
if (track_connect_thread(track, ch, sel, 1) != 0) {
err("track_connect_thread failed");
return -1;
}
/* Then connect the output of the tracking module to the prv
* trace for the current thread */
struct chan *out = track_get_output(track);
long row = (long) sth->gindex;
long flags = PRV_SKIPDUPNULL;
long prvtype = type->prvtype;
if (prv_register(prv, row, prvtype, &emu->bay, out, flags)) {
err("prv_register failed");
return -1;
}
}
return 0;
}
static int
create_type(struct pcf *pcf, struct mark_type *type)
{
struct pcf_type *pcftype = pcf_add_type(pcf, (int) type->prvtype, type->title);
if (pcftype == NULL) {
err("pcf_add_type failed");
return -1;
}
for (struct mark_label *l = type->labels; l; l = l->hh.next) {
if (pcf_add_value(pcftype, (int) l->value, l->label) == NULL) {
err("pcf_add_value failed");
return -1;
}
}
return 0;
}
static int
init_pcf(struct emu *emu, struct pcf *pcf)
{
struct ovni_emu *oemu = EXT(emu, 'O');
struct ovni_mark_emu *m = &oemu->mark;
for (struct mark_type *type = m->types; type; type = type->hh.next) {
if (create_type(pcf, type) != 0) {
err("create_type failed");
return -1;
}
}
return 0;
}
static int
connect_thread(struct emu *emu)
{
/* Get cpu PRV */
struct pvt *pvt = recorder_find_pvt(&emu->recorder, "thread");
if (pvt == NULL) {
err("cannot find thread pvt");
return -1;
}
/* Connect thread channels to PRV */
struct prv *prv = pvt_get_prv(pvt);
for (struct thread *t = emu->system.threads; t; t = t->gnext) {
if (connect_thread_prv(emu, t, prv) != 0) {
err("connect_thread_prv failed");
return -1;
}
}
/* Init thread PCF */
struct pcf *pcf = pvt_get_pcf(pvt);
if (init_pcf(emu, pcf) != 0) {
err("init_pcf failed");
return -1;
}
return 0;
}
static int
connect_cpu_prv(struct emu *emu, struct cpu *scpu, struct prv *prv)
{
struct ovni_emu *oemu = EXT(emu, 'O');
struct ovni_mark_emu *memu = &oemu->mark;
struct ovni_cpu *ocpu = EXT(scpu, 'O');
struct ovni_mark_cpu *mcpu = &ocpu->mark;
for (struct mark_type *type = memu->types; type; type = type->hh.next) {
/* NOTE: We may use a vector of thread channels in every type to
* avoid the double hash access in events */
long i = type->index;
struct track *track = &mcpu->track[i];
struct chan *sel = cpu_get_th_chan(scpu);
int64_t nthreads = (int64_t) emu->system.nthreads;
if (track_set_select(track, sel, NULL, nthreads) != 0) {
err("track_select failed");
return -1;
}
/* Add each thread as input */
for (struct thread *t = emu->system.threads; t; t = t->gnext) {
struct ovni_thread *oth = EXT(t, 'O');
struct ovni_mark_thread *mth = &oth->mark;
/* Use the input thread directly */
struct chan *inp = &mth->channels[i];
if (track_set_input(track, t->gindex, inp) != 0) {
err("track_add_input failed");
return -1;
}
}
/* Then connect the output of the tracking module to the prv
* trace for the current thread */
struct chan *out = track_get_output(track);
long row = (long) scpu->gindex;
long flags = PRV_SKIPDUPNULL;
long prvtype = type->prvtype;
if (prv_register(prv, row, prvtype, &emu->bay, out, flags)) {
err("prv_register failed");
return -1;
}
}
return 0;
}
static int
connect_cpu(struct emu *emu)
{
/* Get cpu PRV */
struct pvt *pvt = recorder_find_pvt(&emu->recorder, "cpu");
if (pvt == NULL) {
err("cannot find thread pvt");
return -1;
}
/* Connect cpu channels to PRV */
struct prv *prv = pvt_get_prv(pvt);
for (struct cpu *cpu = emu->system.cpus; cpu; cpu = cpu->next) {
if (connect_cpu_prv(emu, cpu, prv) != 0) {
err("connect_cpu_prv failed");
return -1;
}
}
/* Init thread PCF */
struct pcf *pcf = pvt_get_pcf(pvt);
if (init_pcf(emu, pcf) != 0) {
err("init_pcf failed");
return -1;
}
return 0;
}
/* Connect the channels to the output PVTs */
int
mark_connect(struct emu *emu)
{
struct ovni_emu *oemu = EXT(emu, 'O');
struct ovni_mark_emu *memu = &oemu->mark;
if (memu->ntypes == 0)
return 0;
if (connect_thread(emu) != 0) {
err("connect_thread() failed");
return -1;
}
if (connect_cpu(emu) != 0) {
err("connect_cpu() failed");
return -1;
}
return 0;
}
int
mark_event(struct emu *emu)
{
if (emu->ev->payload_size != 8 + 4) {
err("unexpected payload size %zd", emu->ev->payload_size);
return -1;
}
struct ovni_emu *oemu = EXT(emu, 'O');
struct ovni_mark_emu *memu = &oemu->mark;
int64_t value = emu->ev->payload->i64[0];
long type = (long) emu->ev->payload->i32[2]; /* always fits */
struct mark_type *mc = find_mark_type(memu, type);
if (mc == NULL) {
err("cannot find mark with type %ld", type);
return -1;
}
if (value == 0) {
err("mark value cannot be zero, type %ld", type);
return -1;
}
long index = mc->index;
struct ovni_thread *oth = EXT(emu->thread, 'O');
struct ovni_mark_thread *mth = &oth->mark;
struct chan *ch = &mth->channels[index];
switch (emu->ev->v) {
case '[':
return chan_push(ch, value_int64(value));
case ']':
return chan_pop(ch, value_int64(value));
case '=':
return chan_set(ch, value_int64(value));
default:
err("unknown mark event value %c", emu->ev->v);
return -1;
}
}

30
src/emu/ovni/mark.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef MARK_H
#define MARK_H
#include "common.h"
#include "chan.h"
struct emu;
struct mark_chan;
struct ovni_mark_emu {
/* Hash table of types of marks */
struct mark_type *types;
long ntypes;
};
struct ovni_mark_thread {
struct track *track;
struct chan *channels;
long nchannels;
};
struct ovni_mark_cpu {
struct track *track;
};
USE_RET int mark_create(struct emu *emu);
USE_RET int mark_connect(struct emu *emu);
USE_RET int mark_event(struct emu *emu);
#endif /* MARK_H */

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef OVNI_PRIV_H
@ -10,6 +10,7 @@
* execution by the kernel. */
#include "emu.h"
#include "mark.h"
#include "model_cpu.h"
#include "model_thread.h"
#include <stdint.h>
@ -33,10 +34,17 @@ struct ovni_thread {
int64_t burst_time[MAX_BURSTS];
int64_t flush_start;
struct ovni_mark_thread mark;
};
struct ovni_cpu {
struct model_cpu m;
struct ovni_mark_cpu mark;
};
struct ovni_emu {
struct ovni_mark_emu mark;
};
int model_ovni_probe(struct emu *emu);

View File

@ -7,11 +7,13 @@
#include "emu.h"
#include "emu_prv.h"
#include "ev_spec.h"
#include "mark.h"
#include "model.h"
#include "model_chan.h"
#include "model_cpu.h"
#include "model_pvt.h"
#include "model_thread.h"
#include "ovni.h"
#include "pv/pcf.h"
#include "pv/prv.h"
#include "system.h"
@ -37,12 +39,16 @@ static struct ev_decl model_evlist[] = {
PAIR_B("OF[", "OF]", "flushing events to disk")
PAIR_E("OU[", "OU]", "unordered event region")
{ "OM[(i64 value, i32 type)", "push mark with value %{value} from type %{type}" },
{ "OM](i64 value, i32 type)", "pop mark with value %{value} from type %{type}" },
{ "OM=(i64 value, i32 type)", "set mark with value %{value} from type %{type}" },
{ NULL, NULL },
};
struct model_spec model_ovni = {
.name = model_name,
.version = "1.0.0",
.version = OVNI_MODEL_VERSION,
.evlist = model_evlist,
.model = model_id,
.create = model_ovni_create,
@ -175,6 +181,19 @@ model_ovni_create(struct emu *emu)
return -1;
}
struct ovni_emu *oemu = calloc(1, sizeof(*oemu));
if (oemu == NULL) {
err("calloc failed:");
return -1;
}
extend_set(&emu->ext, 'O', oemu);
if (mark_create(emu) != 0) {
err("mark_create failed");
return -1;
}
return 0;
}
@ -191,6 +210,11 @@ model_ovni_connect(struct emu *emu)
return -1;
}
if (mark_connect(emu) != 0) {
err("mark_connect failed");
return -1;
}
return 0;
}

View File

@ -23,7 +23,7 @@ emit(struct model *model, struct player *player)
struct emu_ev *ev = player_ev(player);
struct stream *stream = player_stream(player);
printf("%10ld %c%c%c %s ",
printf("%10" PRIi64 " %c%c%c %s ",
ev->rclock,
ev->m,
ev->c,

View File

@ -20,7 +20,7 @@ static int
html_encode(char *dst, int ndst, const char *src)
{
int j = 0;
int nsrc = strlen(src);
int nsrc = (int) strlen(src);
for (int i = 0; i < nsrc; i++) {
/* Simple check */
@ -29,7 +29,7 @@ html_encode(char *dst, int ndst, const char *src)
return -1;
}
int c = src[i];
char c = src[i];
switch (c) {
case '&': strcpy(&dst[j], "&amp;"); j += 5; break;
case '"': strcpy(&dst[j], "&quot;"); j += 6; break;
@ -87,7 +87,7 @@ print_model(struct model_spec *spec)
printf("<dl>\n");
for (long j = 0; j < spec->evspec->nevents; j++) {
if (print_event(spec, j) != 0) {
err("cannot print event %d", j);
err("cannot print event %ld", j);
return -1;
}
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
/* This program is a really bad idea. It attempts to sort streams by using a
@ -74,6 +74,20 @@ ring_add(struct ring *r, struct ovni_ev *ev)
r->head = 0;
}
static void
ring_check(struct ring *r, long long start)
{
uint64_t last_clock = 0;
for (long long i = start; i != r->tail; i = (i + 1) % r->size) {
uint64_t clock = r->ev[i]->header.clock;
if (clock < last_clock) {
die("ring not sorted at i=%lld, last_clock=%"PRIu64" clock=%"PRIu64 ,
i, last_clock, clock);
}
last_clock = clock;
}
}
static ssize_t
find_destination(struct ring *r, uint64_t clock)
{
@ -86,7 +100,7 @@ find_destination(struct ring *r, uint64_t clock)
for (ssize_t i = start; i != end; i = i - 1 < 0 ? r->size - 1 : i - 1) {
last_clock = r->ev[i]->header.clock;
if (last_clock < clock) {
dbg("found suitable position %ld events backwards",
dbg("found suitable position %zd events backwards",
nback);
return i;
}
@ -100,14 +114,14 @@ find_destination(struct ring *r, uint64_t clock)
if (r->head != 0)
die("ring head expected to be 0");
if (r->tail >= r->size - 1)
die("ring tail=%ld expected to be less than %ld", r->tail, r->size - 1);
die("ring tail=%zd expected to be less than %zd", r->tail, r->size - 1);
dbg("starting of ring with nback=%ld", nback);
dbg("starting of ring with nback=%zd", nback);
return r->head;
}
err("cannot find a event previous to clock %lu", clock);
err("nback=%ld, last_clock=%lu", nback, last_clock);
err("cannot find a event previous to clock %"PRIu64, clock);
err("nback=%zd, last_clock=%"PRIu64, nback, last_clock);
return -1;
}
@ -179,11 +193,11 @@ write_events(struct ovni_ev **table, long n, uint8_t *buf)
{
for (long i = 0; i < n; i++) {
struct ovni_ev *ev = table[i];
size_t size = ovni_ev_size(ev);
size_t size = (size_t) ovni_ev_size(ev);
memcpy(buf, ev, size);
buf += size;
dbg("injected event %c%c%c at %ld",
dbg("injected event %c%c%c at %"PRIu64,
ev->header.model,
ev->header.category,
ev->header.value,
@ -200,8 +214,8 @@ cmp_ev(const void *a, const void *b)
struct ovni_ev *ev1 = *pev1;
struct ovni_ev *ev2 = *pev2;
int64_t clock1 = ev1->header.clock;
int64_t clock2 = ev2->header.clock;
int64_t clock1 = (int64_t) ev1->header.clock;
int64_t clock2 = (int64_t) ev2->header.clock;
if (clock1 < clock2)
return -1;
@ -216,29 +230,29 @@ sort_buf(uint8_t *src, uint8_t *buf, int64_t bufsize)
{
struct ovni_ev *ev = (struct ovni_ev *) src;
dbg("first event before sorting %c%c%c at %ld",
dbg("first event before sorting %c%c%c at %"PRIu64,
ev->header.model,
ev->header.category,
ev->header.value,
ev->header.clock);
/* Create a copy of the array */
uint8_t *buf2 = malloc(bufsize);
uint8_t *buf2 = malloc((size_t) bufsize);
if (buf2 == NULL)
die("malloc failed:");
memcpy(buf2, src, bufsize);
memcpy(buf2, src, (size_t) bufsize);
long n = count_events(buf2, buf2 + bufsize);
struct ovni_ev **table = calloc(n, sizeof(struct ovni_ev *));
struct ovni_ev **table = calloc((size_t) n, sizeof(struct ovni_ev *));
if (table == NULL)
die("calloc failed:");
index_events(table, n, buf2);
qsort(table, n, sizeof(struct ovni_ev *), cmp_ev);
qsort(table, (size_t) n, sizeof(struct ovni_ev *), cmp_ev);
write_events(table, n, buf);
dbg("first event after sorting %c%c%c at %ld",
dbg("first event after sorting %c%c%c at %"PRIu64,
ev->header.model,
ev->header.category,
ev->header.value,
@ -254,44 +268,71 @@ static void
write_stream(int fd, void *base, void *dst, const void *src, size_t size)
{
while (size > 0) {
off_t offset = (off_t) ((int64_t) dst - (int64_t) base);
off_t offset = (off_t) dst - (off_t) base;
ssize_t written = pwrite(fd, src, size, offset);
if (written < 0)
die("pwrite failed:");
size -= written;
size -= (size_t) written;
src = (void *) (((uint8_t *) src) + written);
dst = (void *) (((uint8_t *) dst) + written);
}
}
static void
rebuild_ring(struct ring *r, long long start, struct ovni_ev *first, struct ovni_ev *last)
{
long long nbad = 0;
long long n = 0;
struct ovni_ev *ev = first;
for (long long i = start; i != r->tail; i = i + 1 >= r->size ? 0 : i + 1) {
n++;
if (ev != r->ev[i])
nbad++;
if (ev >= last)
die("exceeding last pointer");
r->ev[i] = ev;
size_t size = (size_t) ovni_ev_size(ev);
ev = (struct ovni_ev *) (((uint8_t *) ev) + size);
}
if (ev != last)
die("inconsistency: ev != last");
dbg("rebuilt ring with %lld / %lld misplaced events", nbad, n);
}
static int
execute_sort_plan(struct sortplan *sp)
{
uint64_t clock0 = sp->bad0->header.clock;
dbg("attempt to sort: start clock %ld", sp->bad0->header.clock);
dbg("attempt to sort: start clock %"PRIi64, sp->bad0->header.clock);
uint64_t min_clock = find_min_clock((void *) sp->bad0, (void *) sp->next);
if (min_clock < clock0) {
clock0 = min_clock;
dbg("region not sorted, using min clock=%ld", clock0);
dbg("region not sorted, using min clock=%"PRIi64, clock0);
}
/* Cannot sort in one pass; just fail for now */
int64_t i0 = find_destination(sp->r, clock0);
if (i0 < 0) {
err("cannot find destination for region starting at clock %ld", clock0);
err("cannot find destination for region starting at clock %"PRIi64, clock0);
err("consider increasing the look back size with -n");
return -1;
}
/* Set the pointer to the first event that may be affected */
struct ovni_ev *first = sp->r->ev[i0];
long long dirty = i0;
/* Allocate a working buffer */
int64_t bufsize = ((int64_t) sp->next) - ((int64_t) first);
uintptr_t bufsize = (uintptr_t) sp->next - (uintptr_t) first;
if (bufsize <= 0)
die("bufsize is non-positive");
@ -300,12 +341,19 @@ execute_sort_plan(struct sortplan *sp)
if (!buf)
die("malloc failed:");
sort_buf((uint8_t *) first, buf, bufsize);
sort_buf((uint8_t *) first, buf, (int64_t) bufsize);
write_stream(sp->fd, sp->base, first, buf, bufsize);
free(buf);
/* Pointers from the ring buffer are invalid now, rebuild them */
rebuild_ring(sp->r, dirty, first, sp->next);
/* Invariant: The ring buffer is always sorted here. Check from the
* dirty position onwards, so we avoid scanning all events. */
ring_check(sp->r, dirty);
return 0;
}
@ -313,7 +361,7 @@ execute_sort_plan(struct sortplan *sp)
static int
stream_winsort(struct stream *stream, struct ring *r)
{
char *fn = stream->path;
char *fn = stream->obspath;
int fd = open(fn, O_WRONLY);
if (fd < 0)
@ -375,7 +423,7 @@ stream_winsort(struct stream *stream, struct ring *r)
}
if (empty_regions > 0)
warn("stream %s contains %ld empty sort regions",
warn("stream %s contains %zd empty sort regions",
stream->relpath, empty_regions);
if (updated && fdatasync(fd) < 0)
@ -410,7 +458,7 @@ stream_check(struct stream *stream)
uint64_t cur_clock = ovni_ev_get_clock(ev);
if (cur_clock < last_clock) {
err("backwards jump in time %ld -> %ld for stream %s",
err("backwards jump in time %"PRIi64" -> %"PRIi64" for stream %s",
last_clock, cur_clock, stream->relpath);
backjump = 1;
}
@ -435,8 +483,8 @@ process_trace(struct trace *trace)
struct ring ring;
int ret = 0;
ring.size = max_look_back;
ring.ev = malloc(ring.size * sizeof(struct ovni_ev *));
ring.size = (ssize_t) max_look_back;
ring.ev = malloc((size_t) ring.size * sizeof(struct ovni_ev *));
if (ring.ev == NULL)
die("malloc failed:");
@ -483,7 +531,7 @@ usage(void)
rerr("Sorts the events in each stream of the trace given in\n");
rerr("tracedir, so they are suitable for the emulator ovniemu.\n");
rerr("Only the events enclosed by OU[ OU] are sorted. At most a\n");
rerr("total of %ld events are looked back to insert the unsorted\n",
rerr("total of %zd events are looked back to insert the unsorted\n",
max_look_back);
rerr("events, so the sort procedure can fail with an error.\n");
rerr("\n");
@ -492,7 +540,7 @@ usage(void)
rerr(" trace is already sorted.\n");
rerr("\n");
rerr(" -n Set the number of events to look back.\n");
rerr(" Defaul: %ld\n", max_look_back);
rerr(" Default: %zd\n", max_look_back);
rerr("\n");
rerr(" tracedir The trace directory generated by ovni.\n");
rerr("\n");
@ -511,7 +559,7 @@ parse_args(int argc, char *argv[])
operation_mode = CHECK;
break;
case 'n':
max_look_back = atol(optarg);
max_look_back = (size_t) atol(optarg);
break;
default: /* '?' */
usage();

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include <errno.h>
@ -182,7 +182,7 @@ fill_offset(struct offset *offset, int nsamples)
static void
offset_compute_delta(struct offset *ref, struct offset *cur, int nsamples, int verbose)
{
double *delta = malloc(sizeof(double) * nsamples);
double *delta = malloc(sizeof(double) * (size_t) nsamples);
if (delta == NULL) {
perror("malloc");
@ -199,7 +199,7 @@ offset_compute_delta(struct offset *ref, struct offset *cur, int nsamples, int v
}
}
qsort(delta, nsamples, sizeof(double), cmp_double);
qsort(delta, (size_t) nsamples, sizeof(double), cmp_double);
cur->delta_median = delta[nsamples / 2];
cur->delta_mean = 0;
@ -223,14 +223,14 @@ offset_compute_delta(struct offset *ref, struct offset *cur, int nsamples, int v
static size_t
offset_size(int nsamples)
{
return sizeof(struct offset) + sizeof(double) * nsamples;
return sizeof(struct offset) + sizeof(double) * (size_t) nsamples;
}
static struct offset *
table_get_offset(struct offset_table *table, int i, int nsamples)
{
char *p = (char *) table->_offset;
p += i * offset_size(nsamples);
p += (size_t) i * offset_size(nsamples);
return (struct offset *) p;
}
@ -252,14 +252,14 @@ build_offset_table(int nsamples, int rank, int verbose)
MPI_Comm_size(MPI_COMM_WORLD, &table->nprocs);
table->_offset = calloc(table->nprocs, offset_size(nsamples));
table->_offset = calloc((size_t) table->nprocs, offset_size(nsamples));
if (table->_offset == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
table->offset = malloc(sizeof(struct offset *) * table->nprocs);
table->offset = malloc(sizeof(struct offset *) * (size_t) table->nprocs);
if (table->offset == NULL) {
perror("malloc");
@ -288,8 +288,8 @@ build_offset_table(int nsamples, int rank, int verbose)
void *sendbuf = rank == 0 ? MPI_IN_PLACE : offset;
/* Then collect all the offsets into the rank 0 */
MPI_Gather(sendbuf, offset_size(nsamples), MPI_CHAR,
offset, offset_size(nsamples), MPI_CHAR,
MPI_Gather(sendbuf, (int) offset_size(nsamples), MPI_CHAR,
offset, (int) offset_size(nsamples), MPI_CHAR,
0, MPI_COMM_WORLD);
/* Finish the offsets by computing the deltas on rank 0 */
@ -399,7 +399,7 @@ do_work(struct options *options, int rank)
}
if (drift_mode)
sleep(options->drift_wait);
sleep((unsigned) options->drift_wait);
}
if (rank == 0)

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "path.h"
@ -95,7 +95,7 @@ path_keep(char *path, int n)
void
path_remove_trailing(char *path)
{
int n = strlen(path);
int n = (int) strlen(path);
for (int i = n - 1; i >= 0 && path[i] == '/'; i--) {
path[i] = '\0';
}
@ -112,3 +112,47 @@ path_filename(const char *path)
return start;
}
int
path_append(char dst[PATH_MAX], const char *src, const char *extra)
{
if (snprintf(dst, PATH_MAX, "%s/%s", src, extra) >= PATH_MAX) {
err("path too long: %s/%s", src, extra);
return -1;
}
return 0;
}
/** Copy the path src into dst. */
int
path_copy(char dst[PATH_MAX], const char *src)
{
if (snprintf(dst, PATH_MAX, "%s", src) >= PATH_MAX) {
err("path too long: %s", src);
return -1;
}
return 0;
}
/** Strip last component from path */
void
path_dirname(char path[PATH_MAX])
{
path_remove_trailing(path);
int n = (int) strlen(path);
int i;
for (i = n - 1; i >= 0; i--) {
if (path[i] == '/') {
break;
}
}
/* Remove all '/' */
for (; i >= 0; i--) {
if (path[i] != '/')
break;
else
path[i] = '\0';
}
}

View File

@ -1,9 +1,10 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef PATH_H
#define PATH_H
#include <limits.h>
#include "common.h"
USE_RET int path_has_prefix(const char *path, const char *prefix);
@ -13,5 +14,8 @@ USE_RET int path_keep(char *path, int n);
USE_RET int path_strip(const char *path, int n, const char (**next));
void path_remove_trailing(char *path);
USE_RET const char *path_filename(const char *path);
USE_RET int path_append(char dst[PATH_MAX], const char *src, const char *extra);
USE_RET int path_copy(char dst[PATH_MAX], const char *src);
void path_dirname(char path[PATH_MAX]);
#endif /* PATH_H */

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "player.h"
@ -164,7 +164,7 @@ update_clocks(struct player *player, struct stream *stream)
}
if (sclock < player->lastclock) {
err("backwards jump in time %ld -> %ld in stream '%s'",
err("backwards jump in time %"PRIi64" -> %"PRIi64" in stream '%s'",
player->lastclock, sclock, stream->relpath);
if (player->unsorted == 0)
return -1;

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "proc.h"
@ -6,85 +6,42 @@
#include <stdlib.h>
#include <string.h>
#include "path.h"
#include "stream.h"
#include "thread.h"
static int
get_pid(const char *id, int *pid)
int
proc_stream_get_pid(struct stream *s)
{
/* TODO: Store the PID the metadata.json instead */
JSON_Object *meta = stream_metadata(s);
/* The id must be like "loom.host01.123/proc.345" */
if (path_count(id, '/') != 1) {
err("proc id can only contain one '/': %s", id);
double pid = json_object_dotget_number(meta, "ovni.pid");
/* Zero is used for errors, so forbidden for pid too */
if (pid == 0) {
err("cannot get attribute ovni.pid for stream: %s",
s->relpath);
return -1;
}
/* Get the proc.345 part */
const char *procname;
if (path_next(id, '/', &procname) != 0) {
err("cannot get proc name");
return -1;
}
/* Ensure the prefix is ok */
const char prefix[] = "proc.";
if (!path_has_prefix(procname, prefix)) {
err("proc name must start with '%s': %s", prefix, id);
return -1;
}
/* Get the 345 part */
const char *pidstr;
if (path_next(procname, '.', &pidstr) != 0) {
err("cannot find proc dot in '%s'", id);
return -1;
}
*pid = atoi(pidstr);
return 0;
return (int) pid;
}
int
proc_relpath_get_pid(const char *relpath, int *pid)
{
char id[PATH_MAX];
if (snprintf(id, PATH_MAX, "%s", relpath) >= PATH_MAX) {
err("path too long");
return -1;
}
if (path_keep(id, 2) != 0) {
err("cannot delimite proc dir");
return -1;
}
return get_pid(id, pid);
}
int
proc_init_begin(struct proc *proc, const char *relpath)
proc_init_begin(struct proc *proc, int pid)
{
memset(proc, 0, sizeof(struct proc));
proc->gindex = -1;
proc->appid = 0;
proc->rank = -1;
proc->nranks = 0;
proc->pid = pid;
if (snprintf(proc->id, PATH_MAX, "%s", relpath) >= PATH_MAX) {
if (snprintf(proc->id, PATH_MAX, "proc.%d", pid) >= PATH_MAX) {
err("path too long");
return -1;
}
if (path_keep(proc->id, 2) != 0) {
err("cannot delimite proc dir");
return -1;
}
if (get_pid(proc->id, &proc->pid) != 0) {
err("cannot parse proc pid");
return -1;
}
dbg("created proc %s", proc->id);
return 0;
@ -102,38 +59,105 @@ proc_set_loom(struct proc *proc, struct loom *loom)
proc->loom = loom;
}
int
proc_load_metadata(struct proc *proc, JSON_Object *meta)
static int
load_appid(struct proc *proc, struct stream *s)
{
if (proc->metadata_loaded) {
err("process %s already loaded metadata", proc->id);
JSON_Object *meta = stream_metadata(s);
JSON_Value *appid_val = json_object_dotget_value(meta, "ovni.app_id");
/* May not be present in all thread streams */
if (appid_val == NULL)
return 0;
int appid = (int) json_number(appid_val);
if (proc->appid && proc->appid != appid) {
err("mismatch previous appid %d with stream: %s",
proc->appid, s->relpath);
return -1;
}
JSON_Value *version_val = json_object_get_value(meta, "version");
if (version_val == NULL) {
err("missing attribute 'version' in metadata");
if (appid <= 0) {
err("appid must be >0, stream: %s", s->relpath);
return -1;
}
proc->metadata_version = (int) json_number(version_val);
proc->appid = appid;
return 0;
}
JSON_Value *appid_val = json_object_get_value(meta, "app_id");
if (appid_val == NULL) {
err("missing attribute 'app_id' in metadata");
static int
load_rank(struct proc *proc, struct stream *s)
{
JSON_Object *meta = stream_metadata(s);
JSON_Value *rank_val = json_object_dotget_value(meta, "ovni.rank");
/* Optional */
if (rank_val == NULL) {
dbg("process %s has no rank", proc->id);
return 0;
}
int rank = (int) json_number(rank_val);
if (rank < 0) {
err("rank %d must be >=0, stream: %s", rank, s->relpath);
return -1;
}
proc->appid = (int) json_number(appid_val);
if (proc->rank >= 0 && proc->rank != rank) {
err("mismatch previous rank %d with stream: %s",
proc->rank, s->relpath);
return -1;
}
JSON_Value *rank_val = json_object_get_value(meta, "rank");
/* Same with nranks, but it is not optional now */
JSON_Value *nranks_val = json_object_dotget_value(meta, "ovni.nranks");
if (nranks_val == NULL) {
err("missing ovni.nranks attribute: %s", s->relpath);
return -1;
}
if (rank_val != NULL)
proc->rank = (int) json_number(rank_val);
else
proc->rank = -1;
int nranks = (int) json_number(nranks_val);
proc->metadata_loaded = 1;
if (nranks <= 0) {
err("nranks %d must be >0, stream: %s", nranks, s->relpath);
return -1;
}
if (proc->nranks > 0 && proc->nranks != nranks) {
err("mismatch previous nranks %d with stream: %s",
proc->nranks, s->relpath);
return -1;
}
/* Ensure rank fits in nranks */
if (rank >= nranks) {
err("rank %d must be lower than nranks %d: %s",
rank, nranks, s->relpath);
return -1;
}
dbg("process %s rank=%d nranks=%d",
proc->id, rank, nranks);
proc->rank = rank;
proc->nranks = nranks;
return 0;
}
/** Merges the metadata from the stream in the process. */
int
proc_load_metadata(struct proc *proc, struct stream *s)
{
if (load_appid(proc, s) != 0) {
err("load_appid failed for stream: %s", s->relpath);
return -1;
}
if (load_rank(proc, s) != 0) {
err("load_rank failed for stream: %s", s->relpath);
return -1;
}
return 0;
}
@ -197,8 +221,8 @@ proc_init_end(struct proc *proc)
return -1;
}
if (!proc->metadata_loaded) {
err("metadata not loaded");
if (proc->appid <= 0) {
err("appid not set");
return -1;
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef PROC_H
@ -8,9 +8,9 @@
#include <stdint.h>
#include "common.h"
#include "extend.h"
#include "parson.h"
#include "uthash.h"
struct loom;
struct stream;
struct thread;
struct proc {
@ -18,12 +18,11 @@ struct proc {
char id[PATH_MAX];
int is_init;
int metadata_loaded;
int metadata_version;
int pid;
int index;
int appid;
int rank;
int nranks;
int nthreads;
struct thread *threads;
@ -45,14 +44,14 @@ struct proc {
struct extend ext;
};
USE_RET int proc_relpath_get_pid(const char *relpath, int *pid);
USE_RET int proc_init_begin(struct proc *proc, const char *id);
USE_RET int proc_stream_get_pid(struct stream *s);
USE_RET int proc_init_begin(struct proc *proc, int pid);
USE_RET int proc_init_end(struct proc *proc);
USE_RET int proc_get_pid(struct proc *proc);
void proc_set_gindex(struct proc *proc, int64_t gindex);
void proc_set_loom(struct proc *proc, struct loom *loom);
void proc_sort(struct proc *proc);
USE_RET int proc_load_metadata(struct proc *proc, JSON_Object *meta);
USE_RET int proc_load_metadata(struct proc *proc, struct stream *s);
USE_RET struct thread *proc_find_thread(struct proc *proc, int tid);
USE_RET int proc_add_thread(struct proc *proc, struct thread *thread);
void proc_sort(struct proc *proc);

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "prf.h"
@ -20,7 +20,7 @@ prf_open(struct prf *prf, const char *path, long nrows)
}
prf->nrows = nrows;
prf->rows = calloc(nrows, sizeof(struct prf_row));
prf->rows = calloc((size_t) nrows, sizeof(struct prf_row));
if (prf->rows == NULL) {
err("calloc failed:");

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "prv.h"
@ -25,7 +25,7 @@ prv_open_file(struct prv *prv, long nrows, FILE *file)
prv->file = file;
/* Write fake header to allocate the space */
write_header(file, 0LL, nrows);
write_header(file, 0LL, (int) nrows);
return 0;
}
@ -48,7 +48,7 @@ prv_close(struct prv *prv)
{
/* Fix the header with the current duration */
fseek(prv->file, 0, SEEK_SET);
write_header(prv->file, prv->time, prv->nrows);
write_header(prv->file, prv->time, (int) prv->nrows);
fclose(prv->file);
return 0;
}
@ -69,9 +69,9 @@ find_prv_chan(struct prv *prv, long id)
}
static void
write_line(struct prv *prv, long row_base1, long type, long value)
write_line(struct prv *prv, long row_base1, int64_t type, int64_t value)
{
fprintf(prv->file, "2:0:1:1:%ld:%ld:%ld:%ld\n",
fprintf(prv->file, "2:0:1:1:%ld:%"PRIi64":%"PRIi64":%"PRIi64"\n",
row_base1, prv->time, type, value);
}
@ -117,7 +117,7 @@ emit(struct prv *prv, struct prv_chan *rchan)
}
/* Assume null */
long val = 0;
int64_t val = 0;
if (likely(value.type == VALUE_INT64)) {
val = value.i;
if (rchan->flags & PRV_NEXT)

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2023-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "sort.h"
@ -106,8 +106,8 @@ sort_cb_input(struct chan *in_chan, void *ptr)
if (likely(sort->copied)) {
sort_replace(sort->sorted, sort->n, old, new);
} else {
memcpy(sort->sorted, sort->values, sort->n * sizeof(int64_t));
qsort(sort->sorted, sort->n, sizeof(int64_t), cmp_int64);
memcpy(sort->sorted, sort->values, (size_t) sort->n * sizeof(int64_t));
qsort(sort->sorted, (size_t) sort->n, sizeof(int64_t), cmp_int64);
sort->copied = 1;
}
@ -141,22 +141,22 @@ sort_init(struct sort *sort, struct bay *bay, int64_t n, const char *name)
memset(sort, 0, sizeof(struct sort));
sort->bay = bay;
sort->n = n;
sort->inputs = calloc(n, sizeof(struct sort_input));
sort->inputs = calloc((size_t) n, sizeof(struct sort_input));
if (sort->inputs == NULL) {
err("calloc failed:");
return -1;
}
sort->outputs = calloc(n, sizeof(struct chan));
sort->outputs = calloc((size_t) n, sizeof(struct chan));
if (sort->outputs == NULL) {
err("calloc failed:");
return -1;
}
sort->values = calloc(n, sizeof(int64_t));
sort->values = calloc((size_t) n, sizeof(int64_t));
if (sort->values == NULL) {
err("calloc failed:");
return -1;
}
sort->sorted = calloc(n, sizeof(int64_t));
sort->sorted = calloc((size_t) n, sizeof(int64_t));
if (sort->sorted == NULL) {
err("calloc failed:");
return -1;
@ -165,7 +165,7 @@ sort_init(struct sort *sort, struct bay *bay, int64_t n, const char *name)
/* Init and register outputs */
for (int64_t i = 0; i < n; i++) {
struct chan *out = &sort->outputs[i];
chan_init(out, CHAN_SINGLE, "%s.out%ld", name, i);
chan_init(out, CHAN_SINGLE, "%s.out%"PRIi64, name, i);
/* The sort module may write multiple times to the same
* channel if we update more than one input. */
@ -176,7 +176,7 @@ sort_init(struct sort *sort, struct bay *bay, int64_t n, const char *name)
chan_prop_set(out, CHAN_ALLOW_DUP, 1);
if (bay_register(bay, out) != 0) {
err("bay_register out%ld failed", i);
err("bay_register out%"PRIi64" failed", i);
return -1;
}
}
@ -190,7 +190,7 @@ sort_set_input(struct sort *sort, int64_t index, struct chan *chan)
struct sort_input *input = &sort->inputs[index];
if (input->chan != NULL) {
err("input %d already has a channel", index);
err("input %"PRIi64" already has a channel", index);
return -1;
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "stream.h"
@ -59,7 +59,7 @@ load_stream_fd(struct stream *stream, int fd)
}
int prot = PROT_READ | PROT_WRITE;
stream->buf = mmap(NULL, st.st_size, prot, MAP_PRIVATE, fd, 0);
stream->buf = mmap(NULL, (size_t) st.st_size, prot, MAP_PRIVATE, fd, 0);
if (stream->buf == MAP_FAILED) {
err("mmap failed:");
@ -71,6 +71,96 @@ load_stream_fd(struct stream *stream, int fd)
return 0;
}
static int
load_obs(struct stream *stream, const char *path)
{
int fd;
if ((fd = open(path, O_RDWR)) == -1) {
err("open %s failed:", path);
return -1;
}
if (load_stream_fd(stream, fd) != 0) {
err("load_stream_fd failed for: %s", path);
return -1;
}
if (check_stream_header(stream) != 0) {
err("stream has bad header: %s", path);
return -1;
}
stream->offset = sizeof(struct ovni_stream_header);
stream->usize = stream->size - stream->offset;
if (stream->offset < stream->size) {
stream->active = 1;
} else if (stream->offset == stream->size) {
warn("stream '%s' has zero events", stream->relpath);
stream->active = 0;
} else {
err("impossible, offset %"PRIi64" bigger than size %"PRIi64,
stream->offset, stream->size);
return -1;
}
/* No need to keep the fd open */
if (close(fd)) {
err("close failed:");
return -1;
}
return 0;
}
static int
check_version(JSON_Object *meta)
{
JSON_Value *version_val = json_object_get_value(meta, "version");
if (version_val == NULL) {
err("missing attribute \"version\"");
return -1;
}
int version = (int) json_number(version_val);
if (version != OVNI_METADATA_VERSION) {
err("metadata version mismatch %d (expected %d)",
version, OVNI_METADATA_VERSION);
return -1;
}
return 0;
}
static JSON_Object *
load_json(const char *path)
{
JSON_Value *vmeta = json_parse_file_with_comments(path);
if (vmeta == NULL) {
err("json_parse_file_with_comments() failed");
return NULL;
}
JSON_Object *meta = json_value_get_object(vmeta);
if (meta == NULL) {
err("json_value_get_object() failed");
return NULL;
}
if (check_version(meta) != 0) {
err("check_version failed");
return NULL;
}
return meta;
}
/** Loads a stream from disk.
*
* The relpath must be pointing to a directory with the stream.json and
* stream.obs files.
*/
int
stream_load(struct stream *stream, const char *tracedir, const char *relpath)
{
@ -91,41 +181,23 @@ stream_load(struct stream *stream, const char *tracedir, const char *relpath)
dbg("loading %s", stream->relpath);
int fd;
if ((fd = open(stream->path, O_RDWR)) == -1) {
err("open %s failed:", stream->path);
if (path_append(stream->jsonpath, stream->path, "stream.json") != 0) {
err("path_append failed");
return -1;
}
if (load_stream_fd(stream, fd) != 0) {
err("load_stream_fd failed for stream '%s'",
stream->path);
if ((stream->meta = load_json(stream->jsonpath)) == NULL) {
err("load_json failed for: %s", stream->jsonpath);
return -1;
}
if (check_stream_header(stream) != 0) {
err("stream '%s' has bad header",
stream->path);
if (path_append(stream->obspath, stream->path, "stream.obs") != 0) {
err("path_append failed");
return -1;
}
stream->offset = sizeof(struct ovni_stream_header);
stream->usize = stream->size - stream->offset;
if (stream->offset < stream->size) {
stream->active = 1;
} else if (stream->offset == stream->size) {
warn("stream '%s' has zero events", stream->relpath);
stream->active = 0;
} else {
err("impossible, offset %ld bigger than size %ld",
stream->offset, stream->size);
return -1;
}
/* No need to keep the fd open */
if (close(fd)) {
err("close failed:");
if (load_obs(stream, stream->obspath) != 0) {
err("load_obs failed");
return -1;
}
@ -144,6 +216,16 @@ stream_data_get(struct stream *stream)
return stream->data;
}
/* Is never NULL */
JSON_Object *
stream_metadata(struct stream *stream)
{
if (stream->meta == NULL)
die("stream metadata is NULL: %s", stream->relpath);
return stream->meta;
}
int
stream_clkoff_set(struct stream *stream, int64_t clkoff)
{
@ -196,7 +278,7 @@ stream_step(struct stream *stream)
/* It cannot pass the size, otherwise we are reading garbage */
if (stream->offset > stream->size) {
err("stream offset %ld exceeds size %ld",
err("stream offset %"PRIi64" exceeds size %"PRIi64,
stream->offset, stream->size);
return -1;
}
@ -223,7 +305,7 @@ stream_step(struct stream *stream)
/* Ensure the clock grows monotonically if unsorted flag not set */
if (stream->unsorted == 0) {
if (clock < stream->lastclock) {
err("clock goes backwards %ld -> %ld in stream '%s' at offset %ld",
err("clock goes backwards %"PRIi64" -> %"PRIi64" in stream '%s' at offset %"PRIi64,
stream->lastclock,
clock,
stream->relpath,
@ -241,7 +323,7 @@ stream_step(struct stream *stream)
void
stream_progress(struct stream *stream, int64_t *done, int64_t *total)
{
*done = stream->offset - sizeof(struct ovni_stream_header);
*done = stream->offset - (int64_t) sizeof(struct ovni_stream_header);
*total = stream->usize;
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef STREAM_H
@ -8,6 +8,7 @@
#include <stdint.h>
#include "common.h"
#include "heap.h"
#include "parson.h"
struct ovni_ev;
struct stream {
@ -27,13 +28,17 @@ struct stream {
int active;
int unsorted;
char path[PATH_MAX];
char path[PATH_MAX]; /* To stream dir */
char relpath[PATH_MAX]; /* To tracedir */
char obspath[PATH_MAX]; /* To obs file */
char jsonpath[PATH_MAX]; /* To json file */
int64_t usize; /* Useful size for events */
int64_t offset;
double progress;
JSON_Object *meta;
};
USE_RET int stream_load(struct stream *stream, const char *tracedir, const char *relpath);
@ -46,5 +51,6 @@ USE_RET int64_t stream_lastclock(struct stream *stream);
void stream_allow_unsorted(struct stream *stream);
void stream_data_set(struct stream *stream, void *data);
USE_RET void *stream_data_get(struct stream *stream);
USE_RET JSON_Object *stream_metadata(struct stream *stream);
#endif /* STREAM_H */

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "system.h"
@ -11,7 +11,6 @@
#include "cpu.h"
#include "emu_args.h"
#include "loom.h"
#include "metadata.h"
#include "proc.h"
#include "pv/prf.h"
#include "pv/pvt.h"
@ -24,11 +23,11 @@
struct bay;
static struct thread *
create_thread(struct proc *proc, const char *tracedir, const char *relpath)
create_thread(struct proc *proc, struct stream *s)
{
int tid;
if (thread_relpath_get_tid(relpath, &tid) != 0) {
err("cannot get thread tid from %s", relpath);
if ((tid = thread_stream_get_tid(s)) < 0) {
err("cannot get thread tid from stream: %s", s->relpath);
return NULL;
}
@ -45,21 +44,13 @@ create_thread(struct proc *proc, const char *tracedir, const char *relpath)
return NULL;
}
if (thread_init_begin(thread, relpath) != 0) {
err("cannot init thread");
if (thread_init_begin(thread, tid) != 0) {
err("thread_init_begin failed: %s", s->relpath);
return NULL;
}
/* Build metadata path */
char mpath[PATH_MAX];
if (snprintf(mpath, PATH_MAX, "%s/%s/thread.%d.json",
tracedir, proc->id, tid) >= PATH_MAX) {
err("path too long");
return NULL;
}
if (metadata_load_thread(mpath, thread) != 0) {
err("cannot load metadata from %s", mpath);
if (thread_load_metadata(thread, s) != 0) {
err("thread_load_metadata failed: %s", s->relpath);
return NULL;
}
@ -72,48 +63,39 @@ create_thread(struct proc *proc, const char *tracedir, const char *relpath)
}
static struct proc *
create_proc(struct loom *loom, const char *tracedir, const char *relpath)
create_proc(struct loom *loom, struct stream *s)
{
int pid;
if (proc_relpath_get_pid(relpath, &pid) != 0) {
err("cannot get proc pid from %s", relpath);
int pid = proc_stream_get_pid(s);
if (pid < 0) {
err("cannot get proc pid from stream: %s", s->relpath);
return NULL;
}
struct proc *proc = loom_find_proc(loom, pid);
if (proc != NULL)
return proc;
proc = malloc(sizeof(struct proc));
if (proc == NULL) {
err("malloc failed:");
return NULL;
/* Create a new process */
proc = malloc(sizeof(struct proc));
if (proc == NULL) {
err("malloc failed:");
return NULL;
}
if (proc_init_begin(proc, pid) != 0) {
err("proc_init_begin failed: %s", s->relpath);
return NULL;
}
if (loom_add_proc(loom, proc) != 0) {
err("loom_add_proc failed");
return NULL;
}
}
if (proc_init_begin(proc, relpath) != 0) {
err("proc_init_begin failed");
return NULL;
}
/* Build metadata path */
char mpath[PATH_MAX];
if (snprintf(mpath, PATH_MAX, "%s/%s/metadata.json",
tracedir, proc->id) >= PATH_MAX) {
err("path too long");
return NULL;
}
/* Load metadata too */
if (metadata_load_proc(mpath, loom, proc) != 0) {
err("cannot load metadata from %s", mpath);
return NULL;
}
if (loom_add_proc(loom, proc) != 0) {
err("loom_add_proc failed");
/* The appid is populated from the metadata */
if (proc_load_metadata(proc, s) != 0) {
err("proc_load_metadata failed");
return NULL;
}
@ -131,16 +113,11 @@ find_loom(struct system *sys, const char *id)
}
static struct loom *
create_loom(struct system *sys, const char *relpath)
create_loom(struct system *sys, struct stream *s)
{
char name[PATH_MAX];
if (snprintf(name, PATH_MAX, "%s", relpath) >= PATH_MAX) {
err("path too long: %s", relpath);
return NULL;
}
if (strtok(name, "/") == NULL) {
err("cannot find first '/': %s", relpath);
const char *name = loom_name(s);
if (name == NULL) {
err("loom_name failed");
return NULL;
}
@ -163,6 +140,11 @@ create_loom(struct system *sys, const char *relpath)
sys->nlooms++;
}
if (loom_load_metadata(loom, s) != 0) {
err("loom_load_metadata failed for stream: %s", s->relpath);
return NULL;
}
return loom;
}
@ -220,13 +202,35 @@ report_libovni_version(struct system *sys)
return 0;
}
static int
is_thread_stream(struct stream *s)
{
JSON_Object *meta = stream_metadata(s);
if (meta == NULL) {
err("no metadata for stream: %s", s->relpath);
return -1;
}
/* All streams must have a ovni.part attribute */
const char *part_type = json_object_dotget_string(meta, "ovni.part");
if (part_type == NULL) {
err("cannot get attribute ovni.part for stream: %s",
s->relpath);
return -1;
}
if (strcmp(part_type, "thread") == 0)
return 1;
return 0;
}
static int
create_system(struct system *sys, struct trace *trace)
{
const char *dir = trace->tracedir;
/* Allocate the lpt map */
sys->lpt = calloc(trace->nstreams, sizeof(struct lpt));
sys->lpt = calloc((size_t) trace->nstreams, sizeof(struct lpt));
if (sys->lpt == NULL) {
err("calloc failed:");
return -1;
@ -234,25 +238,28 @@ create_system(struct system *sys, struct trace *trace)
size_t i = 0;
for (struct stream *s = trace->streams; s ; s = s->next) {
if (!loom_matches(s->relpath)) {
int ok = is_thread_stream(s);
if (ok < 0) {
err("is_thread_stream failed");
return -1;
} else if (ok == 0) {
warn("ignoring unknown stream %s", s->relpath);
continue;
}
struct loom *loom = create_loom(sys, s->relpath);
struct loom *loom = create_loom(sys, s);
if (loom == NULL) {
err("create_loom failed");
return -1;
}
/* Loads metadata too */
struct proc *proc = create_proc(loom, dir, s->relpath);
struct proc *proc = create_proc(loom, s);
if (proc == NULL) {
err("create_proc failed");
return -1;
}
struct thread *thread = create_thread(proc, dir, s->relpath);
struct thread *thread = create_thread(proc, s);
if (thread == NULL) {
err("create_thread failed");
return -1;
@ -267,14 +274,6 @@ create_system(struct system *sys, struct trace *trace)
stream_data_set(s, lpt);
}
/* Ensure all looms have at least one CPU */
for (struct loom *l = sys->looms; l; l = l->next) {
if (l->ncpus == 0) {
err("loom %s has no physical CPUs", l->id);
return -1;
}
}
return 0;
}
@ -340,28 +339,28 @@ print_system(struct system *sys)
{
err("content of system: ");
for (struct loom *l = sys->looms; l; l = l->next) {
err("%s gindex=%d", l->id, l->gindex);
err("+ %ld processes: ", l->nprocs);
err("%s gindex=%"PRIi64, l->id, l->gindex);
err("+ %zd processes: ", l->nprocs);
for (struct proc *p = l->procs; p; p = p->hh.next) {
err("| %s gindex=%d pid=%d",
err("| %s gindex=%"PRIi64" pid=%d",
p->id, p->gindex, p->pid);
err("| + %ld threads: ", p->nthreads);
err("| + %d threads: ", p->nthreads);
for (struct thread *t = p->threads; t; t = t->hh.next) {
err("| | %s tid=%d",
t->id, t->tid);
}
}
err("+ %ld phy cpus: ", l->ncpus);
err("+ %zd phy cpus: ", l->ncpus);
for (struct cpu *cpu = l->cpus; cpu; cpu = cpu->hh.next) {
err("| %s gindex=%ld phyid=%d",
err("| %s gindex=%"PRIi64" phyid=%d",
cpu->name,
cpu->gindex,
cpu->phyid);
}
err("+ 1 virtual cpu: ", l->ncpus);
err("+ 1 virtual cpu: ");
struct cpu *cpu = &l->vcpu;
err("| %s gindex=%ld phyid=%d",
err("| %s gindex=%"PRIi64" phyid=%d",
cpu->name,
cpu->gindex,
cpu->phyid);
@ -373,20 +372,20 @@ init_global_indices(struct system *sys)
{
size_t iloom = 0;
for (struct loom *l = sys->looms; l; l = l->next)
loom_set_gindex(l, iloom++);
loom_set_gindex(l, (int64_t) iloom++);
sys->nprocs = 0;
for (struct proc *p = sys->procs; p; p = p->gnext)
proc_set_gindex(p, sys->nprocs++);
proc_set_gindex(p, (int64_t) sys->nprocs++);
sys->nthreads = 0;
for (struct thread *t = sys->threads; t; t = t->gnext)
thread_set_gindex(t, sys->nthreads++);
thread_set_gindex(t, (int64_t) sys->nthreads++);
sys->ncpus = 0;
sys->nphycpus = 0;
for (struct cpu *c = sys->cpus; c; c = c->next) {
cpu_set_gindex(c, sys->ncpus++);
cpu_set_gindex(c, (int64_t) sys->ncpus++);
if (!c->is_virtual)
sys->nphycpus++;
}
@ -424,7 +423,7 @@ init_end_system(struct system *sys)
}
}
info("loaded %ld looms, %ld processes, %ld threads and %ld cpus",
info("loaded %zd looms, %zd processes, %zd threads and %zd cpus",
sys->nlooms, sys->nprocs, sys->nthreads, sys->nphycpus);
return 0;
@ -518,7 +517,7 @@ init_offsets(struct system *sys, struct trace *trace)
/* If we have more than one hostname and no offset table has been found,
* we won't be able to synchronize the clocks */
if (n == 0 && sys->nlooms > 1) {
warn("no clock offset file loaded with %ld looms",
warn("no clock offset file loaded with %zd looms",
sys->nlooms);
}
@ -552,6 +551,12 @@ set_sort_criteria(struct system *sys)
int some_have = 0;
int all_have = 1;
for (struct loom *l = sys->looms; l; l = l->next) {
/* Set the rank_min for later sorting */
if (loom_set_rank_min(l) != 0) {
err("loom_set_rank_min failed");
return -1;
}
if (l->rank_enabled)
some_have = 1;
else
@ -641,13 +646,13 @@ system_connect(struct system *sys, struct bay *bay, struct recorder *rec)
{
/* Create Paraver traces */
struct pvt *pvt_cpu = NULL;
if ((pvt_cpu = recorder_add_pvt(rec, "cpu", sys->ncpus)) == NULL) {
if ((pvt_cpu = recorder_add_pvt(rec, "cpu", (long) sys->ncpus)) == NULL) {
err("recorder_add_pvt failed");
return -1;
}
struct pvt *pvt_th = NULL;
if ((pvt_th = recorder_add_pvt(rec, "thread", sys->nthreads)) == NULL) {
if ((pvt_th = recorder_add_pvt(rec, "thread", (long) sys->nthreads)) == NULL) {
err("recorder_add_pvt failed");
return -1;
}
@ -667,7 +672,7 @@ system_connect(struct system *sys, struct bay *bay, struct recorder *rec)
return -1;
}
if (prf_add(prf, th->gindex, name) != 0) {
if (prf_add(prf, (long) th->gindex, name) != 0) {
err("prf_add failed for thread '%s'", th->id);
return -1;
}
@ -688,7 +693,7 @@ system_connect(struct system *sys, struct bay *bay, struct recorder *rec)
}
struct prf *prf = pvt_get_prf(pvt_cpu);
if (prf_add(prf, cpu->gindex, cpu->name) != 0) {
if (prf_add(prf, (long) cpu->gindex, cpu->name) != 0) {
err("prf_add failed for cpu '%s'", cpu->name);
return -1;
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
/* Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "task.h"
@ -258,13 +258,22 @@ task_type_create(struct task_info *info, uint32_t type_id, const char *label)
return -1;
}
type->gid = task_get_type_gid(label);
int n = snprintf(type->label, MAX_PCF_LABEL, "%s", label);
int n;
if (label[0] == '\0') {
/* Give a name if empty */
n = snprintf(type->label, MAX_PCF_LABEL,
"(unlabeled task type %u)", type_id);
} else {
n = snprintf(type->label, MAX_PCF_LABEL, "%s", label);
}
if (n >= MAX_PCF_LABEL) {
err("task type label too long: %s", label);
err("task type %u label too long", type_id);
return -1;
}
type->gid = task_get_type_gid(type->label);
/* Add the new task type to the hash table */
HASH_ADD_INT(info->types, id, type);
@ -279,7 +288,7 @@ task_create_pcf_types(struct pcf_type *pcftype, struct task_type *types)
/* Emit types for all task types */
for (struct task_type *tt = types; tt != NULL; tt = tt->hh.next) {
struct pcf_value *pcfvalue = pcf_find_value(pcftype, tt->gid);
struct pcf_value *pcfvalue = pcf_find_value(pcftype, (int) tt->gid);
if (pcfvalue != NULL) {
/* Ensure the label is the same, so we know that
* no collision occurred */
@ -292,7 +301,7 @@ task_create_pcf_types(struct pcf_type *pcftype, struct task_type *types)
}
}
if (pcf_add_value(pcftype, tt->gid, tt->label) == NULL) {
if (pcf_add_value(pcftype, (int) tt->gid, tt->label) == NULL) {
err("pcf_add_value failed");
return -1;
}

Some files were not shown because too many files have changed in this diff Show More