Skip to content

Commit

Permalink
Merge pull request #161 from jpmorgan98/main
Browse files Browse the repository at this point in the history
Adding Caching and a Debug Runtime Option
  • Loading branch information
ilhamv authored Feb 15, 2024
2 parents 9ef1d04 + 2b529bd commit eec46fc
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 40 deletions.
13 changes: 8 additions & 5 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
# separate terms of service, privacy policy, and support
# documentation.

# assumming this is being done in a repo with trusted publishing permissions in pypi

name: Upload Python Package

on:
Expand All @@ -17,10 +19,10 @@ permissions:

jobs:
deploy:

runs-on: ubuntu-latest

steps:
permissions:
id-token: write
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.11
uses: actions/setup-python@v3
Expand All @@ -38,8 +40,9 @@ jobs:
bash .github/workflows/patch.sh
- name: Build package
run: python -m build
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

#with:
# user: __token__
# password: ${{ secrets.PYPI_API_TOKEN }}
2 changes: 1 addition & 1 deletion docs/paper.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ We have implemented novel algorithms using this scheme and, in some verification
It uses the Numba compiler for Python to compile compute kernels to a desired hardware target, including support for graphics processing units (GPUs) [@lam_numba_2015].
`MC/DC` uses `mpi4py` for distributed-memory parallelism [@mpi4py_2021] and has run at the scale of tens of thousands of processors [@variansyah_mc23_mcdc].
These acceleration and abstraction techniques allow `MC/DC` developers to remain in a pure Python development environment without needing to support compiled or domain-specific languages.
This has allowed `MC/DC` to grow from its instantiation less than two years ago into a codebase that supports full performant neutron transport and investigation of novel transport algorithms, with development mostly from relative novices.
This has allowed `MC/DC` to grow from its initialization less than two years ago into a codebase that supports full performant neutron transport and investigation of novel transport algorithms, with development mostly from relative novices.

Many of the traditionally developed neutron-transport codes are export-controlled (i.e., are not open source and difficult to access) and notoriously difficult to install, use, and develop in.
Because `MC/DC` is an open-source and easily installable Python package (with a `pip`-installable distribution), it is ideal for use in an academic environment for both research and education.
Expand Down
1 change: 1 addition & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"sphinx.ext.autosummary",
"sphinx_toolbox.github",
"sphinx_toolbox.sidebar_links",
"sphinx.ext.autosectionlabel",
]
autosummary_generate = True

Expand Down
58 changes: 58 additions & 0 deletions docs/source/contribution.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,64 @@ It's pretty easy to do this locally, just run,
in the top level MC/DC directory and all necessary changes will be automatically made for you.

---------
Debugging
---------

MCDC includes options to debug the Numba JIT code.
It does this by toggling Numba options using the numba.config submodule.
This will result in less performant code and longer compile times but will allow for better error messages from Numba and other packages.
`See Numba documentation of a list of all possible debug and compiler options. <https://numba.readthedocs.io/en/stable/reference/envvars.html#debugging>`_
The most useful set of debug options for MC/DC can be enabled with

.. code-block:: python3
python input.py --mode=numba_debug
Which will toggle the following debug and compiler options in Numba:

* ``DISABLE_JIT=False`` turns on the jitter
* ``NUMBA_OPT=0`` Forces the compilers to form un-optimized code (other options for this are ``1``, ``2``, and ``3`` with ``3`` being the most optimized). This option might need to be changed if errors only result from more optimization.
* ``DEBUG=False`` turns on all debugging options. This is still disabled in ``mcdc numba_debug`` as it will print ALOT of info on your terminal screen
* ``NUMBA_FULL_TRACEBACKS=1`` allows errors from sub-packages to be printed (i.e. Numpy)
* ``NUMBA_BOUNDSCHECK=1`` numba will check vectors for bounds errors. If this is disabled it bound errors will result in a ``seg_fault``. This in consort with the previous option allows for the exact location of a bound error to be printed from Numpy subroutines
* ``NUMBA_DEBUG_NRT=1`` enables the `Numba run time (NRT) statistics counter <https://numba.readthedocs.io/en/stable/developer/numba-runtime.html>`_ This helps with debugging memory leaks.
* ``NUMBA_DEBUG_TYPEINFER= 1`` print out debugging information about type inferences that numba might need to make if a function is ill-defined
* ``NUMBA_ENABLE_PROFILING=1`` enables profiler use
* ``NUMBA_DUMP_CFG=1`` prints out a control flow diagram

If extra debug options or alteration to these options are required they can be toggled and passed under the ``mode==numba_debug`` option tree near the top of ``mcdc/main.py``.

-------
Caching
-------

MC/DC is a just-in-time (JIT) compiled code.
This is sometimes disadvantageous, especially for users who might run many versions of the same simulation with slightly different parameters.
As the JIT compilation scheme will only compile functions that are actually used in a given simulation, it is not a grantee that any one function will be compiled.

Developers should be very cautious about using caching features.
Numba has a few documented errors around caching.
The most critical of which is that functions in other files that are called by cached functions will not force a recompile, even if there are changes in those sub-functions.
In this case caching should be disabled.

In MC/DC the outer most loop functions (in ``mcdc/loop.py``) are called to be cached.
This is done with a option on the jit flag above the individual function declarations like

.. code-block:: python3
nb.njit(cache=True)
def loop_fixed_source(mcdc):
# Loop over
...
To disable caching toggle these jit flags from ``True`` to ``False``.
Alteratively a developer could delete the ``__pycache__`` directory or other cache directory which is system dependent (`see more about clearing the numba cache <https://numba.readthedocs.io/en/stable/developer/caching.html>`_)


At some point MC/DC will enable `Numba's Ahead of Time compilation abilities <https://numba.readthedocs.io/en/stable/user/pycc.html>`_. But the core development team is holding off until scheduled `upgrades to AOT functionality in Numba are implemented <https://numba.readthedocs.io/en/stable/reference/deprecation.html#deprecation-numba-pycc>`_.
However if absolutely required by users numba does allow for some `cache sharing <https://numba.readthedocs.io/en/stable/developer/caching.html>`_.

-------
Testing
-------
Expand Down
18 changes: 18 additions & 0 deletions docs/source/user.rst
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,23 @@ Numba Mode
python input.py --mode=numba
When running in Numba mode a significant amount of time is taken compiling Python functions to performant binaries.
Only functions used in a specific simulation will be compiled.
These binaries will be cached meaning that in subsequent runs of the same simulation the compilation step can be avoided.
The cache can be used as an effective ahead of time compilation scheme where binaries can be compiled once and shared between machines.
For more information on caching see :ref:`Caching` and `Numba Caching <https://numba.readthedocs.io/en/stable/developer/caching.html>`_.

MC/DC also has the ability to run Numba in a debugging mode.
This will result in less performant code and longer compile times but will allow for better error messages from Numba and other packages.

.. code-block:: python3
python input.py --mode=numba_debug
For more information on the exact behavior of this option see :ref:`Debugging`


Using MPI
^^^^^^^^^

Expand All @@ -216,6 +233,7 @@ Below, ``--mode`` can equal python or numba.
srun python input.py --mode=<python/numba>
Postprocessing Results
----------------------

Expand Down
25 changes: 15 additions & 10 deletions mcdc/loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,13 @@
# Fixed-source loop
# =========================================================================

# about caching:
# it is enabled as a default at the jit call level
# to effectivly disable cache, delete the cache folder (often located in /MCDC/mcdc/__pycache__)
# see more about cacheing here https://numba.readthedocs.io/en/stable/developer/caching.html

@njit

@njit(cache=True)
def loop_fixed_source(mcdc):
# Loop over batches
for idx_batch in range(mcdc["setting"]["N_batch"]):
Expand Down Expand Up @@ -89,7 +94,7 @@ def loop_fixed_source(mcdc):
# =========================================================================


@njit
@njit(cache=True)
def loop_eigenvalue(mcdc):
# Loop over power iteration cycles
for idx_cycle in range(mcdc["setting"]["N_cycle"]):
Expand Down Expand Up @@ -128,7 +133,7 @@ def loop_eigenvalue(mcdc):
# =============================================================================


@njit
@njit(cache=True)
def loop_source(seed, mcdc):
# Progress bar indicator
N_prog = 0
Expand Down Expand Up @@ -210,7 +215,7 @@ def loop_source(seed, mcdc):
# =========================================================================


@njit
@njit(cache=True)
def loop_particle(P, mcdc):
# Particle tracker
if mcdc["setting"]["track_particle"]:
Expand Down Expand Up @@ -303,7 +308,7 @@ def loop_particle(P, mcdc):
# =============================================================================


@njit
@njit(cache=True)
def loop_iqmc(mcdc):
# function calls from specified solvers
iqmc = mcdc["technique"]["iqmc"]
Expand All @@ -320,7 +325,7 @@ def loop_iqmc(mcdc):
gmres(mcdc)


@njit
@njit(cache=True)
def source_iteration(mcdc):
simulation_end = False
iqmc = mcdc["technique"]["iqmc"]
Expand Down Expand Up @@ -358,7 +363,7 @@ def source_iteration(mcdc):
total_source_old = iqmc["total_source"].copy()


@njit
@njit(cache=True)
def gmres(mcdc):
"""
GMRES solver.
Expand Down Expand Up @@ -513,7 +518,7 @@ def gmres(mcdc):
return


@njit
@njit(cache=True)
def power_iteration(mcdc):
simulation_end = False
iqmc = mcdc["technique"]["iqmc"]
Expand Down Expand Up @@ -559,7 +564,7 @@ def power_iteration(mcdc):
print_iqmc_eigenvalue_exit_code(mcdc)


@njit
@njit(cache=True)
def davidson(mcdc):
"""
The generalized Davidson method is a Krylov subspace method for solving
Expand Down Expand Up @@ -669,7 +674,7 @@ def davidson(mcdc):
# =============================================================================


@njit
@njit(cache=True)
def loop_source_precursor(seed, mcdc):
# TODO: censussed neutrons seeding is still not reproducible

Expand Down
53 changes: 51 additions & 2 deletions mcdc/main.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,74 @@
import argparse, os
import argparse, os, sys
import numba as nb

# Parse command-line arguments
# TODO: Will be inside run() once Python/Numba adapter is integrated
parser = argparse.ArgumentParser(description="MC/DC: Monte Carlo Dynamic Code")
parser.add_argument(
"--mode", type=str, help="Run mode", choices=["python", "numba"], default="python"
"--mode",
type=str,
help="Run mode",
choices=["python", "numba", "numba_debug"],
default="python",
)
parser.add_argument("--N_particle", type=int, help="Number of particles")
parser.add_argument("--output", type=str, help="Output file name")
parser.add_argument("--progress_bar", default=True, action="store_true")
parser.add_argument("--no-progress_bar", dest="progress_bar", action="store_false")
args, unargs = parser.parse_known_args()

from mcdc.print_ import (
print_banner,
print_msg,
print_runtime,
print_header_eigenvalue,
print_warning,
)

# Set mode
# TODO: Will be inside run() once Python/Numba adapter is integrated
mode = args.mode
if mode == "python":
nb.config.DISABLE_JIT = True
elif mode == "numba":
nb.config.DISABLE_JIT = False
nb.config.NUMBA_DEBUG_CACHE = 1
elif mode == "numba_debug":
msg = "\n >> Entering numba debug mode\n >> will result in slower code and longer compile times\n >> to configure debug options see main.py"
print_warning(msg)

nb.config.DISABLE_JIT = False # turns on the jitter
nb.config.DEBUG = False # turns on debugging options
nb.config.NUMBA_FULL_TRACEBACKS = (
1 # enables errors from sub-packages to be printed
)
nb.config.NUMBA_BOUNDSCHECK = 1 # checks bounds errors of vectors
nb.config.NUMBA_COLOR_SCHEME = (
"dark_bg" # prints error messages for dark background terminals
)
nb.config.NUMBA_DEBUG_NRT = 1 # Numba run time (NRT) statistics counter
nb.config.NUMBA_DEBUG_TYPEINFER = (
1 # print out debugging information about type inference.
)
nb.config.NUMBA_ENABLE_PROFILING = 1 # enables profiler use
nb.config.NUMBA_DUMP_CFG = 1 # prints out a control flow diagram
nb.config.NUMBA_OPT = 0 # forums un optimized code from compilers
nb.config.NUMBA_DEBUGINFO = 1 #
nb.config.NUMBA_EXTEND_VARIABLE_LIFETIMES = (
1 # allows for inspection of numba variables after end of compilation
)

# file="str.txt";file1="list.txt"
# out=sys.stdout
# sys.stdout=open('debug_numba_config.txt','w')
# help(nb.config)
# sys.stdout.close

# print_msg('>> Numba config exported to debug_numba_config.txt')

# elif mode == "numba x86":
# nb.config.NUMBA_OPT = 3
# NUMBA_DISABLE_INTEL_SVML

import h5py
import numpy as np
Expand Down
5 changes: 3 additions & 2 deletions mcdc/print_.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import numpy as np
import sys
from mpi4py import MPI

from colorama import Fore, Back, Style

master = MPI.COMM_WORLD.Get_rank() == 0

Expand All @@ -21,7 +21,8 @@ def print_error(msg):

def print_warning(msg):
if master:
print("Warning: %s\n" % msg)
print(Fore.RED + "Warning: %s\n" % msg)
print(Style.RESET_ALL)
sys.stdout.flush()


Expand Down
25 changes: 6 additions & 19 deletions mcdc/visualizer.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from mcdc.print_ import print_warning

try:
# launches visualization window
# must be inside this loop so it doesn't launch when the visualizer is imported
Expand All @@ -7,16 +9,8 @@
import distinctipy # creates unlimited visually distinct colors for visualization

except ImportError as e:
print("")
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
print("MC/DC visualization error:")
print(" Dependencies for visualization not installed")
print(" To install optional dependencies needed for visualization:")
print(" <pip install mcdc[viz]> ")
print("")
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
print("")

msg = "\n >> MC/DC visualization error: \n >> dependencies for visualization not installed \n >> install optional dependencies needed for visualization with \n >> <pip install mcdc[viz]> (add para for mac)"
print_warning(msg)

import tkinter as tk # Tkinter is used to create the window for the time slider and color key
import math
Expand Down Expand Up @@ -420,15 +414,8 @@ def visualize(start_time=0, end_time=0, tick_interval=1, material_colors={}):
# must be inside this loop so it doesn't launch when the visualizer is imported
import netgen.gui
except ImportError as e:
print("")
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
print("MC/DC visualization error:")
print(" Dependencies for visualization not installed")
print(" To install optional dependencies needed for visualization:")
print(" <pip install mcdc[viz]> ")
print("")
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
print("")
msg = "\n >> MC/DC visualization error: \n >> dependencies for visualization not installed \n >> install optional dependencies needed for visualization with \n >> <pip install mcdc[viz]> (add para for mac)"
print_warning(msg)

color_key_dic = draw_Geometry(
current_time=0,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ authors = [
]
description = "Monte Carlo / Dynamic Code, a pure python high performance Monte Carlo neutronics package"
readme = "README.md"
requires-python = ">=3.9, <=3.11.7"
requires-python = ">=3.9, <=3.11.8"
license = {file = "LICENSE"}
keywords = ["Monte Carlo", "Nuclear", "GPU", "numba", "mpi4py", "neutron transport", "neutronics", "HPC"]
classifiers = [
Expand Down

0 comments on commit eec46fc

Please sign in to comment.