-
Notifications
You must be signed in to change notification settings - Fork 189
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Docs: add section on basic performance benchmark
The section provides a basic script to benchmark the performance of an AiiDA installation by launching a number of `ArithmeticAddCalculation` jobs. The script by default automatically sets up the required `Code` and localhost `Computer`. All created nodes are automatically deleted from the database at the end. The documentation gives instructions on how to run the script and provides example output of a run on a typical work station including completion times for runs with variable number of daemon workers. This should give users an idea of the performance of their installation.
- Loading branch information
Showing
2 changed files
with
174 additions
and
0 deletions.
There are no files selected for viewing
127 changes: 127 additions & 0 deletions
127
docs/source/howto/include/scripts/performance_benchmark_base.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
"""Basic script to benchmark the performance of an AiiDA installation.""" | ||
import click | ||
|
||
from aiida.cmdline.params import options | ||
from aiida.cmdline.utils import decorators, echo | ||
|
||
|
||
@click.command() | ||
@options.CODE(required=False, help='A code that can run the ``ArithmeticAddCalculation``, for example bash.') | ||
@click.option('-n', 'number', type=int, default=10, show_default=True, help='The number of processes to submit.') | ||
@decorators.with_dbenv() | ||
def main(code, number): | ||
"""Submit a number of ``ArithmeticAddCalculation`` to the daemon and record time to completion. | ||
This command requires the daemon to be running. | ||
The script will submit a configurable number of ``ArithmeticAddCalculation`` jobs. By default, the jobs are executed | ||
using the ``bash`` executable of the system. If this executable cannot be found the script will exit. The jobs will | ||
be run on the localhost, which is automatically created and configured. At the end of the script, the created nodes | ||
will be deleted, as well as the code and computer, if they were automatically setup. | ||
""" | ||
import shutil | ||
import time | ||
import uuid | ||
import tempfile | ||
|
||
from aiida import orm | ||
from aiida.common import exceptions | ||
from aiida.engine import submit | ||
from aiida.engine.daemon.client import get_daemon_client | ||
from aiida.plugins import CalculationFactory | ||
from aiida.tools.graph.deletions import delete_nodes | ||
|
||
client = get_daemon_client() | ||
|
||
if not client.is_daemon_running: | ||
echo.echo_critical('The daemon is not running.') | ||
|
||
computer_created = False | ||
code_created = False | ||
|
||
if not code: | ||
label = f'benchmark-{uuid.uuid4().hex[:8]}' | ||
computer = orm.Computer( | ||
label=label, | ||
hostname='localhost', | ||
transport_type='local', | ||
scheduler_type='direct', | ||
workdir=tempfile.gettempdir(), | ||
).store() | ||
computer.configure(safe_interval=0.0) | ||
echo.echo_success(f'Created and configured temporary `Computer` {label} for localhost.') | ||
computer_created = True | ||
|
||
executable = shutil.which('bash') | ||
|
||
if executable is None: | ||
echo.echo_critical('Could not determine the absolute path for the `bash` executable.') | ||
|
||
code = orm.Code(label='bash', remote_computer_exec=(computer, executable)).store() | ||
echo.echo_success(f'Created temporary `Code` {code.label} for localhost.') | ||
code_created = True | ||
|
||
cls = CalculationFactory('arithmetic.add') | ||
builder = cls.get_builder() | ||
builder.code = code | ||
builder.x = orm.Int(1) | ||
builder.y = orm.Int(1) | ||
|
||
time_start = time.time() | ||
nodes = [] | ||
|
||
with click.progressbar(range(number), label=f'Submitting {number} calculations.') as bar: | ||
for iteration in bar: | ||
node = submit(builder) | ||
nodes.append(node) | ||
|
||
time_end = time.time() | ||
echo.echo(f'Submission completed in {(time_end - time_start):.2f} seconds.') | ||
|
||
completed = 0 | ||
|
||
with click.progressbar(length=number, label='Waiting for calculations to complete') as bar: | ||
while True: | ||
time.sleep(0.2) | ||
|
||
terminated = [node.is_terminated for node in nodes] | ||
newly_completed = terminated.count(True) - completed | ||
completed = terminated.count(True) | ||
|
||
bar.update(newly_completed) | ||
|
||
if all(terminated): | ||
break | ||
|
||
if any(node.is_excepted or node.is_killed for node in nodes): | ||
echo.echo_warning('At least one submitted calculation excepted or was killed.') | ||
else: | ||
echo.echo_success('All calculations finished successfully.') | ||
|
||
time_end = time.time() | ||
echo.echo(f'Elapsed time: {(time_end - time_start):.2f} seconds.') | ||
|
||
echo.echo('Cleaning up...') | ||
delete_nodes([node.pk for node in nodes], dry_run=False) | ||
echo.echo_success('Deleted all calculations.') | ||
|
||
if code_created: | ||
code_label = code.full_label | ||
orm.Node.objects.delete(code.pk) | ||
echo.echo_success(f'Deleted the created code {code_label}.') | ||
|
||
if computer_created: | ||
computer_label = computer.label | ||
user = orm.User.objects.get_default() | ||
auth_info = computer.get_authinfo(user) | ||
orm.AuthInfo.objects.delete(auth_info.pk) | ||
orm.Computer.objects.delete(computer.pk) | ||
echo.echo_success(f'Deleted the created computer {computer_label}.') | ||
|
||
echo.echo(f'Performance {(number / (time_end - time_start)):.2f} processes / s') | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters