Skip to content
This repository was archived by the owner on Jan 28, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ install:
- sudo rm -rf /dev/shm && sudo ln -s /run/shm /dev/shm
# Work around https://github.com/travis-ci/travis-ci/issues/5485
- travis_retry pip install setuptools==29.0.1
- travis_retry pip install virtualenv==15.1
- pip install tox-travis coveralls

script: tox
Expand Down
52 changes: 51 additions & 1 deletion docs/campaign.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ tags
~~~~
Specify groups of nodes.

A tag can be defined with either an exhaustive list of a regular expression.
A tag can be defined with either an exhaustive list or a regular expression.

For instance, given the set of nodes defined above, we can define the
*cpu* and *gpu* tags as follow:
Expand All @@ -60,6 +60,56 @@ Both methods are being used:
* **nodes** expects an exaustive list of nodes.
* **match** expects a valid regular expression

ssh_config_file
~~~~~~~~~~~~~~~

Optional path to a custom SSH configuration file (see man ssh_config(5)).
This can be used to provide HPCBench access to cluster nodes without passphrase
by using a dedicated SSH key.

For instance::

Host *.my-cluster.com
User hpc
IdentityFile ~/.ssh/hpcbench_rsa

remote_work_dir
~~~~~~~~~~~~~~~

Working path on remote nodes. Default value is ``.hpcbench``
Relative paths are relative from home directory.

installer_template
~~~~~~~~~~~~~~~~~~

Jinja template to use to generate the shell-script installer
deployed on cluster's nodes. Default value is ``ssh-installer.sh.jinja``

installer_prelude_file
~~~~~~~~~~~~~~~~~~~~~~

Optional path to a text file that will be included at the beginning
of the generated shell-script installer.
This can be useful to prepare the working environment, for instance to make
Python 2.7, or Python 3.3+ available in ``PATH`` environment variable if this
is not the case by default.

max_concurrent_runs
~~~~~~~~~~~~~~~~~~~

Number of concurrent benchmarks executed in parallel in the cluster.
Default is 4.

pip_installer_url
~~~~~~~~~~~~~~~~~

HPCBench version to install on nodes. By default it is the current ``ben-et``
version managing the cluster. This is an argument given to ``pip`` installer, here are a some examples:

* ``hpcbench==2.0`` to force a version available PyPi
* ``git+http://github.com/tristan0x/hpcbench@master#egg=hpcbench`` to install the bleeding edge version.
* ``git+http://github.com/me/hpcbench@feat/awesome-feature#egg=hpcbench`` to deploy a fork's branch.

Benchmarks configuration reference
----------------------------------

Expand Down
5 changes: 3 additions & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,13 @@ CLI

**HPCBench** provides a set of command line utilities:

* ben-sh: Execute a tests campaign
* ben-sh: Execute a tests campaign on your workstation
* ben-umb: Extract metrics of an existing campaign
* ben-plop: Draw figures of an existing campaign
* ben-elk: Push campaign data to Elasticsearch
* ben-et: Execute a tests campaign on a cluster

**ben-sh** expects a YAML file describing the campaign to execute.
**ben-sh** and **ben-et** expect a YAML file describing the campaign to execute.
Structure of this YAML file is detailled in the :doc:`campaign file reference <campaign>`.

API
Expand Down
2 changes: 1 addition & 1 deletion hpcbench/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""hpcbench package to specify and execute benchmarks
"""
__version__ = '0.1a'
__version__ = '0.1b.dev'
19 changes: 8 additions & 11 deletions hpcbench/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def metrics(self):
)

"""
raise NotImplementedError
raise NotImplementedError # pragma: no cover

@abstractmethod
def extract(self, outdir, metas):
Expand All @@ -57,7 +57,7 @@ def extract(self, outdir, metas):
the ``metrics`` member funtion.

"""
raise NotImplementedError
raise NotImplementedError # pragma: no cover

@classmethod
def stdout(cls, outdir):
Expand Down Expand Up @@ -92,22 +92,19 @@ def name(self):
"""Get benchmark name
:rtype: string
"""
pass
raise NotImplementedError # pragma: no cover

@abstractproperty
def description(self):
"""Get benchmark long description
:rtype: string
"""
pass
raise NotImplementedError # pragma: no cover
# ---

def __init__(self, attributes=None):
self.attributes = attributes or {}

def __str__(self):
return self.name

@abstractproperty
def execution_matrix(self):
"""Describe benchmark commands
Expand Down Expand Up @@ -155,13 +152,13 @@ def execution_matrix(self):
metas=dict(cores=cores),
)
"""
raise NotImplementedError
raise NotImplementedError # pragma: no cover

def pre_execute(self):
"""Method called before executing one of the command.
Current working directory is the execution directory.
"""
pass
raise NotImplementedError # pragma: no cover

@abstractproperty
def metrics_extractors(self):
Expand All @@ -182,7 +179,7 @@ def metrics_extractors(self):
bar=[bar_extractor(), foobar_extractor()]
)
"""
raise NotImplementedError
raise NotImplementedError # pragma: no cover

@abstractproperty
def plots(self):
Expand All @@ -206,7 +203,7 @@ def plots(self):
plotter:
callable object that will be given metrics to plot
"""
raise NotImplementedError
raise NotImplementedError # pragma: no cover

@classmethod
def get_subclass(cls, name):
Expand Down
80 changes: 55 additions & 25 deletions hpcbench/campaign.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,54 @@
"""HPCBench campaign helper functions
"""
import collections
import re
import uuid

from . toolbox.collections_ext import (
Configuration,
nameddict,
# pragma pylint: disable=no-name-in-module
from pkg_resources.extern import packaging

import hpcbench

from . toolbox.collections_ext import Configuration


def pip_installer_url(version=None):
"""Get argument to give to ``pip`` to install HPCBench.
"""
version = version or hpcbench.__version__
version = packaging.version.Version(version)
version = str(version)
if '.dev' in version:
return 'git+http://github.com/tristan0x/hpcbench@master#egg=hpcbench'
return 'hpcbench=={}'.format(version)


DEFAULT_CAMPAIGN = dict(
output_dir="hpcbench-%Y%m%d-%H:%M:%S",
network=dict(
nodes=[
'localhost',
],
tags=dict(),
ssh_config_file=None,
remote_work_dir='.hpcbench',
installer_template='ssh-installer.sh.jinja',
installer_prelude_file=None,
max_concurrent_runs=4,
pip_installer_url=pip_installer_url(),
),
tag=dict(),
benchmarks={
'*': {}
},
export=dict(
elasticsearch=dict(
host='localhost',
connection_params=dict(),
index_name='hpcbench-{date}'
)
)

)


Expand All @@ -28,16 +71,16 @@ def fill_default_campaign_values(campaign):
:return: object provided in parameter
:rtype: dictionary
"""
default_campaign = dict(
output_dir="hpcbench-%Y%m%d-%H:%M:%S"
)
for key, value in default_campaign.items():
campaign.setdefault(key, value)
campaign.setdefault('network', nameddict())
campaign['network'].setdefault('nodes', ['localhost'])
def _merger(_camp, _deft):
for key in _deft.keys():
if (key in _camp and isinstance(_camp[key], dict)
and isinstance(_deft[key], collections.Mapping)):
_merger(_camp[key], _deft[key])
elif key not in _camp:
_camp[key] = _deft[key]
_merger(campaign, DEFAULT_CAMPAIGN)
campaign.setdefault('campaign_id', str(uuid.uuid4()))
campaign.network.setdefault('tags', {})
campaign.benchmarks.setdefault('*', {})

for tag in list(campaign.network.tags):
config = campaign.network.tags[tag]
if isinstance(config, dict):
Expand All @@ -55,19 +98,6 @@ def fill_default_campaign_values(campaign):
else:
raise Exception('Unknown tag association pattern: %s',
mode)
set_export_campaign_section(campaign)
return campaign


def set_export_campaign_section(campaign):
"""Add default values for the ``export`` section
"""
campaign.setdefault('export', nameddict())
campaign.export.setdefault('elasticsearch', nameddict())
campaign.export.elasticsearch.setdefault('host', 'localhost')
campaign.export.elasticsearch.setdefault('connection_params', {})
campaign.export.elasticsearch.setdefault('index_name',
'hpcbench-{date}')
return campaign


Expand Down
29 changes: 29 additions & 0 deletions hpcbench/cli/benet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""ben-et

Usage:
ben-et [-v | -vv ] CAMPAIGN_FILE
ben-et (-h | --help)
ben-et --version

Options:
-h --help Show this screen
--version Show version
-v -vv -vvv Increase program verbosity
"""

from hpcbench.net import BeNet

from . import cli_common


def main(argv=None):
"""ben-et entry point"""
arguments = cli_common(__doc__, argv=argv)
benet = BeNet(arguments['CAMPAIGN_FILE'])
benet.run()
if argv is not None:
return benet


if __name__ == '__main__':
main()
6 changes: 3 additions & 3 deletions hpcbench/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ def __init__(self, campaign):

@abstractmethod
def child_builder(self, child):
raise NotImplementedError
raise NotImplementedError # pragma: no cover

@abstractproperty
def children(self):
"""Property to be overriden be subclass to provide child objects"""
raise NotImplementedError
raise NotImplementedError # pragma: no cover

@cached_property
def report(self):
Expand Down Expand Up @@ -191,7 +191,7 @@ def __init__(self, campaign, name):

@cached_property
def children(self):
return list(self.campaign.benchmarks[self.name])
return list(self.campaign.benchmarks.get(self.name, []))

def child_builder(self, child):
conf = self.campaign.benchmarks[self.name][child]
Expand Down
Loading