Skip to content

Commit 5800a80

Browse files
authored
Add configurable iteration modes to parsl-perf (#3985)
These are described in the documentation added in this PR. The default mode is the previous behaviour (estimate mode). This PR adds a new mode, exponential, which is useful for looking at scaling behaviour over batch sizes and for more consistent batch sizes across runs. # Changed Behaviour new options, old behaviour should be preserved ## Type of change - New feature
1 parent 2568061 commit 5800a80

File tree

2 files changed

+41
-10
lines changed

2 files changed

+41
-10
lines changed

docs/userguide/advanced/parsl_perf.rst

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ Measuring performance with parsl-perf
66
``parsl-perf`` is tool for making basic performance measurements of Parsl
77
configurations.
88

9-
It runs increasingly large numbers of no-op apps until a batch takes
10-
(by default) 120 seconds, giving a measurement of tasks per second.
9+
It runs repeated batches of no-op apps, giving a measurement of tasks per
10+
second. By default, ``parsl-perf`` will attempt to estimate a batch size
11+
that will take 2 minutes to execute.
1112

1213
This can give a basic measurement of some of the overheads in task
1314
execution.
@@ -23,6 +24,20 @@ argument.
2324
To change the target runtime from the default of 120 seconds, add a
2425
``--time`` parameter.
2526

27+
To change the iteration algorithm used to pick the next batch size and to
28+
decide when to stop, use the ``--iterate`` parameter:
29+
30+
* ``--iterate=estimate`` (the default) will run a small batch, then
31+
repeatedly re-estimate a new batch size until it finds one that takes at least
32+
75% of the target run time. This will rapidly find a batch size of around
33+
the target size.
34+
35+
* ``--iterate=exponential`` will start with a small batch, then double the size
36+
in each subsequent batch until reaching the target run time. This is useful
37+
for understanding how a configuration scales down as batch sizes increase,
38+
which is sometimes sub-linear, and to get more consistent batch sizes across
39+
runs of ``parsl-perf``.
40+
2641
For example:
2742

2843
.. code-block:: bash

parsl/benchmark/perf.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import parsl
88
from parsl.dataflow.dflow import DataFlowKernel
9+
from parsl.errors import InternalConsistencyError
910

1011
min_iterations = 2
1112

@@ -40,19 +41,18 @@ def app(extra_payload: Any, parsl_resource_specification: Dict = {}) -> int:
4041
return 7
4142

4243

43-
def performance(*, resources: dict, target_t: float, args_extra_size: int) -> None:
44+
def performance(*, resources: dict, target_t: float, args_extra_size: int, iterate_mode: str) -> None:
4445
n = 10
4546

4647
delta_t: float
47-
delta_t = 0
48-
49-
threshold_t = int(0.75 * target_t)
5048

5149
iteration = 1
5250

5351
args_extra_payload = "x" * args_extra_size
5452

55-
while delta_t < threshold_t or iteration <= min_iterations:
53+
iterate = True
54+
55+
while iterate:
5656
print(f"==== Iteration {iteration} ====")
5757
print(f"Will run {n} tasks to target {target_t} seconds runtime")
5858
start_t = time.time()
@@ -78,10 +78,20 @@ def performance(*, resources: dict, target_t: float, args_extra_size: int) -> No
7878
print(f"Runtime: actual {delta_t:.3f}s vs target {target_t}s")
7979
print(f"Tasks per second: {rate:.3f}")
8080

81-
n = max(1, int(target_t * rate))
82-
8381
iteration += 1
8482

83+
# decide upon next iteration
84+
85+
match iterate_mode:
86+
case "estimate":
87+
n = max(1, int(target_t * rate))
88+
iterate = delta_t < (0.75 * target_t) or iteration <= min_iterations
89+
case "exponential":
90+
n = int(n * 2)
91+
iterate = delta_t < target_t or iteration <= min_iterations
92+
case _:
93+
raise InternalConsistencyError(f"Bad iterate mode {iterate_mode} - should have been validated at arg parse time")
94+
8595

8696
def cli_run() -> None:
8797
parser = argparse.ArgumentParser(
@@ -96,6 +106,12 @@ def cli_run() -> None:
96106
parser.add_argument("--time", metavar="SECONDS", help="target number of seconds for an iteration", default=120, type=float)
97107
parser.add_argument("--argsize", metavar="BYTES", help="extra bytes to add into app invocation arguments", default=0, type=int)
98108
parser.add_argument("--version", action="version", version=f"parsl-perf from Parsl {parsl.__version__}")
109+
parser.add_argument("--iterate",
110+
metavar="MODE",
111+
help="Iteration mode: estimate, exponential",
112+
type=str,
113+
default="estimate",
114+
choices=("estimate", "exponential"))
99115

100116
args = parser.parse_args()
101117

@@ -105,7 +121,7 @@ def cli_run() -> None:
105121
resources = {}
106122

107123
with load_dfk_from_config(args.config):
108-
performance(resources=resources, target_t=args.time, args_extra_size=args.argsize)
124+
performance(resources=resources, target_t=args.time, args_extra_size=args.argsize, iterate_mode=args.iterate)
109125
print("Tests complete - leaving DFK block")
110126
print("The end")
111127

0 commit comments

Comments
 (0)