diff --git a/.cspell.json b/.cspell.json
index 5bd726026..4ad06d442 100644
--- a/.cspell.json
+++ b/.cspell.json
@@ -7,7 +7,7 @@
{
"name": "ok-unknown-words",
"path": "./.cspell/ok-unknown-words.txt",
- "addWords": false,
+ "addWords": false
}
],
"dictionaries": [
@@ -19,10 +19,13 @@
"ignorePaths": [
"cspell.json",
"*.cdl",
+ // local packaging and buid byproducts
"build",
"*.egg-info",
"**/*.egg-info/**",
- "notebooks",
+ "epmtdocs/site/**",
+ // notebooks/ contains lots of html
+ "notebooks",
// sample/ contains test workload scripts and staged job data
"sample/**",
// test/data/ contains binary fixtures, CSVs, and outlier datasets
diff --git a/.cspell/ok-unknown-words.txt b/.cspell/ok-unknown-words.txt
index c35f6928b..3591bc345 100644
--- a/.cspell/ok-unknown-words.txt
+++ b/.cspell/ok-unknown-words.txt
@@ -1,40 +1,535 @@
-CMIP
-cmip
-docstrings
-EPMT
epmt
-EPMTDB
-epmtdocs
-epmtlib
-jobid
-jobids
-noaa
-NOAA
-noarch
-noqa
-numpy
-omip
-PAPI
-papi
-PAPIEX
+EPMT
papiex
-PPAN
-ppan
-pylint
-pylintrc
-pytest
-pyyaml
-RDHPCS
-rdhpcs
-scikit
-scipy
-setuptools
+jobid
+procs
slurm
+epmtlib
+PAPIEX
+ndays
SLURM
-slurmctld
-slurmd
-SLURMD
+refmodels
+rdtsc
+numtids
+ctxsw
+tcsh
+refmodel
+usertime
+systemtime
+jobname
+fltr
+exename
+majflt
+rssmax
+minflt
+hsmget
sqlalchemy
+pyod
+dbcare
+timeslices
+syscr
+PAPI
+mkdocs
+jobids
+invol
+inblock
+delayacct
+blkio
+syscw
+rchar
+pytest
+outblock
+oncpu
+ppid
+pgid
+unanalyzed
+dframe
+pylint
+mvod
+papi
+JOBID
+pyinstaller
+exitsignal
+uninstrument
+outl
+logfn
+fdet
+timavg
+dbsize
+slurmctld
+setuptools
+plotly
+funcs
+wrapit
srun
sbatch
-SBATCH
+findwhat
+Durachta
+untar
+rootcause
+nprocs
+ncrcat
+ncatted
+LOCALID
+fregrid
+DSQLITE
+destdir
+vftmp
+tushar
+SQLA
+slurmd
+ocsvm
+modulefiles
+metricname
+hbos
+epmtdocs
+CPUS
+byhost
+psycopg
+pids
+ondelete
+ncrc
+ncpus
+ncks
+mpirank
+llnl
+infile
+indir
+filedict
+csvjoiner
+bycpu
+gethostname
+exitcode
+dmput
+datas
+autouse
+splitvars
+SHLVL
+pyproject
+nans
+MVOD
+madz
+libsqlite
+kwargify
+jobdatafile
+dlist
+badfiles
+uvod
+usejson
+sysexit
+slurmdbd
+scipy
+scikit
+randn
+pytz
+numpy
+NODELIST
+mpinumranks
+maxiters
+libpfm
+ipykernel
+intlvl
+initdb
+fini
+errdir
+dlst
+dbcopy
+cmip
+backref
+anysh
+ABOD
+wchar
+tuser
+tepmt
+syscalls
+syscall
+sqla
+scriptname
+mirrorlist
+MACHTYPE
+LOGNAME
+localfile
+LOADEDMODULES
+linuxkit
+libpapiex
+labapp
+jupyterlab
+ipywidgets
+ipython
+dotdict
+docstrings
+Dockerfiles
+cpus
+warnopts
+usebytes
+unprocd
+undercsh
+TAVG
+Smirnov
+SLURMD
+Slurmd
+Slurmctld
+Slurm
+sleeptest
+sklearn
+sinfo
+SIGUSR
+RUSAGE
+rmean
+rmax
+RLIMIT
+retlist
+qtconsole
+pyenv
+pkgs
+pidf
+outf
+onupdate
+omip
+OLDPWD
+oldproctag
+nrecs
+NODEID
+noaa
+nestlevel
+MPLCONFIGDIR
+modulecmd
+mjob
+MADZ
+livereload
+libmonitor
+lesspipe
+ldlib
+kstest
+Kolmogorov
+joblist
+inputfile
+inputf
+inmem
+GTIDS
+getrusage
+filetostage
+devtest
+devhome
+deets
+csvfile
+covsuffix
+cntmax
+CMIP
+classfiers
+bcolors
+argslist
+Wilk
+unproc
+unittests
+retstr
+repr
+rdhpcs
+rcfile
+PYTHONSTARTUP
+pystartup
+printsettings
+PLATFORMTHEME
+pidfile
+papiexclean
+outrows
+outrow
+OSTYPE
+nthreads
+NTASKS
+NPROCS
+NODENAME
+noconfirm
+NNODES
+MODULESHOME
+MODULEPATH
+mempeak
+MANPATH
+lzma
+LSCOLORS
+libpapi
+LESSOPEN
+LESSCLOSE
+ldconfig
+lastid
+jobscriptname
+jobdir
+inbetween
+HOSTTYPE
+HISTSIZE
+groupnames
+GOPATH
+GOBIN
+exenames
+eventlist
+dockerclean
+distpath
+didsomething
+dictlist
+dbname
+dashclean
+cutime
+csvt
+cstime
+cpio
+coveragerc
+cminflt
+cmajflt
+CLICOLOR
+Bxegedabagaced
+appmenu
+utime
+tsums
+tablespaced
+sucess
+stime
+schedstat
+runtests
+qualname
+PYTEST
+primaryjoin
+outpath
+numranks
+njobs
+MATPLOTLIBDATA
+libexec
+kvdict
+Jobid
+inlinevar
+indexd
+giovtorres
+getpid
+fdist
+epmt's
+echoerr
+dumperr
+drilldown
+docsapp
+dmget
+D'Agostino
+contextmanager
+autovacuum
+apage
+alist
+Yoyodyne
+workflowdb
+Werkzeug
+WALLTIME
+virtualenv
+VARCHAR
+Unpickling
+thismodule
+thisisatoken
+tablename
+Srun
+signum
+signo
+sdist
+showevtinfo
+sessionmaker
+rockylinux
+pylintrc
+pydatetime
+pycache
+psql
+PPAN
+postambles
+Postamble
+OKBLUE
+nots
+normaltest
+noqa
+noheader
+nbserver
+minmax
+metaclass
+matplotlib
+mapperlib
+levelname
+joblib
+jobdata
+jmsg
+gsmput
+hostnames
+goodpath
+getuid
+gettimeofday
+EPMTDB
+distutils
+decomp
+csvjoin
+conftest
+contextlib
+classmethod
+bitrot
+astext
+argparse
+arctan
+arrayfuncs
+arraywise
+asdict
+autoflush
+automap
+cmor
+getenv
+getpgid
+getppid
+getsid
+getsitepackages
+hiddenimports
+hookspath
+isort
+jobacct
+jobtags
+Kolkata
+lambda
+lasttime
+linuxproc
+localtime
+snum
+salloc
+testpip
+textposition
+typevar
+typealias
+unsetenv
+untarring
+venv
+Waittime
+abstractproperty
+hsmput
+elif
+endswith
+cython
+csvdir
+modz
+Mucci
+multimodel
+multifactor
+metadatafile
+minimalmetrics
+mmperftools
+MEMLOCK
+LASTVAL
+FSIZE
+globus
+cmdname
+jobcomp
+filetxt
+Fairshare
+sched
+cleandb
+secondaryjoin
+raiseerr
+NTCF
+KUBECONFIG
+NOFILE
+perfevent
+gettid
+tids
+NOAAGFDL
+slurmctl
+encfeat
+encdf
+xspf
+svgz
+rmvb
+PRIO
+tmpvikl
+pdsbspm
+proctrack
+Proctrack
+readlink
+schemaname
+PGPASSWORD
+multimodal
+unimodal
+trimodal
+perc
+clfs
+esac
+uncollated
+postprocruns
+overgeneral
+booleaness
+mypackage
+mymodule
+nosec
+mypy
+optparse
+ixin
+NOTSET
+datefmt
+postproc
+dbitem
+OKGREEN
+metadatafile
+dateutil
+rgxs
+pygtk
+msvs
+nbhome
+noarch
+parso
+noarchive
+datapub
+dockerhub
+readcsv
+rownum
+poolclass
+Eeuo
+outform
+decdf
+decfeat
+arcname
+zxvf
+filert
+spcname
+rsplit
+dtype
+ints
+datname
+blas
+pathex
+ESRCH
+EINVAL
+idempotently
+kneedle
+lmdd
+LMDD
+cblof
+CBLOF
+iforest
+npts
+scoreatpercentile
+ddof
+EOSQL
+gettz
+cvzf
+Frob
+codehilite
+tmpn
+hereisasupersecurepassword
+aggr
+perlbrew
+ENDC
+EEXIST
+reerr
+rdstc
+dotdicts
+asus
+outfd
+outcsv
+outtar
+tweakable
+devel
+openmp
+flac
+nrows
+skiprows
+isin
+ndarray
+bitmask
+Uncategorized
+xaxis
+parseable
diff --git a/.github/workflows/md_lint.yml b/.github/workflows/md_lint.yml
index 1c0924159..5de579960 100644
--- a/.github/workflows/md_lint.yml
+++ b/.github/workflows/md_lint.yml
@@ -24,7 +24,6 @@ jobs:
uses: actions/checkout@v4
- name: Lint markdown files
- continue-on-error: true
uses: DavidAnson/markdownlint-cli2-action@v19
with:
globs: |
diff --git a/DEVELOPER.md b/DEVELOPER.md
index 796b4b600..04dfa29b0 100644
--- a/DEVELOPER.md
+++ b/DEVELOPER.md
@@ -1,4 +1,5 @@
# `epmt` Developer and Advanced Usage Guide
+
This document contains detailed information about `epmt` configuration, data collection,
database submission, analysis, metrics, debugging, and CI/CD infrastructure.
@@ -15,7 +16,7 @@ For installation and quick-start instructions, see [README.md](./README.md).
- [Data Collection with SLURM epilog and prolog](#data-collection-with-slurm-epilog-and-prolog)
- [The Second Mode, Data Submission](#the-second-mode-data-submission)
- [Manual Submission Example](#manual-submission-example)
- - [Compressed Directory Submission Exmple](#compressed-directory-submission-exmple)
+ - [Compressed Directory Submission Example](#compressed-directory-submission-example)
- [Internal-batch Job Submission Example](#internal-batch-job-submission-example)
- [Data From Current Session Submission Example](#data-from-current-session-submission-example)
- [The Third Mode, Data Analysis and Visualization](#the-third-mode-data-analysis-and-visualization)
@@ -34,12 +35,14 @@ For installation and quick-start instructions, see [README.md](./README.md).
- [`version GLIBC_x.xx not found`](#version-glibc_xxx-not-found)
## Configuration
-`epmt` houses default settings (`epmt_default_settings.py`), user settings (`settings.py`),
-and a submodule (`epmt_settings.py`) that appends the user settings to the end of the
+
+`epmt` houses default settings (`epmt_default_settings.py`), user settings (`settings.py`),
+and a submodule (`epmt_settings.py`) that appends the user settings to the end of the
default settings, overriding them.
Custom user settings should only be included by developers who understand `epmt`'s requirements.
The default settings should first be evaluated, they look a little bit like the following:
+
```bash
$ cat src/epmt/epmt_default_settings.py
...
@@ -55,8 +58,10 @@ $ cat src/epmt/epmt_default_settings.py
```
### Environment Variables
+
The following variables replace, at run-time, the values in the `db_params` dictionary found in `settings.py`:
-```
+
+```text
EPMT_DB_PROVIDER
EPMT_DB_USER
EPMT_DB_PASSWORD
@@ -66,7 +71,9 @@ EPMT_DB_FILENAME
```
### Getting Current Configuration Information
+
You can examine all current settings by passing the `--help` option:
+
```bash
$ ./epmt --help
usage: epmt [-n] [-d] [-h] [-a] [--drop]
@@ -95,19 +102,22 @@ environment variables (overrides settings.py):
```
## The Three Modes of `epmt`
+
There are three modes to `epmt` usage; data collection, data submission, and data analysis. Each
has different dependencies:
-* **Collection** requires Python 2.6 or higher, and compiled [`papiex`](https://github.com/noaa-gfdl/papiex)
+- **Collection** requires Python 2.6 or higher, and compiled [`papiex`](https://github.com/noaa-gfdl/papiex)
libraries for process tagging
-* **Submission** requires Python packages for SQL and database interactions (`sqlalchemy`, `sqlite`, `postgres`)
-* **Analysis** requires `jupyter`, `iPython`, and additionally [`epmt-dash`](https://github.com/noaa-gfdl/epmt-dash)
+- **Submission** requires Python packages for SQL and database interactions (`sqlalchemy`, `sqlite`, `postgres`)
+- **Analysis** requires `jupyter`, `iPython`, and additionally [`epmt-dash`](https://github.com/noaa-gfdl/epmt-dash)
and `plotly` for dashboard-style analytics
### The First Mode, Data Collection
#### Collecting Performance Data
+
Assuming you have `epmt` installed and in your path, let's modify a job file:
+
```bash
$ cat my_job.sh
#!/bin/bash
@@ -116,6 +126,7 @@ $ cat my_job.sh
```
This becomes:
+
```bash
$ cat my_job_epmt.sh
#!/bin/bash
@@ -125,7 +136,8 @@ epmt run ./compute_the_world --debug
epmt stop
```
-Or more succintlty by automating the start/stop cycle with the `--auto` or `-a` flag:
+Or more succinctly by automating the start/stop cycle with the `--auto` or `-a` flag:
+
```bash
$ cat my_job_epmt2.sh
#!/bin/bash
@@ -134,6 +146,7 @@ epmt -a run ./compute_the_world --debug
```
But usually we want to run more than one executable. We could have any number of run statements:
+
```bash
$ cat my_job_epmt3.sh
#!/bin/bash
@@ -150,10 +163,11 @@ provides the configuration to export to the environment through the `source`
command. This is intended for use in a job file and should be evaluated by the
running shell, be it `bash` or `csh`. `epmt source` prints the required
environment variables in Bash format unless either the `SHELL` or `_`
-environment variable ends in `csh`.
+environment variable ends in `csh`.
**Note the unset of `LD_PRELOAD` before stop!** This prevents the data
collection routine from running on `epmt stop` itself.
+
```bash
$ cat my_job_bash.sh
#!/bin/bash
@@ -172,7 +186,8 @@ unset LD_PRELOAD
epmt stop
```
-Here's an example for `csh`, when run interactively,
+Here's an example for `csh`, when run interactively,
+
```bash
$ /bin/csh
> epmt -j1 source
@@ -182,10 +197,11 @@ setenv LD_PRELOAD /Users/phil/Work/GFDL/epmt.git/../papiex-oss/papiex-oss-instal
```
#### Data Collection with SLURM epilog and prolog
+
Using configured prolog and epilogs with SLURM tasks allows one to skip job
instrumentation entirely, except for job tags (`EPMT_JOB_TAGS`) and process
tags (`PAPIEX_TAGS`). These are configured in `slurm.conf` for jobs
-submitted with `sbatch` but can be tested on the command line when using `srun`.
+submitted with `sbatch` but can be tested on the command line when using `srun`.
The above Csh job is equivalent to the below sequence using a prolog and
epilog, ***with the exception of the trailing submit statement.***
@@ -200,10 +216,11 @@ $ sleep 1
For this job to work using `sbatch`, make the following modifications in
`slurm.conf`, substituting the appropriate path for `$EPMT_PREFIX`:
+
```bash
-$ SLURM_TASK_SCRIPT_DIR=${EPMT_PREFIX}/epmt-install/slurm
-$ TaskProlog=${SLURM_TASK_SCRIPT_DIR}/slurm_task_prolog_epmt.sh
-$ TaskEpilog=${SLURM_TASK_SCRIPT_DIR}/slurm_task_epilog_epmt.sh
+SLURM_TASK_SCRIPT_DIR=${EPMT_PREFIX}/epmt-install/slurm
+TaskProlog=${SLURM_TASK_SCRIPT_DIR}/slurm_task_prolog_epmt.sh
+TaskEpilog=${SLURM_TASK_SCRIPT_DIR}/slurm_task_epilog_epmt.sh
```
If this fails, the `papiex` installation is likely either missing or
@@ -211,29 +228,35 @@ misconfigured in `settings.py`. The `-a` flag tells `epmt` to treat
this run as an entire job.
### The Second Mode, Data Submission
+
After collecting the data, jobs (groups of processes) are imported into the
database with the `submit` command. This command takes arguments in the form of
-directories or tar files that must contain a `job_metadata` file.
+directories or tar files that must contain a `job_metadata` file.
Normal operation is to submit one or more directories:
+
```bash
-$ epmt submit [...]
+epmt submit [...]
```
One can also submit a list of compressed tar files:
+
```bash
-$ epmt submit [...]
+epmt submit [...]
```
There is also a mode where the current environment is used to determine where to find the data.
+
```bash
-$ epmt submit
+epmt submit
```
#### Manual Submission Example
+
We can submit our previous job to the database defined in `settings.py` by
running the `epmt submit` command with the directory returned by `stage` (found
in the location set by `settings.py` `epmt_output_prefix`):
+
```bash
$ epmt -v submit /tmp/epmt/1/
INFO:epmt_cmds:submit_to_db(/tmp/epmt/1/,*-papiex-[0-9]*-[0-9]*.csv,False)
@@ -282,14 +305,18 @@ INFO:epmt_job:Staged import took 0:00:00.189151, 5.286781 processes per second
INFO:epmt_cmds:Committed job 1 to database: Job[u'1']
```
-#### Compressed Directory Submission Exmple
+#### Compressed Directory Submission Example
+
This might happen at the end of the day via a cron job:
+
```bash
-$ epmt submit /*tgz
+epmt submit /*tgz
```
#### Internal-batch Job Submission Example
+
These commands could be part of every users job, or in the batch systems configurable preambles/postambles.
+
```bash
$ cat my_job.sh
#!/bin/bash
@@ -302,16 +329,19 @@ epmt submit
```
The start/stop cycle can be removed with the `--auto` or `-a` flag, which performs start and stop for you:
-```
-$ epmt -a run ./debug_the_world --outliers
-$ epmt submit
+
+```bash
+epmt -a run ./debug_the_world --outliers
+epmt submit
```
#### Data From Current Session Submission Example
-If not inside of a batch environment, `epmt` will *attempt to fake-and-bake a job id*. This is useful
-when performing interactive runs. You may not be able to submit these jobs to a shared database due to
-constraints on job ID uniqueness, sincet he session ID is not guaranteed to be unique across reboots,
+
+If not inside of a batch environment, `epmt` will *attempt to fake-and-bake a job id*. This is useful
+when performing interactive runs. You may not be able to submit these jobs to a shared database due to
+constraints on job ID uniqueness, since the session ID is not guaranteed to be unique across reboots,
much less other systems. However, this use case is perfectly acceptable when using a private database:
+
```bash
$ epmt start
WARNING:epmt_cmds:JOB_ID unset: Using session id 6948 as JOB_ID
@@ -323,8 +353,10 @@ $ epmt submit
```
### The Third Mode, Data Analysis and Visualization
+
`epmt` uses an `IPython` notebook data analytics environment. Starting the
Jupyter notebook is easy from the `epmt notebook` command:
+
```bash
$ epmt notebook
[I 15:39:24.236 NotebookApp] Serving notebooks from local directory: /home/chris/Documents/playground/MM/build/epmt
@@ -344,23 +376,29 @@ $ epmt notebook
The notebook command supports passing parameters to jupyter, such as host IP
for sharing access with machines on the local network, notebook token, and
notebook password:
+
```bash
-$ epmt notebook -- --ip 0.0.0.0 --NotebookApp.token='thisisatoken' --NotebookApp.password='hereisa$upersecurepassword'
+epmt notebook -- --ip 0.0.0.0 --NotebookApp.token='thisisatoken' --NotebookApp.password='hereisasupersecurepassword'
```
## Debugging
+
`epmt` can be passed both `-n` (dry-run) and `-v` (verbosity) to help
with debugging. Add more `-v` flags to increase verbosity level (`-vvv`).
+
```bash
-$ epmt -v start
+epmt -v start
```
Or to attempt a submit without touching the database:
+
```bash
-$ epmt -vv submit -n /dir/to/jobdata
+epmt -vv submit -n /dir/to/jobdata
```
Also, one can decode and dump the job_metadata file in a dir or compressed dir.
+
+
```bash
$ epmt dump ~/Downloads/yrs05-25.20190221/CM4_piControl_C_atmos_00050101.papiex.gfdl.19712961.tgz
exp_component atmos
@@ -384,13 +422,16 @@ job_pl_start 2019-02-20 19:58:41.274267
job_pl_submit 2019-02-20 19:58:41.274463
job_pl_username Foo.Bar
```
+
## Performance Metrics Data Dictionary
+
`epmt` collects data both from the job runtime and the applications run in that
environment. See the `src/epmt/models/` directory for fixed data stored related to each
object. Metric data is stored differently; the data collector's data dictionary
can be found in papiex-oss/README.md. At the time of this writing, it looked
like this:
+
| Key | Scope | Description |
|--------------------------- |--------- |-------------------------------------------------------- |
| 1. tags | Process | User specified tags for this executable |
@@ -443,48 +484,59 @@ like this:
| * | Thread | PAPI metrics |
### Addition of new metrics
+
Additional metrics can be configured either in two ways:
-* The `papiex_options` string in `settings.py` if using `epmt run` or `epmt source`
-* The value of the `PAPIEX_OPTIONS` environment variable if using `LD_PRELOAD` directly.
+
+- The `papiex_options` string in `settings.py` if using `epmt run` or `epmt source`
+- The value of the `PAPIEX_OPTIONS` environment variable if using `LD_PRELOAD` directly.
The value of these should be a comma separated string:
+
```bash
-$ export PAPIEX_OPTIONS="PERF_COUNT_SW_CPU_CLOCK,PAPI_CYCLES"
+export PAPIEX_OPTIONS="PERF_COUNT_SW_CPU_CLOCK,PAPI_CYCLES"
```
To list available and functioning metrics, use one of the included command line tools:
- * `papi_avail` and `papi_native_avail` (via `papi`)
- * `check_events` and `showevtinfo` (via `libpfm`)
- * `perf list` (`linux`)
+
+- `papi_avail` and `papi_native_avail` (via `papi`)
+- `check_events` and `showevtinfo` (via `libpfm`)
+- `perf list` (`linux`)
The `PERF_COUNT_SW_*` events should work on any system that has the proper
`/proc/sys/kernel/perf_event_paranoid` setting.
One should verify the functionality of the metric using the `papi_command_line` tool:
+
```bash
-$ papi_command_line PERF_COUNT_SW_CPU_CLOCK
-$ papi_command_line CYCLES
+papi_command_line PERF_COUNT_SW_CPU_CLOCK
+papi_command_line CYCLES
```
## CI/CD Workflows and Caching
+
`epmt`'s GitHub Actions CI is split into focused workflows that use
`actions/cache` to avoid rebuilding expensive artifacts on every pull request
run.
### Workflows
+
+
| Workflow | Trigger | Purpose |
|---|---|---|
| `docker_build_test.yml` | `push` to `main`, `pull_request` | Full build + test pipeline; restores cached artifacts before building |
| `slurm_image_build.yml` | Weekly (Mon 06:00 UTC), `workflow_dispatch` | Builds the `slurm-cluster` Docker image from source and saves it to cache |
| `weekly_tarball_build.yml` | Weekly (Mon 06:00 UTC), `workflow_dispatch` | Compiles `papiex` and downloads `epmt-dash`, then saves both to cache |
| `build_and_test_epmt.yml` | `push` to `main`, `pull_request` | Source-tree unit tests (no Docker) |
+
### Caches and Invalidation
+
Each cache step is keyed on its build prerequisites — analogous to how `make`
uses file modification times to decide whether a target must be rebuilt. Changing
a prerequisite produces a new cache key, causing a cache miss and forcing a fresh
build.
+
| Cache | Cache key components | Invalidation trigger | Notes |
|---|---|---|---|
| `epmt-build` Docker image | `OS_TARGET` + `PYTHON_VERSION` +
`SQLITE_VERSION` +
`hashFiles(Dockerfile, requirements.txt.py3)` | Edit the Dockerfile or requirements file, or bump any version variable | Fully content-hash based — closest analogy to `make` |
@@ -492,24 +544,29 @@ build.
| `test-release` Docker image | `OS_TARGET` + `PYTHON_VERSION` +
`SQLITE_VERSION` +
`hashFiles(Dockerfile, requirements.txt.py3)` +
`github.sha` | Always rebuilds (by design) —
`restore-keys` prefix reuses
unchanged early layers via
`--cache-from` | Image content changes
every commit; layer reuse
keeps it fast |
| `slurm-cluster` Docker image | `IMAGE_TAG` +
`SLURM_TAG` +
`SLURM_CLUSTER_TAG` | Bump any of the three version
variables in `docker_build_test.yml`
and `slurm_image_build.yml` | Version-string based; upstream
tag mutations without a version
bump won't invalidate |
| `epmt-dash` UI directory | `EPMT_DASH_SRC_BRANCH` | Change `EPMT_DASH_SRC_BRANCH`
in `docker_build_test.yml`,
`weekly_tarball_build.yml`,
and `Makefile` | Branch-name based; new commits
to same branch don't invalidate —
weekly workflow bounds staleness
to ≤1 week |
+
### Cache Invalidation Gap vs. `make`
+
`make` detects prerequisite changes via file modification times regardless of
version numbers. The GitHub Actions caches above use version strings or content
hashes instead, so:
-* `epmt-build` is fully `make`-like — changing the Dockerfile or
+
+- `epmt-build` is fully `make`-like — changing the Dockerfile or
requirements file immediately produces a different hash and forces a rebuild.
-* `papiex` and `slurm-cluster` require a deliberate version bump in the
+- `papiex` and `slurm-cluster` require a deliberate version bump in the
workflow env block to trigger a rebuild. Remote source changes without a
version bump go undetected until the next weekly build.
-* `epmt-dash` requires either a branch rename or waiting for the weekly
+- `epmt-dash` requires either a branch rename or waiting for the weekly
build. The weekly `weekly_tarball_build.yml` workflow always fetches fresh
content, bounding maximum staleness to one week.
### Forcing a Rebuild
+
To force any individual cache to rebuild, bump the relevant version variable
in the `env:` section of both the weekly workflow and `docker_build_test.yml`,
and update the `Makefile` to match:
+
```yaml
# docker_build_test.yml (and weekly_tarball_build.yml)
env:
@@ -523,6 +580,7 @@ The `epmt-build` cache is invalidated automatically whenever
modified — no manual version bump is needed.
### Weekly Pre-warming
+
`slurm_image_build.yml` and `weekly_tarball_build.yml` run every Monday
morning to pre-warm their respective caches before the working week begins.
`docker_build_test.yml` then restores those caches on pull request and push
@@ -533,10 +591,12 @@ artifact inline so the pipeline never silently skips a required build step.
## Troubleshooting
### Virtual Environments
+
Note that often in virtual environments, hardware counters are not often available in the VM.
### Common Error Messages
#### `version GLIBC_x.xx not found`
+
The collector library may not have been built for the current environment or the release
OS version does not match the current environment.
diff --git a/Dockerfiles/Dockerfile.centos-7-epmt-test-release b/Dockerfiles/Dockerfile.centos-7-epmt-test-release
index e578fc824..0d4bd6e47 100644
--- a/Dockerfiles/Dockerfile.centos-7-epmt-test-release
+++ b/Dockerfiles/Dockerfile.centos-7-epmt-test-release
@@ -86,9 +86,6 @@ RUN rm -f *.tgz epmt-installer
-#
-# ian attempting smth here
-#
##won't work, read-only file system, even sudo won't do it
#RUN sudo -n echo 2 > /proc/sys/kernel/perf_event_paranoid
diff --git a/Makefile b/Makefile
index 681d109e1..815d50bb3 100644
--- a/Makefile
+++ b/Makefile
@@ -163,7 +163,7 @@ $(EPMT_RELEASE) dist:
# runs setuptools
# note that this step requires EPMT_RELEASE and PAPIEX_RELEASE, but we don't explicitly state it here, b.c.
-# when we go in the docker container, the time-zone changes and therefore thet timestamp comparison triggers re-making
+# when we go in the docker container, the time-zone changes and therefore the timestamp comparison triggers re-making
# targets that do not need to be remade
python-dist:
@echo "(python-dist) whoami: $(shell whoami)"
@@ -192,7 +192,7 @@ test-$(EPMT_RELEASE) dist-test:
@echo "WARNING removing directory to clean up: rm -rf epmt-install-tests"
rm -rf epmt-install-tests
-# this target 1) builds an image with an environment inwhich we'd like to build our applicaiton
+# this target 1) builds an image with an environment in which we'd like to build our application
# 2) builds that application within a running container of that image
# NOTE: bind mounts to current working directory, usually the repository directory
docker-dist:
@@ -204,7 +204,7 @@ docker-dist:
@echo
@echo
@echo " - docker build Dockerfiles/Dockerfile.$(OS_TARGET)-epmt-build"
- @echo " we are creating a container environment inwhich to build the python distribution"
+ @echo " we are creating a container environment in which to build the python distribution"
$(DOCKER_BUILD) Dockerfiles/Dockerfile.$(OS_TARGET)-epmt-build -t $(OS_TARGET)-epmt-build:$(EPMT_VERSION) \
--build-arg sqlite_version=$(SQLITE_VERSION) \
--build-arg sqlite_year=$(SQLITE_YEAR) \
@@ -212,7 +212,7 @@ docker-dist:
@echo
@echo
@echo " - docker run