Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
M
MPI-BugBench
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
High Performance Computing - Public
MPI-BugBench
Commits
ed2c1cc8
Commit
ed2c1cc8
authored
Feb 8, 2024
by
Jammer, Tim
Browse files
Options
Downloads
Patches
Plain Diff
TemplateManager dealing with instructions directly
parent
91e29056
No related branches found
No related tags found
1 merge request
!14
Infrastructure: Remove Instructionblock
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
scripts/Infrastructure/InstructionBlock.py
+0
-202
0 additions, 202 deletions
scripts/Infrastructure/InstructionBlock.py
scripts/Infrastructure/Template.py
+105
-106
105 additions, 106 deletions
scripts/Infrastructure/Template.py
with
105 additions
and
308 deletions
scripts/Infrastructure/InstructionBlock.py
deleted
100644 → 0
+
0
−
202
View file @
91e29056
from
__future__
import
annotations
import
typing
from
scripts.Infrastructure.Instruction
import
Instruction
from
scripts.Infrastructure.MPICall
import
MPICall
class
InstructionBlock
:
"""
Class Overview:
The `InstructionBlock` class represents a block of instructions in a Testcase (to be registered for a template).
First, the Instructions for all ranks are executed (in the order they are registered)
Then each thread executes the instructions registered to this specific rank
If one need a different Order: use multiple Instruction Blocks
Methods:
- `__init__(self)`: Initializes a new instance of the InstructionBlock class.
- `register_operation(self, op, kind=
'
all
'
)`: Registers an operation based on rank.
- `get_version(self)`: Retrieves required MPI version
- `__str__(self)`: Converts the InstructionBlock instance to a string, replacing placeholders.
"""
def
__init__
(
self
,
name
:
str
=
None
):
"""
Initialize an empty InstructionBlock
Parameters:
- name (str): The name of the block (for referencing this block with the template Manager)
May be None, does not influence the code generated
"""
self
.
operations
=
{
'
all
'
:
[],
'
not0
'
:
[],
}
assert
not
isinstance
(
name
,
int
)
self
.
name
=
name
def
register_instruction
(
self
,
op
:
str
|
Instruction
|
typing
.
List
[
Instruction
],
kind
:
str
|
int
=
'
all
'
):
"""
Registers an operation based on rank.
Parameters:
- op: The operation (or list of Operations) to register.
- kind: Rank to execute the operation (
'
all
'
,
'
not0
'
, or integer).
- all: all Ranks execute this operation
- not0: all Ranks but the Root (rank 0) execute
- Or the integer of the rank that should execute
Note: if a str is passed as the operation, it will create a new Instruction from the given string
"""
if
isinstance
(
op
,
str
):
op
=
Instruction
(
op
)
if
kind
==
'
all
'
:
if
isinstance
(
op
,
list
):
self
.
operations
[
'
all
'
].
extend
(
op
)
else
:
self
.
operations
[
'
all
'
].
append
(
op
)
elif
kind
==
'
not0
'
:
if
isinstance
(
op
,
list
):
self
.
operations
[
'
not0
'
].
extend
(
op
)
else
:
self
.
operations
[
'
not0
'
].
append
(
op
)
else
:
as_int
=
int
(
kind
)
# will Raise ValueError if not integer
if
as_int
not
in
self
.
operations
:
self
.
operations
[
as_int
]
=
[]
if
isinstance
(
op
,
list
):
self
.
operations
[
as_int
].
extend
(
op
)
else
:
self
.
operations
[
as_int
].
append
(
op
)
def
get_version
(
self
)
->
str
:
"""
Retrieves the minimum required MPI version.
Returns:
str: The MPI version used.
"""
max_v
=
"
0.0
"
for
k
,
v
in
self
.
operations
.
items
():
for
op
in
v
:
if
isinstance
(
op
,
MPICall
):
max_v
=
max
(
op
.
get_version
(),
max_v
)
return
max_v
def
__str__
(
self
):
"""
Converts the InstructionBlock instance to a string, replacing placeholders.
Returns:
str: The string representation of the InstructionBlock.
"""
result_str
=
""
for
key
,
val
in
self
.
operations
.
items
():
if
key
==
'
all
'
:
for
op
in
val
:
result_str
+=
str
(
op
)
+
"
\n
"
elif
key
==
'
not0
'
:
if
len
(
val
)
>
0
:
result_str
+=
"
if (rank != 0) {
\n
"
for
op
in
val
:
result_str
+=
str
(
op
)
+
"
\n
"
result_str
+=
"
}
\n
"
else
:
if
len
(
val
)
>
0
:
result_str
+=
"
if (rank == %d) {
\n
"
%
int
(
key
)
for
op
in
val
:
result_str
+=
str
(
op
)
+
"
\n
"
result_str
+=
"
}
\n
"
return
result_str
def
has_instruction
(
self
,
kind
:
int
|
str
=
'
all
'
,
index
:
int
=
0
)
->
bool
:
"""
Checks if the Block has an operation with the given index and kind
Parameters:
- kind (
'
all
'
,
'
not0
'
or integer): which ranks should execute the operation
- index (int ): the index of the operation within the given kind
Returns:
boolean
"""
try
:
result
=
self
.
operations
[
kind
][
index
]
return
True
except
(
KeyError
,
IndexError
)
as
e
:
return
False
def
get_instruction
(
self
,
kind
:
int
|
str
=
'
all
'
,
index
:
str
|
int
=
0
)
->
Instruction
|
typing
.
List
[
Instruction
]:
"""
Retrieve the operation registered. will Raise IndexError if not present
Parameters:
- kind (
'
all
'
,
'
not0
'
or integer): which ranks should execute the operation
- index (
'
all
'
or int): the index of the operation within the given kind;
'
all
'
means that the list of all operations for the kind is returned
Returns:
str: The operation specified by kind and index
"""
if
index
==
'
all
'
:
if
kind
not
in
self
.
operations
:
return
[]
return
self
.
operations
[
kind
]
else
:
as_int
=
int
(
index
)
# will Raise ValueError if not integer
return
self
.
operations
[
kind
][
as_int
]
def
replace_instruction
(
self
,
op
:
str
|
Instruction
|
typing
.
List
[
Instruction
],
kind
:
str
|
int
=
'
all
'
,
index
:
str
|
int
=
0
):
"""
Replace the operation registered. will Raise IndexError if not present
Parameters:
- op the new operation or list of operations
- kind (
'
all
'
,
'
not0
'
or integer): which ranks should execute the operation
- index (
'
all
'
or int): the index of the operation within the given kind;
'
all
'
means all operations will be replaced with the given list
Notes : if one wants to replace all operations one needs to provide a list
if one only wants to replace one operation: no list of operations is allowed
if a string is passed as the operation, it will create a new Instruction
"""
if
isinstance
(
op
,
str
):
op
=
Instruction
(
op
)
if
index
==
'
all
'
:
if
not
isinstance
(
op
,
list
):
raise
ValueError
(
'
Provide List for replacement
'
)
self
.
operations
[
kind
]
=
op
else
:
as_int
=
int
(
index
)
# will Raise ValueError if not integer
if
not
isinstance
(
op
,
Instruction
):
raise
ValueError
(
'
Provide Instruction
'
)
if
len
(
self
.
operations
[
kind
])
<
as_int
:
raise
IndexError
(
"
Operation Not Found
"
)
self
.
operations
[
kind
][
as_int
]
=
op
def
insert_instruction
(
self
,
op
:
str
|
Instruction
|
typing
.
List
[
Instruction
],
kind
:
str
|
int
=
'
all
'
,
before_index
:
int
=
0
):
"""
Inserts an operation before the specified one. will Raise IndexError if not present
Parameters:
- op the new operation or list of operations
- kind (
'
all
'
,
'
not0
'
or integer): which ranks should execute the operation
- index (int): the index of the operation within the given kind
note: if str is passed as the operation, it will Create a New Instruction
"""
if
isinstance
(
op
,
str
):
op
=
Instruction
(
op
)
as_int
=
int
(
before_index
)
# will Raise ValueError if not integer
if
len
(
self
.
operations
[
kind
])
<
before_index
:
raise
IndexError
(
"
Operation Not Found
"
)
if
isinstance
(
op
,
list
):
self
.
operations
[
kind
]
=
(
self
.
operations
[
kind
][
0
:
before_index
-
1
]
+
op
+
self
.
operations
[
kind
][
before_index
:])
else
:
self
.
operations
[
kind
].
insert
(
before_index
,
op
)
def
remove_instruction
(
self
,
kind
:
str
|
int
=
'
all
'
,
index
:
str
|
int
=
0
):
"""
Removes the operation registered. will Raise IndexError if not present
Parameters:
- kind (
'
all
'
,
'
not0
'
or integer): which ranks should execute the operation
- index (
'
all
'
or int): the index of the operation within the given kind
"""
if
index
==
'
all
'
:
self
.
operations
[
kind
]
=
[]
else
:
as_int
=
int
(
index
)
# will Raise ValueError if not integer
if
len
(
self
.
operations
[
kind
])
<
index
:
raise
IndexError
(
"
Operation Not Found
"
)
del
self
.
operations
[
kind
][
index
]
This diff is collapsed.
Click to expand it.
scripts/Infrastructure/Template.py
+
105
−
106
View file @
ed2c1cc8
#! /usr/bin/python3
from
__future__
import
annotations
import
typing
from
scripts.Infrastructure.InstructionBlock
import
InstructionBlock
from
scripts.Infrastructure.Instruction
import
Instruction
from
scripts.Infrastructure.MPICall
import
MPICall
template
=
"""
// @{generatedby}@
...
...
@@ -83,7 +89,7 @@ class TemplateManager:
"""
self
.
_descr_full
=
""
self
.
_descr_short
=
""
self
.
_
block
s
=
[]
self
.
_
instruction
s
=
[]
self
.
_thread_level
=
thread_level
self
.
_min_ranks
=
min_ranks
self
.
_has_finalize
=
has_finalize
...
...
@@ -117,13 +123,16 @@ class TemplateManager:
.
replace
(
"
@{version}@
"
,
version
)
.
replace
(
"
@{test_code}@
"
,
block_string
))
def
register_instruction
_block
(
self
,
block
:
Instruction
Block
):
def
register_instruction
(
self
,
inst
:
Instruction
|
typing
.
List
[
Instruction
]
):
"""
Registers an instruction block with the template. inserting it at the end, before the mpi finalize
Parameters:
- block: The instruction block to register.
"""
self
.
_blocks
.
append
(
block
)
if
isinstance
(
inst
,
list
):
self
.
_instructions
.
extend
(
inst
)
else
:
self
.
_instructions
.
append
(
inst
)
def
get_version
(
self
)
->
str
:
"""
...
...
@@ -157,132 +166,122 @@ class TemplateManager:
assert
self
.
_descr_short
!=
""
return
self
.
_descr_short
def
get_block
(
self
,
block_name
:
str
=
None
,
idx
:
int
=
None
)
->
InstructionBlock
:
def
get_instruction
(
self
,
identifier
:
str
=
None
,
return_list
=
False
,
idx
:
int
=
None
)
->
Instruction
|
typing
.
List
[
Instruction
]:
"""
Retrieves the given Instruction Block Either by name or by index
Raises IndexError if the specified block is not found
Raises IndexError if multiple Blocks with the given name are found
Raises ValueError if Both a block name and index are given (or none is given)
Args:
block_name (str): The name of the InstructionBlock to receive
idx (int): index of the InstructionBlock to retrieve
Returns:
the specified Block
TODO DOCUMENTATION
"""
if
block_name
is
not
None
:
if
idx
is
not
None
:
raise
ValueError
(
"
Both block name and index are given
"
)
to_return
=
[
b
for
b
in
self
.
_blocks
if
b
.
name
==
block_name
]
if
len
(
to_return
)
==
0
:
raise
IndexError
(
"
Block Not Found
"
)
if
len
(
to_return
)
>
1
:
raise
IndexError
(
"
Multiple Blocks Found
"
)
# assert only one param is not None
parameters
=
[
identifier
,
idx
]
if
parameters
.
count
(
None
)
!=
1
:
raise
ValueError
(
"
Only one parameter is allowed to be specified
"
)
if
identifier
is
not
None
:
to_return
=
[
i
for
i
in
self
.
_instructions
if
i
.
get_identifier
()
==
identifier
]
if
return_list
:
return
to_return
if
len
(
to_return
)
==
1
:
return
to_return
[
0
]
if
len
(
to_return
)
==
0
:
raise
IndexError
(
"
Found no matching Instruction
"
)
raise
IndexError
(
"
Found too many elements
"
)
if
idx
is
not
None
:
if
block_name
is
not
None
:
r
aise
ValueError
(
"
Both block name and index are given
"
)
return
self
.
_
block
s
[
idx
]
if
return_list
:
r
eturn
[
self
.
_instructions
[
idx
]]
return
self
.
_
instruction
s
[
idx
]
raise
ValueError
(
"
Neither Both block name nor index is given
"
)
def
insert_block
(
self
,
new_block
:
InstructionBlock
,
after_block_name
:
str
=
None
,
after_idx
:
int
=
None
,
before_block_name
:
str
=
None
,
before_idx
:
int
=
None
):
def
__get_instruction_index
(
self
,
identifier
:
str
)
->
typing
.
List
[
int
]:
"""
inserts the given Instruction Block after/before the one specified Either by name or by index
Raises IndexError if the specified block is not found
Raises IndexError if multiple Blocks with the given name are found
Raises ValueError if Both a block name and index are given (or none is given)
Raises ValueError if Both a before and an after block is given (or none is given)
Args:
new_block (InstructionBlock): the block to insert
after_block_name (str): The name of the InstructionBlock to receive
after_idx (int): index of the InstructionBlock to retrieve
TODO: documentation
"""
return
[
idx
for
inst
,
idx
in
enumerate
(
self
.
_instructions
)
if
inst
.
get_identifier
()
==
identifier
]
def
insert_instruction
(
self
,
new_instruction
:
Instruction
,
after_instruction
:
str
|
int
=
None
,
before_instruction
:
str
|
int
=
None
):
"""
TODO: documentation
"""
# assert only one param is not None
parameters
=
[
after_
block_name
,
after_idx
,
before_block_name
,
before_idx
]
if
parameters
.
count
(
None
)
!=
3
:
parameters
=
[
after_
instruction
,
before_instruction
]
if
parameters
.
count
(
None
)
!=
1
:
raise
ValueError
(
"
Only one parameter is allowed to be specified
"
)
if
after_block_name
is
not
None
:
to_return
=
[
b
for
b
in
self
.
_blocks
if
b
.
name
==
after_block_name
]
if
len
(
to_return
)
==
0
:
raise
IndexError
(
"
Block Not Found
"
)
if
len
(
to_return
)
>
1
:
raise
IndexError
(
"
Multiple Blocks Found
"
)
self
.
_blocks
.
insert
(
self
.
_blocks
.
index
(
to_return
[
0
])
+
1
,
new_block
)
return
if
before_block_name
is
not
None
:
to_return
=
[
b
for
b
in
self
.
_blocks
if
b
.
name
==
before_block_name
]
if
len
(
to_return
)
==
0
:
raise
IndexError
(
"
Block Not Found
"
)
if
len
(
to_return
)
>
1
:
raise
IndexError
(
"
Multiple Blocks Found
"
)
self
.
_blocks
.
insert
(
self
.
_blocks
.
index
(
to_return
[
0
]),
new_block
)
return
if
after_idx
is
not
None
:
self
.
_blocks
.
insert
(
after_idx
+
1
,
new_block
)
return
if
before_idx
is
not
None
:
self
.
_blocks
.
insert
(
before_idx
,
new_block
)
return
idx_to_use
=
0
if
after_instruction
is
not
None
:
if
isinstance
(
after_instruction
,
int
):
idx_to_use
=
1
+
after_instruction
else
:
assert
isinstance
(
after_instruction
,
str
)
inst_idx_list
=
self
.
__get_instruction_index
(
after_instruction
)
if
len
(
inst_idx_list
)
!=
1
:
raise
IndexError
(
"
Did not find place to insert
"
)
idx_to_use
=
1
+
inst_idx_list
[
0
]
if
before_instruction
is
not
None
:
if
isinstance
(
before_instruction
,
int
):
idx_to_use
=
before_instruction
else
:
assert
isinstance
(
before_instruction
,
str
)
inst_idx_list
=
self
.
__get_instruction_index
(
before_instruction
)
if
len
(
inst_idx_list
)
!=
1
:
raise
IndexError
(
"
Did not find place to insert
"
)
idx_to_use
=
inst_idx_list
[
0
]
raise
ValueError
(
"
Neither Both block name nor index is given
"
)
self
.
_instructions
.
insert
(
idx_to_use
,
new_instruction
)
def
remove_
block
(
self
,
block_name
:
str
=
None
,
idx
:
int
=
None
):
def
remove_
instruction
(
self
,
identifier
:
str
=
None
,
idx
:
int
|
typing
.
List
[
int
]
=
None
):
"""
Removes the given Instruction Block Either by name or by index
Raises IndexError if the specified block is not found
Raises IndexError if multiple Blocks with the given name are found
Raises ValueError if Both a block name and index are given (or none is given)
Args:
block_name (str): The name of the InstructionBlock to receive
idx (int): index of the InstructionBlock to retrieve
TODO: documentation
"""
if
block_name
is
not
None
:
if
idx
is
not
None
:
raise
ValueError
(
"
Both block name and index are given
"
)
to_return
=
[
b
for
b
in
self
.
_blocks
if
b
.
name
==
block_name
]
if
len
(
to_return
)
==
0
:
raise
IndexError
(
"
Block Not Found
"
)
if
len
(
to_return
)
>
1
:
raise
IndexError
(
"
Multiple Blocks Found
"
)
self
.
_blocks
.
remove
(
to_return
[
0
])
# assert only one param is not None
parameters
=
[
identifier
,
idx
]
if
parameters
.
count
(
None
)
!=
1
:
raise
ValueError
(
"
Only one parameter is allowed to be specified
"
)
idxs_to_remove
=
[]
if
idx
is
not
None
:
if
block_name
is
not
None
:
raise
ValueError
(
"
Both block name and index are given
"
)
del
self
.
_blocks
[
idx
]
if
isinstance
(
idx
,
int
):
idxs_to_remove
=
[
idx
]
else
:
idxs_to_remove
=
idx
if
identifier
is
not
None
:
idxs_to_remove
=
self
.
__get_instruction_index
(
identifier
)
raise
ValueError
(
"
Neither Both block name nor index is given
"
)
if
len
(
idxs_to_remove
)
==
0
:
# TODO
# may also be a silen No-Op?
raise
ValueError
(
"
Nothing to remove
"
)
def
replace_block
(
self
,
new_block
:
InstructionBlock
,
block_name
:
str
=
None
,
idx
:
int
=
None
):
self
.
_instructions
=
[
elem
for
idx
,
elem
in
enumerate
(
self
.
_instructions
)
if
idx
not
in
idxs_to_remove
]
def
replace_instruction
(
self
,
new_instruction
=
Instruction
,
identifier
:
str
=
None
,
idx
:
int
|
typing
.
List
[
int
]
=
None
):
"""
Removes the given Instruction Block Either by name or by index
Raises IndexError if the specified block is not found
Raises IndexError if multiple Blocks with the given name are found
Raises ValueError if Both a block name and index are given (or none is given)
Args:
new_block (InstructionBlock): The new Block to replace the old one (does not need to have the same name)
block_name (str): The name of the InstructionBlock to receive
idx (int): index of the InstructionBlock to retrieve
TODO: documentation
"""
assert
isinstance
(
new_block
,
InstructionBlock
)
if
block_name
is
not
None
:
if
idx
is
not
None
:
raise
ValueError
(
"
Both block name and index are given
"
)
to_return
=
[
b
for
b
in
self
.
_blocks
if
b
.
name
==
block_name
]
if
len
(
to_return
)
==
0
:
raise
IndexError
(
"
Block Not Found
"
)
if
len
(
to_return
)
>
1
:
raise
IndexError
(
"
Multiple Blocks Found
"
)
self
.
_blocks
[
self
.
_blocks
.
index
(
to_return
[
0
])]
=
new_block
# assert only one param is not None
parameters
=
[
identifier
,
idx
]
new_instruction_list
=
[]
if
isinstance
(
new_instruction
,
Instruction
):
new_instruction_list
=
[
new_instruction
]
else
:
new_instruction_list
=
new_instruction
idxs_to_replace
=
[]
if
idx
is
not
None
:
if
block_name
is
not
None
:
raise
ValueError
(
"
Both block name and index are given
"
)
self
.
_blocks
[
idx
]
=
new_block
if
isinstance
(
idx
,
int
):
idxs_to_replace
=
[
idx
]
else
:
idxs_to_replace
=
idx
if
identifier
is
not
None
:
idxs_to_replace
=
self
.
__get_instruction_index
(
identifier
)
raise
ValueError
(
"
Neither Both block name nor index is given
"
)
if
len
(
idxs_to_replace
)
==
len
(
new_instruction_list
):
raise
ValueError
(
"
Number of instructions to Replace does not match number of given instructions
"
)
for
(
index
,
replacement
)
in
zip
(
idxs_to_replace
,
new_instruction_list
):
self
.
_instructions
[
index
]
=
replacement
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment