Skip to content

Commit 0a69bae

Browse files
OutlyingWestOutlyingWest
andauthored
Add optional Vampir auto-launch integration (#48)
* vampir launch command added * vampir disabling command added * vampir launch control commands documented; logging chapter moved to Usage * tests fixed * ignore scorep-* results * VAMPIR_NOT_FOUND message at %%enable_vampir_launch_on_scorep_instrumented execution * %env unable to unwrap vars like '$PATH' -> not found PATH message fixed * os unused deleted --------- Co-authored-by: OutlyingWest <alexeybuv7@amail.com>
1 parent 53b9801 commit 0a69bae

6 files changed

Lines changed: 112 additions & 23 deletions

File tree

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,15 @@ __pycache__/
44
build
55
logs_scorep_jupyter/
66
**/*.egg-info
7+
8+
# PyCharm
9+
.idea/
10+
.ipynb_checkpoints/
11+
12+
# Jupyter Notebook
13+
.ipynb_checkpoints
14+
15+
# Ignore all result directories inside examples/ at any depth
16+
examples/**/scorep-*/
17+
18+

README.md

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,14 @@ For binding to Score-P, the kernel uses the [Score-P Python bindings](https://gi
2929
- [Usage](#usage)
3030
- [Score-P Instrumentation](#score-p-instrumentation)
3131
- [Configuring Score-P in Jupyter](#configuring-score-p-in-jupyter)
32+
- [Vampir Launch Control](#vampir-launch-control)
3233
- [Multi-Cell Mode](#multi-cell-mode)
3334
- [Write Mode](#write-mode)
35+
- [Logging Configuration](#logging-configuration)
3436
- [Presentation of Performance Data](#presentation-of-performance-data)
3537
- [Limitations](#limitations)
3638
- [Serialization Type Support](#serialization-type-support)
3739
- [Overhead](#overhead)
38-
- [Logging Configuration](#logging-configuration)
3940
- [Future Work](#future-work)
4041
- [Citing](#citing)
4142
- [Contact](#contact)
@@ -131,7 +132,22 @@ Executes a cell with Score-P, i.e. it calls `python -m scorep <cell code>`
131132

132133
![](doc/instrumentation.gif)
133134

135+
### Vampir Launch Control
136+
137+
To automatically launch **Vampir** after a cell with Score-P instrumentation, use:
138+
139+
```
140+
%%enable_vampir_launch_on_scorep_instrumented
141+
```
134142

143+
This will cause the kernel to open `traces.otf2` in Vampir (if found) after the next instrumented cell.
144+
To disable this behavior again:
145+
146+
```
147+
%%disable_vampir_launch
148+
```
149+
150+
By default, Vampir launching is disabled. You must enable it explicitly when needed.
135151

136152
## Multi-Cell Mode
137153
You can also treat multiple cells as one single cell by using the multi cell mode. Therefore you can mark the cells in the order you wish to execute them.
@@ -186,6 +202,23 @@ Stops the marking process and writes the marked cells in a Python script. Additi
186202

187203
![](doc/writemode.gif)
188204

205+
## Logging Configuration
206+
To adjust logging and obtain more detailed output about the behavior of the scorep_jupyter kernel, refer to the `src/logging_config.py` file.
207+
This file contains configuration options for controlling the verbosity, format, and destination of log messages. You can customize it to suit your debugging needs.
208+
209+
Log files are stored in the following directory:
210+
```
211+
scorep_jupyter_kernel_python/
212+
├── logs_scorep_jupyter/
213+
│ ├── debug.log
214+
│ ├── info.log
215+
└── └── error.log
216+
```
217+
In some cases, you may want to suppress tqdm messages that are saved to error.log (since tqdm outputs to stderr). This can be done using the following environment variable:
218+
```
219+
%env TQDM_DISABLE=1
220+
```
221+
189222

190223
# Presentation of Performance Data
191224

@@ -205,23 +238,6 @@ Similar yields for cloudpickle. Use the `%%marshalling_settings` magic command t
205238

206239
When dealing with big data structures, there might be a big runtime overhead at the beginning and the end of a Score-P cell. This is due to additional data saving and loading processes for persistency in the background. However this does not affect the actual user code and the Score-P measurements.
207240

208-
## Logging Configuration
209-
To adjust logging and obtain more detailed output about the behavior of the scorep_jupyter kernel, refer to the `src/logging_config.py` file.
210-
This file contains configuration options for controlling the verbosity, format, and destination of log messages. You can customize it to suit your debugging needs.
211-
212-
Log files are stored in the following directory:
213-
```
214-
scorep_jupyter_kernel_python/
215-
├── logs_scorep_jupyter/
216-
│ ├── debug.log
217-
│ ├── info.log
218-
└── └── error.log
219-
```
220-
In some cases, you may want to suppress tqdm messages that are saved to error.log (since tqdm outputs to stderr). This can be done using the following environment variable:
221-
```
222-
%env TQDM_DISABLE=1
223-
```
224-
225241
# Future Work
226242

227243
The kernel is still under development.

src/scorep_jupyter/kernel.py

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def __init__(self, **kwargs):
100100
importlib.import_module("scorep")
101101
except ModuleNotFoundError:
102102
self.scorep_python_available_ = False
103-
103+
self.launch_vampir_requested = False
104104
logging.config.dictConfig(LOGGING)
105105
self.log = logging.getLogger("kernel")
106106

@@ -634,8 +634,12 @@ async def scorep_execute(
634634
f"Instrumentation results can be found in "
635635
f"{os.getcwd()}/{scorep_folder}"
636636
)
637-
638637
self.pershelper.postprocess()
638+
639+
# Optional Vampir launch
640+
if self.launch_vampir_requested and scorep_folder:
641+
self.try_launch_vampir(scorep_folder)
642+
639643
return self.standard_reply()
640644

641645
def start_reading_scorep_process_streams(
@@ -786,6 +790,38 @@ def handle_captured_output(self, output: List[str], stream: str):
786790
else:
787791
self.log.error(f"Undefined stream type: {stream}")
788792

793+
def try_launch_vampir(self, scorep_folder: str):
794+
"""
795+
Attempts to find traces.otf2 and launch Vampir on it.
796+
Errors are logged using log_error().
797+
"""
798+
trace_path = None
799+
for root, dirs, files in os.walk(scorep_folder):
800+
if "traces.otf2" in files:
801+
trace_path = os.path.join(root, "traces.otf2")
802+
break
803+
804+
if not trace_path or not os.path.isfile(trace_path):
805+
self.log_error(
806+
KernelErrorCode.INSTRUMENTATION_PATH_UNKNOWN,
807+
scorep_folder=scorep_folder,
808+
)
809+
return
810+
811+
if shutil.which("vampir") is None:
812+
self.log_error(KernelErrorCode.VAMPIR_NOT_FOUND)
813+
return
814+
815+
try:
816+
subprocess.run(["pkill", "-f", "vampir"], check=False)
817+
self.cell_output(f"\nLaunching Vampir: {trace_path}")
818+
subprocess.Popen(["vampir", trace_path])
819+
except Exception as e:
820+
self.log_error(
821+
KernelErrorCode.VAMPIR_LAUNCH_FAILED,
822+
exception=str(e),
823+
)
824+
789825
async def do_execute(
790826
self,
791827
code,
@@ -861,6 +897,18 @@ async def do_execute(
861897
return self.scorep_not_available() or self.abort_writefile()
862898
elif code.startswith("%%end_writefile"):
863899
return self.scorep_not_available() or self.end_writefile()
900+
901+
elif code.startswith("%%enable_vampir_launch_on_scorep_instrumented"):
902+
self.launch_vampir_requested = True
903+
if shutil.which("vampir") is None:
904+
self.log_error(KernelErrorCode.VAMPIR_NOT_FOUND)
905+
else:
906+
self.cell_output("Vampir will be launched after next instrumented execution.")
907+
return self.standard_reply()
908+
elif code.startswith("%%disable_vampir_launch"):
909+
self.launch_vampir_requested = False
910+
self.cell_output("Vampir launching disabled.")
911+
return self.standard_reply()
864912
elif code.startswith("%%execute_with_scorep"):
865913
scorep_missing = self.scorep_not_available()
866914
if scorep_missing is None:

src/scorep_jupyter/kernel_messages.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import os
21
from enum import Enum, auto
32

43
from .logging_config import LOGGING
@@ -12,6 +11,8 @@ class KernelErrorCode(Enum):
1211
SCOREP_SUBPROCESS_FAIL = auto()
1312
SCOREP_NOT_AVAILABLE = auto()
1413
SCOREP_PYTHON_NOT_AVAILABLE = auto()
14+
VAMPIR_NOT_FOUND = auto()
15+
VAMPIR_LAUNCH_FAILED = auto()
1516

1617

1718
KERNEL_ERROR_MESSAGES = {
@@ -38,6 +39,18 @@ class KernelErrorCode(Enum):
3839
"[mode: {mode}] Subprocess terminated unexpectedly. "
3940
"Persistence not recorded (marshaller: {marshaller})."
4041
),
42+
KernelErrorCode.INSTRUMENTATION_PATH_UNKNOWN: (
43+
"Instrumentation output directory not found or missing traces.otf2 "
44+
"(looked in: {scorep_folder})"
45+
),
46+
KernelErrorCode.VAMPIR_NOT_FOUND: (
47+
'Vampir binary not found in PATH. Add it to PATH to enable automatic launch'
48+
' (e.g. in ~/.bashrc: export PATH="/path/to/vampir/bin:$PATH"'
49+
),
50+
51+
KernelErrorCode.VAMPIR_LAUNCH_FAILED: (
52+
"Failed to launch Vampir: {exception}"
53+
),
4154
}
4255

4356

src/scorep_jupyter/logging_config.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66

77
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
8-
print(f"{Path(__file__).as_uri()=}")
9-
print(f"{PROJECT_ROOT=}")
108
LOGGING_DIR = PROJECT_ROOT / "logs_scorep_jupyter"
119
os.makedirs(LOGGING_DIR, exist_ok=True)
1210

tests/test_kernel.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ def test_error_templates_are_formatable(self):
186186
"detail": "dummy_detail",
187187
"step": "dummy_step",
188188
"optional_hint": "dummy_optional_hint",
189+
"scorep_folder": "/fake/path/to/scorep-dir",
190+
"exception": "dummy_exception",
189191
}
190192

191193
for code, template in KERNEL_ERROR_MESSAGES.items():

0 commit comments

Comments
 (0)