Skip to content

Commit b22dd66

Browse files
Merge pull request #2533 from devitocodes/advisor_refresh_II
misc: Update advisor with oneAPI 2025
2 parents e1dcb86 + fd5df3f commit b22dd66

9 files changed

Lines changed: 234 additions & 267 deletions

File tree

benchmarks/user/advisor/README.md

Lines changed: 68 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,88 @@
1-
Example runs:
1+
# Intel Advisor roofline profiling on Devito
22

3-
* `python3 run_advisor.py --name isotropic --path <path-to-devito>/examples/seismic/acoustic/acoustic_example.py`
4-
* `python3 run_advisor.py --name tti_so8 --path <path-to-devito>/examples/seismic/tti/tti_example.py --exec-args "-so 8"`
5-
* `python3 run_advisor.py --name iso_ac_so6 --path <path-to-devito>/benchmarks/user/benchmark.py --exec-args "bench -P acoustic -so 6 --tn 200 -d 100 100 100 --autotune off -x 1"`
3+
This README aims to help users derive rooflines through using Devito with [Intel Advisor](https://www.intel.com/content/www/us/en/developer/tools/oneapi/advisor.html).
4+
We recommend going through tutorial [02_advisor_roofline.ipynb](https://github.com/devitocodes/devito/blob/master/examples/performance/02_advisor_roofline.ipynb) for a more detailed step-by-step guidance.
65

7-
After the run has finished you should be able to plot a roofline with the results and export roofline data to JSON using:
8-
* `python3 roofline.py --name Roofline --project <advisor-project-name>`
6+
### Prerequisites:
7+
* Support is guaranteed only for Intel oneAPI 2025; earlier versions may not work.
8+
You may download Intel oneAPI [here](https://www.intel.com/content/www/us/en/developer/tools/oneapi/base-toolkit-download.html?packages=oneapi-toolkit&oneapi-toolkit-os=linux&oneapi-lin=apt).
99

10-
To create a read-only snapshot for use with Intel Advisor GUI, use:
11-
* `advixe-cl --snapshot --project-dir=<advisor-project-name> pack -- /<new-snapshot-name>`
10+
* Add Advisor (advixe-cl) and compilers (icx) in the path. The right env variables should be sourced along the lines of (depending on your isntallation folder):
11+
```sh
12+
source /opt/intel/oneapi/advisor/latest/env/vars.sh
13+
source /opt/intel/oneapi/compiler/latest/env/vars.sh
14+
```
1215

13-
Prerequisites:
14-
* Support guaranteed only for Intel Advisor as installed with Intel Parallel Studio v 2020 Update 2
15-
and Intel oneAPI 2021; earlier years may not work; other 2020/2021 versions, as well as later years,
16-
may or may not work.
1716
* In Linux systems you may need to enable system-wide profiling by setting:
18-
- `/proc/sys/kernel/yama/ptrace_scope` to `0`
19-
- `/proc/sys/kernel/perf_event_paranoid` to `1`
2017

21-
* `numactl` must be available on the system. If not available, install with:
22-
`sudo apt-get install numactl`
18+
```sh
19+
/proc/sys/kernel/yama/ptrace_scope to 0
20+
/proc/sys/kernel/perf_event_paranoid to 1
21+
```
22+
23+
* `numactl` must be available on the system. If not available, install using:
24+
```sh
25+
sudo apt-get install numactl
26+
```
2327
* Install `pandas` and `matplotlib`. They are not included in the core Devito installation.
28+
```sh
29+
pip install pandas matplotlib
30+
```
31+
32+
33+
### Example runs:
2434

25-
Limitations:
35+
```bash
36+
# The isotropic acoustic example
37+
python3 run_advisor.py --name isotropic --path <path-to-devito>/examples/seismic/acoustic/acoustic_example.py
38+
# The isotropic elastic example
39+
python3 run_advisor.py --name iso_elastic --path <path-to-devito>/examples/seismic/elastic/elastic_example.py --exec-args "-so 4"
40+
# The anisotropic acoustic (TTI) example
41+
python3 run_advisor.py --name tti_so8 --path <path-to-devito>/examples/seismic/tti/tti_example.py --exec-args "-so 8"
42+
```
2643

27-
* Untested with more complicated examples.
28-
* Untested on Intel KNL (we might need to ask `numactl` to bind to MCDRAM).
29-
* Running the `tripcounts` analysis takes a lot, despite starting in paused
44+
After the run has finished you should be able to save a `.json` and plot the
45+
roofline with the results:
46+
```bash
47+
python3 roofline.py --name Roofline --project <advisor-project-name>
48+
```
49+
50+
To create a read-only snapshot for use with Intel Advisor GUI, use:
51+
```bash
52+
advixe-cl --snapshot --project-dir=<advisor-project-name> pack -- /<new-snapshot-name>
53+
```
54+
### Limitations:
55+
56+
* Not tested with all possible examples that Devito can support.
57+
* Running the `tripcounts` analysis is time-consuming, despite starting in paused
3058
mode. This analysis, together with the `survey` analysis, is necessary to
3159
generate a roofline. Both are run by `run_advisor.py`.
32-
* Requires python3, untested in earlier versions of python and conda environments
33-
* Currently requires download of repository and running `pip3 install .`, the scripts
60+
* Requires Python 3.9 or later, untested in conda environments
61+
* Currently requires download of repository and running `pip install .`, the scripts
3462
are currently not included as a package with the user installation of Devito
3563

36-
TODO:
64+
### TODO:
3765

3866
* Give a name to the points in the roofline, otherwise it's challenging to
3967
relate loops (code sections) to data.
4068
* Emit a report summarizing the configuration used to run the analysis
4169
(threading, socket binding, ...).
4270

43-
Useful links:
71+
### Useful links:
72+
73+
* [ Intel® Advisor Performance Optimization Cookbook ](https://www.intel.com/content/www/us/en/docs/advisor/cookbook/2024-2/overview.html " Intel® Advisor Performance Optimization Cookbook ")
74+
75+
* [ Intel® Advisor User Guide ](https://www.intel.com/content/www/us/en/docs/advisor/cookbook/2024-2/overview.html " Intel® Advisor User Guide ")
76+
77+
* [ Roofline Resources for Intel® Advisor Users ](https://software.intel.com/content/www/us/en/develop/articles/advisor-roofline-resources.html " Roofline Resources for Intel® Advisor Users ")
78+
4479
* [ Memory-Level Roofline Analysis in Intel® Advisor ](https://software.intel.com/content/www/us/en/develop/articles/memory-level-roofline-model-with-advisor.html " Memory-Level Roofline Analysis in Intel® Advisor ")
45-
* [CPU / Memory Roofline Insights
46-
Perspective](https://software.intel.com/content/www/us/en/develop/documentation/advisor-user-guide/top/optimize-cpu-usage/cpu-roofline-perspective.html "CPU / Memory Roofline Insights
47-
Perspective")
48-
* [ Roofline Resources for Intel® Advisor Users ](https://software.intel.com/content/www/us/en/develop/articles/advisor-roofline-resources.html " Roofline Resources for Intel® Advisor Users ")
80+
81+
* [ Identify Bottlenecks Iteratively: Cache-Aware Roofline ](https://www.intel.com/content/www/us/en/docs/advisor/cookbook/2024-2/identify-bottlenecks-cache-aware-roofline.html " Identify Bottlenecks Iteratively: Cache-Aware Roofline ")
82+
83+
* [ Samuel Williams, Andrew Waterman, and David Patterson [2009]. Roofline: an insightful visual performance model for multicore architectures ](https://dl.acm.org/doi/10.1145/1498765.1498785 " Roofline: an insightful visual performance model for multicore architectures ")
84+
85+
* [ A. Ilic, F. Pratas and L. Sousa [2014]. Cache-aware Roofline model: Upgrading the loft ](https://ieeexplore.ieee.org/document/6506838 " Cache-aware Roofline model: Upgrading the loft ")
86+
87+
* [ Understanding the Roofline Model by Durganshu Mishra ](https://hackernoon.com/understanding-the-roofline-model " Understanding the Roofline Model ")
88+

benchmarks/user/advisor/roofline.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,22 @@
1818
import sys
1919
import os
2020

21-
from benchmarks.user.advisor.advisor_logging import check, err, log
21+
from advisor_logging import check, err, log
2222

2323

2424
try:
2525
import advisor
2626
except ImportError:
2727
check(False, 'Error: Intel Advisor could not be found on the system,'
2828
' make sure to source environment variables properly. Information can be'
29-
' found at https://software.intel.com/content/www/us/en/develop/'
30-
'documentation/advisor-user-guide/top/launch-the-intel-advisor/'
31-
'intel-advisor-cli/setting-and-using-intel-advisor-environment-variables.html')
29+
' found at https://www.intel.com/content/www/us/en/docs/advisor/'
30+
'user-guide/2024-2/set-up-environment-variables.html')
3231
sys.exit(1)
3332

3433

3534
matplotlib.use('Agg')
3635
# Use fancy plot colors
37-
plt.style.use('seaborn-darkgrid')
36+
plt.style.use('ggplot')
3837

3938

4039
@click.command()
@@ -65,21 +64,25 @@
6564
def roofline(name, project, scale, precision, mode, th):
6665
pd.options.display.max_rows = 20
6766

68-
log('Opening project...')
67+
log(f'Opening project {project}...')
6968
project = advisor.open_project(str(project))
7069

7170
if not project:
72-
err('Could not open project %s.' % project)
71+
err(f'Could not open project {project}.')
7372
log('Loading data...')
7473

7574
data = project.load(advisor.SURVEY)
7675
rows = [{col: row[col] for col in row} for row in data.bottomup]
7776
roofs = data.get_roofs()
7877

78+
# Following deprecation solution from here:
79+
# https://github.com/pandas-dev/pandas/issues/57734
80+
pd.set_option('future.no_silent_downcasting', True)
7981
full_df = pd.DataFrame(rows).replace('', np.nan)
8082

8183
# Narrow down the columns to those of interest
8284
try:
85+
analysis_columns = ['loop_name', 'self_ai', 'self_gflops', 'self_time']
8386
df = full_df[analysis_columns].copy()
8487
except KeyError:
8588
err('Could not read data columns from profiling. Not enough data has been '
@@ -168,8 +171,8 @@ def roofline(name, project, scale, precision, mode, th):
168171
label_x = row.self_ai + (row.self_ai + ai_max - 2 * ai_min) * (2**0.005 - 1)
169172
label_y = row.self_gflops
170173
ax.text(label_x, label_y,
171-
'Time: %.2fs\n'
172-
'Incidence: %.0f%%' % (row.self_time, row.percent_weight),
174+
f'Time: {row.self_time:.2f}s\n'
175+
f'Incidence: {row.percent_weight:.0f}%',
173176
bbox={'boxstyle': 'round', 'facecolor': 'white'}, fontsize=8)
174177
top_loops_data = [{'ai': row.self_ai,
175178
'gflops': row.self_gflops,
@@ -198,19 +201,18 @@ def roofline(name, project, scale, precision, mode, th):
198201
legend = plt.legend(loc='center left', bbox_to_anchor=(1, 0.5),
199202
prop={'size': 7}, title='Rooflines')
200203

201-
# saving the chart in PNG format
202-
plt.savefig('%s.png' % name, bbox_extra_artists=(legend,), bbox_inches='tight')
204+
# saving the chart in PDF format
205+
plt.savefig(f'{name}.pdf', bbox_extra_artists=(legend,), bbox_inches='tight')
203206
figpath = os.path.realpath(__file__).split(os.path.basename(__file__))[0]
204-
log('Figure saved in %s%s.png.' % (figpath, name))
207+
log(f'\nFigure saved in {figpath}{name}.pdf.')
205208

206209
# Save the JSON file
207210
with open('%s.json' % name, 'w') as f:
208211
f.write(json.dumps(roofline_data))
209212

210-
log('JSON file saved as %s.json.' % name)
213+
log(f'\nJSON file saved as {name}.json.')
214+
log('Done!')
211215

212216

213-
analysis_columns = ['loop_name', 'self_ai', 'self_gflops', 'self_time']
214-
215217
if __name__ == '__main__':
216218
roofline()

benchmarks/user/advisor/run_advisor.py

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1+
import click
12
import datetime
23
import logging
34
import os
5+
import sys
6+
47
from pathlib import Path
58
from subprocess import check_output, PIPE, Popen
6-
import sys
79
from tempfile import gettempdir, mkdtemp
810

9-
import click
10-
11-
12-
from benchmarks.user.advisor.advisor_logging import (check, log, progress,
13-
log_process)
11+
from advisor_logging import check, log, progress, log_process
1412

1513

1614
@click.command()
@@ -30,40 +28,43 @@
3028
'in --exec-args (if any).')
3129
def run_with_advisor(path, output, name, exec_args):
3230
path = Path(path)
33-
check(path.is_file(), '%s not found' % path)
34-
check(path.suffix == '.py', '%s not a Python file' % path)
31+
check(path.is_file(), f'{path} not found')
32+
check(path.suffix == '.py', f'{path} not a Python file')
3533

3634
# Create a directory to store the profiling report
3735
if name is None:
3836
name = path.stem
3937
if exec_args:
40-
name = "%s_%s" % (name, ''.join(exec_args.split()))
38+
name = f"{name}_{''.join(exec_args.split())}"
4139
if output is None:
4240
output = Path(gettempdir()).joinpath('devito-profilings')
4341
output.mkdir(parents=True, exist_ok=True)
4442
else:
4543
output = Path(output)
4644
if name is None:
47-
output = Path(mkdtemp(dir=str(output), prefix="%s-" % name))
45+
output = Path(mkdtemp(dir=str(output), prefix=f"{name}-"))
4846
else:
4947
output = Path(output).joinpath(name)
5048
output.mkdir(parents=True, exist_ok=True)
5149

52-
# Intel Advisor and Intel compilers must be available through either Intel Parallel
53-
# Studio or Intel oneAPI (currently tested versions include IPS 2020 Update 2 and
54-
# oneAPI 2021 beta08)
50+
# advixe-cl and icx should be available through Intel oneAPI
51+
# (tested with Intel oneAPI 2025.1)
5552
try:
5653
ret = check_output(['advixe-cl', '--version']).decode("utf-8")
54+
log(f"Found advixe-cl version: {ret.strip()}\n")
5755
except FileNotFoundError:
58-
check(False, "Error: Couldn't detect `advixe-cl` to run Intel Advisor.")
56+
check(False, "Error: Couldn't detect `advixe-cl` to run Intel Advisor."
57+
" Please source the Advisor environment.")
5958

6059
try:
61-
ret = check_output(['icc', '--version']).decode("utf-8")
60+
ret = check_output(['icx', '--version']).decode("utf-8")
61+
log(f"Found icx version: {ret.strip()}\n")
6262
except FileNotFoundError:
63-
check(False, "Error: Couldn't detect Intel Compiler (icc).")
63+
check(False, "Error: Couldn't detect Intel Compiler (icx)."
64+
" Please source the Intel oneAPI compilers.")
6465

6566
# All good, Intel compiler and advisor are available
66-
os.environ['DEVITO_ARCH'] = 'intel'
67+
os.environ['DEVITO_ARCH'] = 'icx'
6768

6869
# Tell Devito to instrument the generated code for Advisor
6970
os.environ['DEVITO_PROFILING'] = 'advisor'
@@ -73,7 +74,7 @@ def run_with_advisor(path, output, name, exec_args):
7374
if devito_logging is None:
7475
os.environ['DEVITO_LOGGING'] = 'WARNING'
7576

76-
with progress('Setting up multi-threading environment'):
77+
with progress('Setting up multi-threading environment with OpenMP'):
7778
# Roofline analyses are recommended with threading enabled
7879
os.environ['DEVITO_LANGUAGE'] = 'openmp'
7980

@@ -84,20 +85,19 @@ def run_with_advisor(path, output, name, exec_args):
8485
ret = check_output(['numactl', '--show']).decode("utf-8")
8586
ret = dict(i.split(':') for i in ret.split('\n') if i)
8687
n_sockets = len(ret['cpubind'].split())
87-
n_cores = len(ret['physcpubind'].split()) # noqa
8888
except FileNotFoundError:
8989
check(False, "Couldn't detect `numactl`, necessary for thread pinning.")
9090

9191
# Prevent NumPy from using threads, which otherwise leads to a deadlock when
9292
# used in combination with Advisor. This issue has been described at:
93-
# `software.intel.com/en-us/forums/intel-advisor-xe/topic/780506`
93+
# `software.intel.com/en-us/forums/intel-advisor-xe/topic/780506`
9494
# Note: we should rather sniff the BLAS library used by NumPy, and set the
9595
# appropriate env var only
9696
os.environ['OPENBLAS_NUM_THREADS'] = '1'
9797
os.environ['MKL_NUM_THREADS'] = '1'
9898
# Note: `Numaexpr`, used by NumPy, also employs threading, so we shall disable
9999
# it too via the corresponding env var. See:
100-
# `stackoverflow.com/questions/17053671/python-how-do-you-stop-numpy-from-multithreading` # noqa
100+
# `stackoverflow.com/questions/17053671/python-how-do-you-stop-numpy-from-multithreading` # noqa
101101
os.environ['NUMEXPR_NUM_THREADS'] = '1'
102102

103103
# To build a roofline with Advisor, we need to run two analyses back to
@@ -130,8 +130,8 @@ def run_with_advisor(path, output, name, exec_args):
130130
]
131131
py_cmd = [sys.executable, str(path)] + exec_args.split()
132132

133-
# Before collecting the `survey` and `tripcounts` a "pure" python run to warmup the
134-
# jit cache is preceded
133+
# Before collecting the `survey` and `tripcounts` a "pure" python run
134+
# to warmup the jit cache is preceded
135135

136136
log('Starting Intel Advisor\'s `roofline` analysis for `%s`' % name)
137137
dt = datetime.datetime.now()
@@ -147,6 +147,9 @@ def run_with_advisor(path, output, name, exec_args):
147147
advixe_handler.setFormatter(advixe_formatter)
148148
advixe_logger.addHandler(advixe_handler)
149149

150+
log(f"Project folder: {output}")
151+
log(f"Logging progress in: `{advixe_handler.baseFilename}`")
152+
150153
with progress('Performing `cache warm-up` run'):
151154
try:
152155
p_warm_up = Popen(py_cmd, stdout=PIPE, stderr=PIPE)
@@ -170,10 +173,12 @@ def run_with_advisor(path, output, name, exec_args):
170173
except OSError:
171174
check(False, 'Failed!')
172175

173-
log('Storing `survey` and `tripcounts` data in `%s`' % str(output))
176+
log(f'Storing `survey` and `tripcounts` data in `{output}`')
174177
log('To plot a roofline type: ')
175-
log('python3 roofline.py --name %s --project %s --scale %f'
176-
% (name, str(output), n_sockets))
178+
log(f'python3 roofline.py --name {name} --project {output} --scale {n_sockets}')
179+
180+
log('\nTo open the roofline using advixe-gui: ')
181+
log(f'advixe-gui {output}')
177182

178183

179184
if __name__ == '__main__':

conftest.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from devito import Eq, configuration, Revolver # noqa
99
from devito.checkpointing import NoopRevolver
1010
from devito.finite_differences.differentiable import EvalDerivative
11-
from devito.arch import Cpu64, Device, sniff_mpi_distro, Arm
11+
from devito.arch import Cpu64, Device, sniff_mpi_distro, Arm, get_advisor_path
1212
from devito.arch.compiler import (compiler_registry, IntelCompiler, OneapiCompiler,
1313
NvidiaCompiler)
1414
from devito.ir.iet import (FindNodes, FindSymbols, Iteration, ParallelBlock,
@@ -32,8 +32,8 @@ def skipif(items, whole_module=False):
3232
# Sanity check
3333
accepted = set()
3434
accepted.update({'device', 'device-C', 'device-openmp', 'device-openacc',
35-
'device-aomp', 'cpu64-icc', 'cpu64-icx', 'cpu64-nvc', 'cpu64-arm',
36-
'cpu64-icpx', 'chkpnt'})
35+
'device-aomp', 'cpu64-icc', 'cpu64-icx', 'cpu64-nvc',
36+
'noadvisor', 'cpu64-arm', 'cpu64-icpx', 'chkpnt'})
3737
accepted.update({'nodevice'})
3838
unknown = sorted(set(items) - accepted)
3939
if unknown:
@@ -79,6 +79,12 @@ def skipif(items, whole_module=False):
7979
isinstance(configuration['platform'], Cpu64):
8080
skipit = "`icx+cpu64` won't work with this test"
8181
break
82+
# Skip if icx or advisor are not available
83+
if i == 'noadvisor' and \
84+
(not isinstance(configuration['compiler'], IntelCompiler) or
85+
not get_advisor_path()):
86+
skipit = "Only `icx+advisor` should be tested here"
87+
break
8288
# Skip if it won't run on Arm
8389
if i == 'cpu64-arm' and isinstance(configuration['platform'], Arm):
8490
skipit = "Arm doesn't support x86-specific instructions"

0 commit comments

Comments
 (0)