Skip to content

Commit 5099c3b

Browse files
authored
Merge pull request #38 from bcdev/mb-profiling
add runtime profiling as option to the command line client or configuration
2 parents 5a6134d + 5323ed0 commit 5099c3b

File tree

4 files changed

+63
-5
lines changed

4 files changed

+63
-5
lines changed

docs/cli.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Options:
2222
'target_dir' configuration field.
2323
--dry-run Run the tool without creating, changing, or deleting
2424
any files.
25+
--profiling TEXT Path for profiling output. Switches on profiling.
2526
--help-config json|md Show configuration help and exit.
2627
--help Show this message and exit.
2728
```

tests/test_cli.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Copyright © 2024 Norman Fomferra
22
# Permissions are hereby granted under the terms of the MIT License:
33
# https://opensource.org/licenses/MIT.
4-
4+
import os
55
import unittest
66
from click.testing import CliRunner
77

@@ -104,3 +104,27 @@ def test_some_slices_and_no_target(self):
104104
"Error: Missing 'target_dir' in configuration\n", result.output
105105
)
106106
self.assertFalse(FileObj("memory://target.zarr").exists())
107+
108+
def test_profiling(self):
109+
make_test_dataset(uri="memory://slice-1.zarr")
110+
make_test_dataset(uri="memory://slice-2.zarr")
111+
make_test_dataset(uri="memory://slice-3.zarr")
112+
113+
runner = CliRunner()
114+
# noinspection PyTypeChecker
115+
result = runner.invoke(
116+
zappend,
117+
[
118+
"--profiling",
119+
"prof.out",
120+
"--target",
121+
"memory://target.zarr",
122+
"memory://slice-1.zarr",
123+
"memory://slice-2.zarr",
124+
"memory://slice-3.zarr",
125+
],
126+
)
127+
self.assertEqual("", result.output)
128+
self.assertEqual(0, result.exit_code)
129+
self.assertTrue(FileObj("prof.out").exists())
130+
os.unlink("prof.out")

zappend/api.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# Copyright © 2024 Norman Fomferra
22
# Permissions are hereby granted under the terms of the MIT License:
33
# https://opensource.org/licenses/MIT.
4-
5-
from typing import Iterable, Any
4+
from cProfile import Profile
5+
from io import StringIO
6+
from pstats import Stats
7+
from typing import Iterable, Any, Literal
68

79
from .config import ConfigItem
810
from .config import ConfigLike
@@ -15,6 +17,7 @@
1517
from .slice import SliceSource
1618
from .slice import to_slice_factories
1719
from .slice import to_slice_factory
20+
from .log import logger
1821

1922

2023
__all__ = [
@@ -31,9 +34,14 @@
3134
"to_slice_factory",
3235
]
3336

37+
_TOTAL_TIME: Literal["tottime"] = "tottime"
38+
3439

3540
def zappend(
36-
slices: Iterable[SliceObj | SliceFactory], config: ConfigLike = None, **kwargs: Any
41+
slices: Iterable[SliceObj | SliceFactory],
42+
config: ConfigLike = None,
43+
profiling=None,
44+
**kwargs: Any,
3745
):
3846
"""
3947
Robustly create or update a Zarr dataset from dataset slices.
@@ -57,8 +65,25 @@ def zappend(
5765
May be a file path or URI, a ``dict``, ``None``, or a sequence of
5866
the aforementioned. If a sequence is used, subsequent configurations
5967
are incremental to the previous ones.
68+
profiling: Path for profiling output.
69+
Switches on profiling
6070
kwargs: Additional configuration parameters.
6171
Can be used to pass or override configuration values in *config*.
6272
"""
6373
processor = Processor(config, **kwargs)
74+
75+
if profiling:
76+
profile = Profile()
77+
logger.info(f"profiling ...")
78+
profile.enable()
79+
6480
processor.process_slices(slices)
81+
82+
if profiling:
83+
profile.disable()
84+
results = StringIO()
85+
stats = Stats(profile, stream=results)
86+
stats.sort_stats(_TOTAL_TIME).print_stats()
87+
with open(profiling, "w") as f:
88+
f.write(results.getvalue())
89+
logger.info(f"profiling output written to {profiling}")

zappend/cli.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
is_flag=True,
2929
help="Run the tool without creating, changing," " or deleting any files.",
3030
)
31+
@click.option("--profiling", help="Path for profiling output. Switches on profiling.")
3132
@click.option(
3233
"--help-config",
3334
metavar="json|md",
@@ -39,6 +40,7 @@ def zappend(
3940
config: tuple[str, ...],
4041
target: str | None,
4142
dry_run: bool,
43+
profiling: str,
4244
help_config: str | None,
4345
):
4446
"""Create or update a Zarr datacube TARGET from slice datasets SLICES.
@@ -61,7 +63,13 @@ def zappend(
6163

6264
# noinspection PyBroadException
6365
try:
64-
zappend(slices, config=config, target_dir=target, dry_run=dry_run)
66+
zappend(
67+
slices,
68+
config=config,
69+
target_dir=target,
70+
dry_run=dry_run,
71+
profiling=profiling,
72+
)
6573
except BaseException as e:
6674
raise click.ClickException(f"{e}") from e
6775

0 commit comments

Comments
 (0)