From d7f083072d80e0a07a0f26f5ccfa6a15f51b5961 Mon Sep 17 00:00:00 2001 From: Ben Clifford Date: Thu, 21 Sep 2023 10:02:55 +0100 Subject: [PATCH 1/4] Document parsl-perf (#2891) --- docs/userguide/index.rst | 1 + docs/userguide/parsl_perf.rst | 53 +++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 docs/userguide/parsl_perf.rst diff --git a/docs/userguide/index.rst b/docs/userguide/index.rst index ae7df17450..21de9eb704 100644 --- a/docs/userguide/index.rst +++ b/docs/userguide/index.rst @@ -19,4 +19,5 @@ User guide joins usage_tracking plugins + parsl_perf performance diff --git a/docs/userguide/parsl_perf.rst b/docs/userguide/parsl_perf.rst new file mode 100644 index 0000000000..2ea1adb00f --- /dev/null +++ b/docs/userguide/parsl_perf.rst @@ -0,0 +1,53 @@ +.. _label-parsl-perf: + +Measuring performance with parsl-perf +===================================== + +``parsl-perf`` is tool for making basic performance measurements of Parsl +configurations. + +It runs increasingly large numbers of no-op apps until a batch takes +(by default) 120 seconds, giving a measurement of tasks per second. + +This can give a basic measurement of some of the overheads in task +execution. + +``parsl-perf`` must be invoked with a configuration file, which is a Python +file containing a variable ``config`` which contains a `Config` object, or +a function ``fresh_config`` which returns a `Config` object. The +``fresh_config`` format is the same as used with the pytest test suite. + +To specify a ``parsl_resource_specification`` for tasks, add a ``--resources`` +argument. + +To change the target runtime from the default of 120 seconds, add a +``--time`` parameter. + +For example: + +.. code-block:: bash + + + $ python -m parsl.benchmark.perf --config parsl/tests/configs/workqueue_ex.py --resources '{"cores":1, "memory":0, "disk":0}' + ==== Iteration 1 ==== + Will run 10 tasks to target 120 seconds runtime + Submitting tasks / invoking apps + warning: using plain-text when communicating with workers. + warning: use encryption with a key and cert when creating the manager. + All 10 tasks submitted ... waiting for completion + Submission took 0.008 seconds = 1248.676 tasks/second + Runtime: actual 3.668s vs target 120s + Tasks per second: 2.726 + + [...] + + ==== Iteration 4 ==== + Will run 57640 tasks to target 120 seconds runtime + Submitting tasks / invoking apps + All 57640 tasks submitted ... waiting for completion + Submission took 34.839 seconds = 1654.487 tasks/second + Runtime: actual 364.387s vs target 120s + Tasks per second: 158.184 + Cleaning up DFK + The end + From c78926218a3bd4af45430f5ff04a0dc7beba4356 Mon Sep 17 00:00:00 2001 From: Ben Clifford Date: Thu, 21 Sep 2023 10:39:03 +0100 Subject: [PATCH 2/4] Switch empty dfk() error from ConfigurationError to NoDataFlowKernelError (#2890) This is in support of https://github.com/Parsl/parsl/issues/2873#issuecomment-1726540856 --- parsl/dataflow/dflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parsl/dataflow/dflow.py b/parsl/dataflow/dflow.py index e51d6dd39a..c42d536c70 100644 --- a/parsl/dataflow/dflow.py +++ b/parsl/dataflow/dflow.py @@ -1438,5 +1438,5 @@ def wait_for_current_tasks(cls) -> None: def dfk(cls) -> DataFlowKernel: """Return the currently-loaded DataFlowKernel.""" if cls._dfk is None: - raise ConfigurationError('Must first load config') + raise NoDataFlowKernelError('Must first load config') return cls._dfk From f8fb612b53f0d6293df7f288571a1cece5790524 Mon Sep 17 00:00:00 2001 From: Ben Clifford Date: Tue, 3 Oct 2023 07:31:24 +0100 Subject: [PATCH 3/4] Make parsl-perf iterations have at least 1 task (#2896) Prior to this PR: In some startup situations, the estimated number of tasks for the next iteration can round down to 0, and then parsl-perf can sometimes enter an infinite loop without increasing the loop size: ==== Iteration 29463 ==== Will run 0 tasks to target 20.0 seconds runtime Submitting tasks / invoking apps All 0 tasks submitted ... waiting for completion Submission took 2.1457672119140625e-06 seconds = 0.0 tasks/second Runtime: 1.049041748046875e-05s vs target 20.0 Tasks per second: 0.0 --- parsl/benchmark/perf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parsl/benchmark/perf.py b/parsl/benchmark/perf.py index 9325c24004..5740f2841d 100644 --- a/parsl/benchmark/perf.py +++ b/parsl/benchmark/perf.py @@ -62,7 +62,7 @@ def performance(*, resources: dict, target_t: float): print(f"Runtime: actual {delta_t:.3f}s vs target {target_t}s") print(f"Tasks per second: {rate:.3f}") - n = int(target_t * rate) + n = max(1, int(target_t * rate)) iteration += 1 From b32147f40ee0de76b20d9f4237aa3eaa4d3c7a88 Mon Sep 17 00:00:00 2001 From: Ben Clifford Date: Tue, 3 Oct 2023 12:05:42 +0100 Subject: [PATCH 4/4] Fix flake8 error from upcoming Python 3.12 (#2893) In Python 3.12, f-strings vs flake8 has more whitespace checking, in line with whitespace checking in other Python expressions, as part of a broader rationalisation of f-string implementation: https://docs.python.org/3.12/whatsnew/3.12.html#whatsnew312-pep701 --- parsl/benchmark/perf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parsl/benchmark/perf.py b/parsl/benchmark/perf.py index 5740f2841d..d92b9105ad 100644 --- a/parsl/benchmark/perf.py +++ b/parsl/benchmark/perf.py @@ -48,7 +48,7 @@ def performance(*, resources: dict, target_t: float): submitted_t = time.time() print(f"All {n} tasks submitted ... waiting for completion") - print(f"Submission took {submitted_t - start_t:.3f} seconds = {n/(submitted_t - start_t):.3f} tasks/second") + print(f"Submission took {submitted_t - start_t:.3f} seconds = {n / (submitted_t - start_t):.3f} tasks/second") for f in concurrent.futures.as_completed(fs): assert f.result() == 7