diff --git a/.github/scripts/fbgemm_gpu_build.bash b/.github/scripts/fbgemm_gpu_build.bash index 3d754c2f4..33189bf41 100644 --- a/.github/scripts/fbgemm_gpu_build.bash +++ b/.github/scripts/fbgemm_gpu_build.bash @@ -194,6 +194,76 @@ __configure_fbgemm_gpu_build () { echo "[BUILD] FBGEMM_GPU build arguments have been set: ${build_args[@]}" } +__build_fbgemm_gpu_set_package_name () { + # Determine the package name based on release type and variant + export package_name="fbgemm_gpu" + + # Append qualifiers for the non-release version + if [ "$fbgemm_release_type" != "release" ]; then + export package_name="${package_name}_${fbgemm_release_type}" + fi + + # Append cpu or rocm for the non-CUDA case + if [ "$fbgemm_variant" == "cpu" ]; then + export package_name="${package_name}-cpu" + elif [ "$fbgemm_variant" == "rocm" ]; then + export package_name="${package_name}-rocm" + fi + + echo "[BUILD] Determined and set Python package name to use: ${package_name}" +} + +__build_fbgemm_gpu_set_python_tag () { + # shellcheck disable=SC2207,SC2086 + local python_version=($(conda run --no-capture-output ${env_prefix} python --version)) + + # shellcheck disable=SC2206 + local python_version_arr=(${python_version[1]//./ }) + + # Set the python tag (e.g. Python 3.12 -> py312) + export python_tag="py${python_version_arr[0]}${python_version_arr[1]}" + echo "[BUILD] Extracted and set Python tag: ${python_tag}" +} + +__build_fbgemm_gpu_set_python_plat_name () { + if [[ $KERN_NAME == 'Darwin' ]]; then + # This follows PyTorch package naming conventions + # See https://pypi.org/project/torch/#files + if [[ $MACHINE_NAME == 'arm64' ]]; then + export python_plat_name="macosx_11_0_${MACHINE_NAME}" + else + export python_plat_name="macosx_10_9_${MACHINE_NAME}" + fi + + elif [[ $KERN_NAME == 'Linux' ]]; then + # manylinux2014 is specified, bc manylinux1 does not support aarch64 + # See https://github.com/pypa/manylinux + export python_plat_name="manylinux2014_${MACHINE_NAME}" + + else + echo "[BUILD] Unsupported OS platform: ${KERN_NAME}" + return 1 + fi + + echo "[BUILD] Extracted and set Python platform name: ${python_plat_name}" +} + +__build_fbgemm_gpu_set_run_multicore () { + # shellcheck disable=SC2155 + local core=$(lscpu | grep "Core(s)" | awk '{print $NF}') && echo "core = ${core}" || echo "core not found" + # shellcheck disable=SC2155 + local sockets=$(lscpu | grep "Socket(s)" | awk '{print $NF}') && echo "sockets = ${sockets}" || echo "sockets not found" + local re='^[0-9]+$' + + export run_multicore="" + if [[ $core =~ $re && $sockets =~ $re ]] ; then + local n_core=$((core * sockets)) + export run_multicore=" -j ${n_core}" + fi + + echo "[BUILD] Set multicore run option for setup.py: ${run_multicore}" +} + __build_fbgemm_gpu_common_pre_steps () { # Private function that uses variables instantiated by its caller @@ -203,28 +273,23 @@ __build_fbgemm_gpu_common_pre_steps () { (test_binpath "${env_name}" c++) || return 1 (test_binpath "${env_name}" g++) || return 1 - # Determine the package name based on release type and variant - package_name="fbgemm_gpu" - if [ "$fbgemm_release_type" != "release" ]; then - package_name="${package_name}_${fbgemm_release_type}" + # Set the default the FBGEMM_GPU variant to be CUDA + if [ "$fbgemm_variant" != "cpu" ] && [ "$fbgemm_variant" != "rocm" ]; then + export fbgemm_variant="cuda" fi - if [ "$fbgemm_variant" == "cpu" ]; then - package_name="${package_name}-cpu" - elif [ "$fbgemm_variant" == "rocm" ]; then - package_name="${package_name}-rocm" - else - # Set to the default variant - fbgemm_variant="cuda" - fi - echo "[BUILD] Determined Python package name to use: ${package_name}" - # Extract the Python tag - # shellcheck disable=SC2207,SC2086 - python_version=($(conda run --no-capture-output ${env_prefix} python --version)) - # shellcheck disable=SC2206 - python_version_arr=(${python_version[1]//./ }) - python_tag="py${python_version_arr[0]}${python_version_arr[1]}" - echo "[BUILD] Extracted Python tag: ${python_tag}" + # Extract and set the package name given the FBGEMM_GPU variant + __build_fbgemm_gpu_set_package_name + + # Extract and set the Python tag + __build_fbgemm_gpu_set_python_tag + + # Extract and set the platform name + __build_fbgemm_gpu_set_python_plat_name + + # Set multicore run option for setup.py if the number of cores on the machine + # permit for this + __build_fbgemm_gpu_set_run_multicore echo "[BUILD] Running pre-build cleanups ..." print_exec rm -rf dist @@ -332,25 +397,6 @@ build_fbgemm_gpu_package () { echo "################################################################################" echo "" - # manylinux2014 is specified, bc manylinux1 does not support aarch64 - # See https://github.com/pypa/manylinux - local plat_name="manylinux2014_${MACHINE_NAME}" - - echo "[BUILD] Checking arch_list = ${arch_list}" - echo "[BUILD] Checking build_args:" - echo "${build_args[@]}" - - # shellcheck disable=SC2155 - local core=$(lscpu | grep "Core(s)" | awk '{print $NF}') && echo "core = ${core}" || echo "core not found" - # shellcheck disable=SC2155 - local sockets=$(lscpu | grep "Socket(s)" | awk '{print $NF}') && echo "sockets = ${sockets}" || echo "sockets not found" - local re='^[0-9]+$' - local run_multicore="" - if [[ $core =~ $re && $sockets =~ $re ]] ; then - local n_core=$((core * sockets)) - local run_multicore=" -j ${n_core}" - fi - # Distribute Python extensions as wheels on Linux echo "[BUILD] Building FBGEMM-GPU wheel (VARIANT=${fbgemm_variant}) ..." # shellcheck disable=SC2086 @@ -358,7 +404,7 @@ build_fbgemm_gpu_package () { python setup.py "${run_multicore}" bdist_wheel \ --package_name="${package_name}" \ --python-tag="${python_tag}" \ - --plat-name="${plat_name}" \ + --plat-name="${python_plat_name}" \ --verbose \ "${build_args[@]}" @@ -410,7 +456,9 @@ build_fbgemm_gpu_install () { echo "[BUILD] Building + installing FBGEMM-GPU (VARIANT=${fbgemm_variant}) ..." # shellcheck disable=SC2086 print_exec conda run --no-capture-output ${env_prefix} \ - python setup.py install "${build_args[@]}" + python setup.py "${run_multicore}" install \ + --verbose \ + "${build_args[@]}" # Run checks on the built libraries (run_fbgemm_gpu_postbuild_checks "${fbgemm_variant}") || return 1 @@ -460,7 +508,9 @@ build_fbgemm_gpu_develop () { echo "[BUILD] Building (develop) FBGEMM-GPU (VARIANT=${fbgemm_variant}) ..." # shellcheck disable=SC2086 print_exec conda run --no-capture-output ${env_prefix} \ - python setup.py build develop "${build_args[@]}" + python setup.py "${run_multicore}" build develop \ + --verbose \ + "${build_args[@]}" # Run checks on the built libraries (run_fbgemm_gpu_postbuild_checks "${fbgemm_variant}") || return 1 diff --git a/fbgemm_gpu/docs/src/fbgemm_gpu-development/BuildInstructions.rst b/fbgemm_gpu/docs/src/fbgemm_gpu-development/BuildInstructions.rst index 5c334e9f9..5b5084cdc 100644 --- a/fbgemm_gpu/docs/src/fbgemm_gpu-development/BuildInstructions.rst +++ b/fbgemm_gpu/docs/src/fbgemm_gpu-development/BuildInstructions.rst @@ -380,6 +380,33 @@ build cache: python setup.py clean +Set Wheel Build Variables +~~~~~~~~~~~~~~~~~~~~~~~~~ + +When building out the Python wheel, the package name, Python version tag, and +Python platform name must first be properly set: + +.. code:: sh + + # Set the package name depending on the build variant + export package_name=fbgemm_gpu_{cpu, cuda, rocm} + + # Set the Python version tag. It should follow the convention `py`, + # e.g. Python 3.12 -> py312 + export python_tag=py312 + + # Determine the processor architecture + export ARCH=$(uname -m) + + # Set the Python platform name for the Linux case + export python_plat_name="manylinux2014_${ARCH}" + # For the macOS (x86_64) case + export python_plat_name="macosx_10_9_${ARCH}" + # For the macOS (arm64) case + export python_plat_name="macosx_11_0_${ARCH}" + # For the Windows case + export python_plat_name="win_${ARCH}" + .. _fbgemm-gpu.build.process.cpu: CPU-Only Build @@ -391,20 +418,16 @@ For CPU-only builds, the ``--cpu_only`` flag needs to be specified. # !! Run in fbgemm_gpu/ directory inside the Conda environment !! - export ARCH=$(uname -m) - - python_tag=py310 - package_name=fbgemm_gpu_cpu - # Build the wheel artifact only python setup.py bdist_wheel \ - --package_name="${package_name}" \ --package_variant=cpu \ + --package_name="${package_name}" \ --python-tag="${python_tag}" \ - --plat-name="manylinux1_${ARCH}" + --plat-name="${python_plat_name}" # Build and install the library into the Conda environment - python setup.py install --package_variant=cpu + python setup.py install \ + --package_variant=cpu .. _fbgemm-gpu.build.process.cuda: @@ -419,9 +442,6 @@ CUDA device, however, is not required for building the package. # !! Run in fbgemm_gpu/ directory inside the Conda environment !! - # Determine the processor architecture - export ARCH=$(uname -m) - # [OPTIONAL] Specify the CUDA installation paths # This may be required if CMake is unable to find nvcc export CUDACXX=/path/to/nvcc @@ -437,10 +457,6 @@ CUDA device, however, is not required for building the package. # Specify NVML path export NVML_LIB_PATH=/path/to/libnvidia-ml.so - # Update to reflect the version of Python in the Conda environment - python_tag=py310 - package_name=fbgemm_gpu - # Build for SM70/80 (V100/A100 GPU); update as needed # If not specified, only the CUDA architecture supported by current system will be targeted # If not specified and no CUDA device is present either, all CUDA architectures will be targeted @@ -452,10 +468,10 @@ CUDA device, however, is not required for building the package. # Build the wheel artifact only python setup.py bdist_wheel \ - --package_name="${package_name}" \ --package_variant=cuda \ + --package_name="${package_name}" \ --python-tag="${python_tag}" \ - --plat-name="manylinux1_${ARCH}" \ + --plat-name="${python_plat_name}" \ --nvml_lib_path=${NVML_LIB_PATH} \ -DTORCH_CUDA_ARCH_LIST="${cuda_arch_list}" @@ -478,22 +494,18 @@ the package. # !! Run in fbgemm_gpu/ directory inside the Conda environment !! - export ARCH=$(uname -m) export ROCM_PATH=/path/to/rocm # Build for the target architecture of the ROCm device installed on the machine (e.g. 'gfx906;gfx908;gfx90a') # See https://wiki.gentoo.org/wiki/ROCm for list export PYTORCH_ROCM_ARCH=$(${ROCM_PATH}/bin/rocminfo | grep -o -m 1 'gfx.*') - python_tag=py310 - package_name=fbgemm_gpu_rocm - # Build the wheel artifact only python setup.py bdist_wheel \ - --package_name="${package_name}" \ --package_variant=rocm \ + --package_name="${package_name}" \ --python-tag="${python_tag}" \ - --plat-name="manylinux1_${ARCH}" \ + --plat-name="${python_plat_name}" \ -DHIP_ROOT_DIR="${ROCM_PATH}" \ -DCMAKE_C_FLAGS="-DTORCH_USE_HIP_DSA" \ -DCMAKE_CXX_FLAGS="-DTORCH_USE_HIP_DSA" diff --git a/fbgemm_gpu/docs/src/general/Documentation.rst b/fbgemm_gpu/docs/src/general/Documentation.rst deleted file mode 100644 index 1b7835bd8..000000000 --- a/fbgemm_gpu/docs/src/general/Documentation.rst +++ /dev/null @@ -1,392 +0,0 @@ -Documentation -============= - -Both FBGEMM and FBGEMM_GPU provide extensive comments in its source files, which -serve as the most authoritative and up-to-date documentation available for the -two libraries. - - -.. _fbgemm-gpu.docs.build: - -Building the API Documentation ------------------------------- - -**Note:** The most up-to-date documentation build instructions are embedded in -a set of scripts bundled in the FBGEMM repo under -`setup_env.bash `_. - -The general steps for building the FBGEMM and FBGEMM_GPU documentation are as -follows: - -#. Set up an isolated build environment. -#. Build FBGEMM_GPU (CPU variant). -#. Set up the documentation toolchain. -#. Run documentation build scripts. - -Set Up Build Environment -~~~~~~~~~~~~~~~~~~~~~~~~ - -Follow the instructions for setting up the Conda environment at -:ref:`fbgemm-gpu.build.setup.env`. - -Build FBGEMM_GPU -~~~~~~~~~~~~~~~~ - -A build pass of **FBGEMM_GPU** is required for the documentation to be built -correctly. Follow the instructions in -:ref:`fbgemm-gpu.build.setup.tools.install`, followed by -:ref:`fbgemm-gpu.build.process.cpu`, to build FBGEMM_GPU (CPU variant). - -Set Up the Documentation Toolchain -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: sh - - # !! Run inside the Conda environment !! - - # From the /fbgemm_gpu/ directory - cd docs - - # Install Sphinx and other docs tools - pip install -r requirements.txt - - # Install Doxygen and Make - conda install -c conda-forge -y doxygen graphviz make - -Build the Documentation -~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: sh - - # Generate the C++ documentation, the Python documentation, and assemble - # together - make clean doxygen html - -After the build completes, view the generated documentation: - -.. code:: sh - - sphinx-serve -b build - -Deployment Preview -~~~~~~~~~~~~~~~~~~ - -As a PyTorch project, a preview of the FBGEMM and FBGEMM_GPU documentation will -be automatically built and deployed by `Netlify `__ -when pull requests are made. When the build completes, the deployment preview -can be found at: - -.. code:: sh - - https://deploy-preview->--pytorch-fbgemm-docs.netlify.app/ - - -General Documentation Guidelines --------------------------------- - -When new public API methods are added, they should be accompanied by sufficient -documentation. Here are some guidelines for documenting FBGEMM and FBGEMM_GPU -code: - -* Code by itself is not documentation! Put yourself in the shoes of new - developers who has to understand what your code does, and make their lives - easier. - -* Documentation should be added for any and all public API methods. - -* Don't leave docstring-writing as a separate task. - -* Write docstrings together with the code. - -* At a very minimum, add: - - * A description of the method. - * A description for each argument that can be passed into the method. - * A description of the method's return value. - -* Add usage examples, links to other methods, and method invocation limitations. - - -Adding Documentation to Python Code ------------------------------------ - -Documentation for Python is provided through docstrings and generated using -`Sphinx `__. Please reference the -`Google-style Python docstrings -`__ -guide for docstring formatting examples. - -Follow these instructions to document, generate, and publish a new Python -docstring: - -#. Add the docstring directly under the name of the target method. At a very - minimum, please add descriptions of: - - * The method's functional behavior - * The arguments, as denoted by the ``Args`` section - * The return value, as denoted by the ``Returns`` section - * The exceptions that can be thrown (if applicable), as denoted by the - ``Raises`` section - - Other sections such as ``Todo``, ``Note``, and ``Example`` should be added - as needed. - - Here is an example Python docstring: - - .. literalinclude:: ../../../fbgemm_gpu/docs/examples.py - :language: python - :start-after: fbgemm-gpu.python.docs.examples.docstring.start - :end-before: fbgemm-gpu.python.docs.examples.docstring.end - -#. On the Sphinx documentation side, add an ``autofunction`` directive to the - corresponding ``.rst`` file. If an ``.rst`` file for the corresponding - Python source file does not exist, create a new one by the same name as the - Python source file. Using the above example: - - .. code:: rst - - .. autofunction:: fbgemm_gpu.docs.examples.example_method - -#. Make sure the ``.rst`` file is included in to the ``toctree`` in - ``index.rst`` (e.g. :ref:`fbgemm-gpu.toc.api.python`). - -#. Verify the changes by building the docs locally with - :ref:`fbgemm-gpu.docs.build` or submitting a PR for a Netlify preview. - ------------- - -The Python docstring example above generates the following HTML output: - -.. autofunction:: fbgemm_gpu.docs.examples.example_method - ------------- - - -Adding Documentation to C++ Code --------------------------------- - -Documentation for C++ is provided through -`Javadoc-style comments `__ -and generated using Sphinx, `Doxygen `__, and -`Breathe `__. - -Documentation is kept in header files with the ``.h`` extension as well as in -``.cpp``, ``cu``, and ``cuh`` files. In these files, everything between -``#ifndef DOXYGEN_THIS_WILL_BE_SKIPPED`` and ``#endif`` will be hidden from the -HTML output. When you add descriptionss to a function, make sure that the -``#ifndef`` and ``#endif`` are configured correctly. - -Follow these instructions to document, generate, and publish a new C++ -docstring: - -#. API methods are grouped together by group tags for better organization in - Sphinx. If a desired method group for the target method is not defined yet, - define it near the top of the relevant header file with the ``@defgroup`` - command: - - .. literalinclude:: ../../../src/docs/example_code.cpp - :language: cpp - :start-after: fbgemm-gpu.cpp.docs.examples.defgroup.start - :end-before: fbgemm-gpu.cpp.docs.examples.defgroup.end - -#. Add the docstring directly above the target method's declaration. At a very - minimum, please add descriptions of: - - * The method's functional behavior - * The type parameters, as denoted by the ``@tparam`` tag - * The arguments, as denoted by the ``@param`` tag - * The return value, as denoted by the ``@return`` tag - * The exceptions that can be thrown (if applicable), as denoted by the - ``@throw`` tag - - Other commands such as ``@note``, ``@warning``, and ``@see`` should be added - as needed. - - Here is an example C++ docstring: - - .. literalinclude:: ../../../src/docs/example_code.cpp - :language: cpp - :start-after: fbgemm-gpu.cpp.docs.examples.docstring.start - :end-before: fbgemm-gpu.cpp.docs.examples.docstring.end - -#. On the Sphinx documentation side, add a ``doxygengroup`` directive to the - corresponding ``.rst`` file. If an ``.rst`` file for the corresponding - header file does not exist, create a new one by the same name as the header - file. Using the above example: - - .. code:: rst - - .. doxygengroup:: example-method-group - :content-only: - -#. Make sure the ``.rst`` file is included in to the ``toctree`` in - ``index.rst`` (e.g. :ref:`fbgemm-gpu.toc.api.cpp`). - -#. The C++ source header file needs to be in one of the directories listed in - the ``INPUT`` parameter in ``Doxygen.ini``. In general, this has already - been taken care of, but if it's in a directory not listed, be sure to - append the directory path to the parameter. - -#. Verify the changes by building the docs locally with - :ref:`fbgemm-gpu.docs.build` or submitting a PR for a Netlify preview. - ------------- - -The Doxygen example above generates the following HTML output: - -.. doxygengroup:: example-method-group - :content-only: - ------------- - - -Sphinx Documentation Pointers ------------------------------ - -References Other Sections of the Documentation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To reference other sections in the documentation, an anchor must first be -created above the target section: - -.. code:: rst - - .. _fbgemm-gpu.example.reference: - - Example Section Header - ---------------------- - - NOTES: - - #. The reference anchor must start with an underscore, i.e. ``_``. - - #. !! There must be an empty line between the anchor and its target !! - -The anchor can then be referenced elsewhere in the docs: - -.. code:: rst - - Referencing the section :ref:`fbgemm-gpu.example.reference` from - another page in the docs. - - Referencing the section with - :ref:`custom text ` from another page - in the docs. - - Note that the prefix underscore is not needed when referencing the anchor. - - -Referencing the Source Code -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The ``literalinclude`` directive can be used to display the source code inside a -Sphinx document. To display the full file content: - -.. code:: rst - - .. literalinclude:: relative/path/from/this/rst/file/to/the/source.txt - - -To display only a section of the file, a pair of unique tags must first be added -to the target source file, as comments with the tag string enclosed in brackets. - -For Python source files: - -.. code:: python - - # [example.tag.start] - - # ... code section that will be referenced ... - - # [example.tag.end] - -For C++ source files: - -.. code:: cpp - - /// @skipline [example.tag.start] - - /// ... code section that will be referenced ... - - /// @skipline [example.tag.end] - -The tags then need to be supplied to the ``literalinclude`` directive: - -.. code:: rst - - .. literalinclude:: relative/path/from/this/rst/file/to/the/source.cpp - :language: cpp - :start-after: example.tag.start - :end-before: example.tag.end - -See the Sphinx documentation -`here `__ -for more information. - - -Adding LaTeX -~~~~~~~~~~~~ - -Math expressions with LaTeX can be added inline to Sphinx docs using the -``math`` directive: - -.. code:: rst - - Example text: :math:`k_{n+1} = n^2 + k_n^2 - k_{n-1}` - -The above example will be rendered as: :math:`k_{n+1} = n^2 + k_n^2 - k_{n-1}`. - -Math expressinos can also be inserted as a code block: - -.. code:: rst - - .. math:: - - \int_a^bu \frac{d^2v}{dx^2} \,dx - = \left.u \frac{dv}{dx} \right|_a^b - - \int_a^b \frac{du}{dx} \frac{dv}{dx} \,dx - -.. math:: - - \int_a^bu \frac{d^2v}{dx^2} \,dx - = \left.u \frac{dv}{dx} \right|_a^b - - \int_a^b \frac{du}{dx} \frac{dv}{dx} \,dx - -See the Sphinx documentation -`here `__ -and `here `__ -for more information. - - -Adding Graphs -~~~~~~~~~~~~~ - -Graphs can be generated in Sphinx using ``graphviz`` directive. Graph -descriptions can be added inside a block: - -.. code:: rst - - .. graphviz:: - - digraph example { - "From" -> "To"; - } - -.. graphviz:: - - digraph example { - "From" -> "To"; - } - -Alternatively, they can be imported from an external ``.dot`` file: - -.. code:: rst - - .. graphviz:: ExampleGraph.dot - -.. graphviz:: ExampleGraph.dot - -See the -`Sphinx `__ -and `Graphviz `__ documentation more -information. diff --git a/fbgemm_gpu/docs/src/general/documentation/Cpp.rst b/fbgemm_gpu/docs/src/general/documentation/Cpp.rst new file mode 100644 index 000000000..0f919f225 --- /dev/null +++ b/fbgemm_gpu/docs/src/general/documentation/Cpp.rst @@ -0,0 +1,76 @@ +.. _general.docs.add.cpp: + +Adding Documentation to C++ Code +-------------------------------- + +Documentation for C++ is provided through +`Javadoc-style comments `__ +and generated using Sphinx, `Doxygen `__, and +`Breathe `__. + +Documentation is kept in header files with the ``.h`` extension as well as in +``.cpp``, ``cu``, and ``cuh`` files. In these files, everything between +``#ifndef DOXYGEN_THIS_WILL_BE_SKIPPED`` and ``#endif`` will be hidden from the +HTML output. When you add descriptionss to a function, make sure that the +``#ifndef`` and ``#endif`` are configured correctly. + +Follow these instructions to document, generate, and publish a new C++ +docstring: + +#. API methods are grouped together by group tags for better organization in + Sphinx. If a desired method group for the target method is not defined yet, + define it near the top of the relevant header file with the ``@defgroup`` + command: + + .. literalinclude:: ../../../../src/docs/example_code.cpp + :language: cpp + :start-after: fbgemm-gpu.cpp.docs.examples.defgroup.start + :end-before: fbgemm-gpu.cpp.docs.examples.defgroup.end + +#. Add the docstring directly above the target method's declaration. At a very + minimum, please add descriptions of: + + * The method's functional behavior + * The type parameters, as denoted by the ``@tparam`` tag + * The arguments, as denoted by the ``@param`` tag + * The return value, as denoted by the ``@return`` tag + * The exceptions that can be thrown (if applicable), as denoted by the + ``@throw`` tag + + Other commands such as ``@note``, ``@warning``, and ``@see`` should be added + as needed. + + Here is an example C++ docstring: + + .. literalinclude:: ../../../../src/docs/example_code.cpp + :language: cpp + :start-after: fbgemm-gpu.cpp.docs.examples.docstring.start + :end-before: fbgemm-gpu.cpp.docs.examples.docstring.end + +#. On the Sphinx documentation side, add a ``doxygengroup`` directive to the + corresponding ``.rst`` file. If an ``.rst`` file for the corresponding + header file does not exist, create a new one by the same name as the header + file. Using the above example: + + .. code:: rst + + .. doxygengroup:: example-method-group + :content-only: + +#. Make sure the ``.rst`` file is included in to the ``toctree`` in + ``index.rst`` (e.g. :ref:`fbgemm-gpu.toc.api.cpp`). + +#. The C++ source header file needs to be in one of the directories listed in + the ``INPUT`` parameter in ``Doxygen.ini``. In general, this has already + been taken care of, but if it's in a directory not listed, be sure to + append the directory path to the parameter. + +#. Verify the changes by building the docs locally with + :ref:`general.docs.build` or submitting a PR for a Netlify preview. + +------------ + +The Doxygen example above generates the following HTML output: + +.. doxygengroup:: example-method-group + :content-only: diff --git a/fbgemm_gpu/docs/src/general/ExampleGraph.dot b/fbgemm_gpu/docs/src/general/documentation/ExampleGraph.dot similarity index 100% rename from fbgemm_gpu/docs/src/general/ExampleGraph.dot rename to fbgemm_gpu/docs/src/general/documentation/ExampleGraph.dot diff --git a/fbgemm_gpu/docs/src/general/documentation/Overview.rst b/fbgemm_gpu/docs/src/general/documentation/Overview.rst new file mode 100644 index 000000000..041db2ad4 --- /dev/null +++ b/fbgemm_gpu/docs/src/general/documentation/Overview.rst @@ -0,0 +1,148 @@ +Documentation +============= + +Both FBGEMM and FBGEMM_GPU provide extensive comments in its source files, which +serve as the most authoritative and up-to-date documentation available for the +two libraries. + + +General Documentation Guidelines +-------------------------------- + +When new public API methods are added, they should be accompanied by sufficient +documentation. Here are some guidelines for documenting FBGEMM and FBGEMM_GPU +code: + +* **Code by itself is not documentation!** Put yourself in the shoes of new + developers who has to understand what your code does, and make their lives + easier. + +* Documentation should be added for any and all public API methods. + +* Don't leave documentation as a separate task. Instead, write docstrings + together with the code. + +* At a very minimum, add: + + * A description of the method. + * A description of the parameters and arguments that can be passed to the method. + * A description of the method's return value. + * Usage examples, links to other methods, and method invocation limitations. + + +Specific Documentation Guides +----------------------------- + +.. toctree:: + :maxdepth: 1 + + Cpp.rst + Python.rst + Sphinx.rst + + +.. _general.docs.build: + + +Building the Documentation +-------------------------- + +**Note:** The most up-to-date documentation build instructions are embedded in +a set of scripts bundled in the FBGEMM repo under +`setup_env.bash `_. + +The general steps for building the FBGEMM and FBGEMM_GPU documentation are as +follows: + +#. Set up an isolated build environment. +#. Build FBGEMM_GPU (CPU variant). +#. Set up the documentation toolchain. +#. Run documentation build scripts. + +Set Up Build Environment +~~~~~~~~~~~~~~~~~~~~~~~~ + +Follow the instructions for setting up the Conda environment at +:ref:`fbgemm-gpu.build.setup.env`. + +Build FBGEMM_GPU +~~~~~~~~~~~~~~~~ + +A build pass of **FBGEMM_GPU** is required for the documentation to be built +correctly. Follow the instructions in +:ref:`fbgemm-gpu.build.setup.tools.install`, followed by +:ref:`fbgemm-gpu.build.process.cpu`, to build FBGEMM_GPU (CPU variant). + +Set Up the Documentation Toolchain +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: sh + + # !! Run inside the Conda environment !! + + # From the /fbgemm_gpu/ directory + cd docs + + # Install Sphinx and other Python packages + pip install -r requirements.txt + + # Install Doxygen and and other tools + conda install -c conda-forge -y doxygen graphviz make + +Build the Documentation +~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: sh + + # Generate the C++ documentation, the Python documentation, and assemble + # together + make clean doxygen html + +After the build completes, view the generated documentation: + +.. code:: sh + + sphinx-serve -b build + + +Linting the Documentation +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The same command used for building can be used for linting, by prepending the +``SPHINX_LINT`` flag: + +.. code:: sh + + SPHINX_LINT=1 make clean doxygen html + +For technical reasons, running a Sphinx build with linting turned on will cause +the documentation to be assembled incorrectly, which is why linting is invoked +separately from the build. + +Occasionally, unresolved references might show up while linting, which have the +following error signature: + +.. code:: sh + + /opt/build/repo/fbgemm_gpu/docs/docstring of torch._ops.fbgemm.PyCapsule.jagged_2d_to_dense:1:py:class reference target not found: Tensor + +If these errors turn out to be false negatives, they can be silenced by being +added into the ``nitpick.ignore`` file (in the same directory as Sphinx +``conf.py``): + +.. code:: yaml + + # Add in `{domain} {reference}` format, with space in between. + py:class Tensor + + +Deployment Preview +~~~~~~~~~~~~~~~~~~ + +A preview of the FBGEMM and FBGEMM_GPU documentation will be automatically built +and deployed by `Netlify `__ when pull requests are +made. When the build completes, the deployment preview can be found at: + +.. code:: sh + + https://deploy-preview-{PR NUMBER}--pytorch-fbgemm-docs.netlify.app/ diff --git a/fbgemm_gpu/docs/src/general/documentation/Python.rst b/fbgemm_gpu/docs/src/general/documentation/Python.rst new file mode 100644 index 000000000..727c9646c --- /dev/null +++ b/fbgemm_gpu/docs/src/general/documentation/Python.rst @@ -0,0 +1,89 @@ +.. _general.docs.add.python: + +Adding Documentation to Python Code +----------------------------------- + +Documentation for Python is provided through docstrings and generated using +`Sphinx `__. Please reference the +`Google-style Python docstrings +`__ +guide for docstring formatting examples. + +Follow these instructions to document, generate, and publish a new Python +docstring: + +#. Add the docstring directly under the name of the target method. At a very + minimum, please add descriptions of: + + * The method's functional behavior + * The arguments, as denoted by the ``Args`` section + * The return value, as denoted by the ``Returns`` section + * The exceptions that can be thrown (if applicable), as denoted by the + ``Raises`` section + + Other sections such as ``Todo``, ``Note``, and ``Example`` should be added + as needed. + + Here is an example Python docstring: + + .. literalinclude:: ../../../../fbgemm_gpu/docs/examples.py + :language: python + :start-after: fbgemm-gpu.python.docs.examples.docstring.start + :end-before: fbgemm-gpu.python.docs.examples.docstring.end + +#. On the Sphinx documentation side, add an ``autofunction`` directive to the + corresponding ``.rst`` file. If an ``.rst`` file for the corresponding + Python source file does not exist, create a new one by the same name as the + Python source file. Using the above example: + + .. code:: rst + + .. autofunction:: fbgemm_gpu.docs.examples.example_method + +#. Make sure the ``.rst`` file is included in to the ``toctree`` in + ``index.rst`` (e.g. :ref:`fbgemm-gpu.toc.api.python`). + +#. Verify the changes by building the docs locally with + :ref:`general.docs.build` or submitting a PR for a Netlify preview. + +------------ + +The Python docstring example above generates the following HTML output: + +.. autofunction:: fbgemm_gpu.docs.examples.example_method + +------------ + + +.. _general.docs.add.autogen: + +Adding Documentation to Auto-Generated Python Code +-------------------------------------------------- + +Many FBGEMM_GPU Python API methods are auto-generated through PyTorch during the +build process, and require docstrings to be attached after the fact. Follow +these instructions to document auto-generated Python methods: + +#. If needed, create a Python file under ``fbgemm_gpu/fbgemm_gpu/docs`` in the + repo. + +#. In the Python file, use the provided helper methods in + ``fbgemm_gpu.docs.common`` to add attach a docstring to the target + auto-generated method by method name. Here is an example from the codebase: + + .. literalinclude:: ../../../../fbgemm_gpu/docs/jagged_tensor_ops.py + :language: python + :start-after: fbgemm-gpu.autogen.docs.examples.docstring.start + :end-before: fbgemm-gpu.autogen.docs.examples.docstring.end + +#. If not already present, append the Python file to the imports list in + ``fbgemm_gpu/fbgemm_gpu/docs/__init__.py``. This will force the ad-hoc + documentation to be loaded on ``fbgemm_gpu`` module load. For example: + + .. code:: rst + + from . import the_new_doc_module + + +#. Follow the remaining steps in :ref:`general.docs.add.python` to render the + docstring in the documentation. diff --git a/fbgemm_gpu/docs/src/general/documentation/Sphinx.rst b/fbgemm_gpu/docs/src/general/documentation/Sphinx.rst new file mode 100644 index 000000000..7251b07f1 --- /dev/null +++ b/fbgemm_gpu/docs/src/general/documentation/Sphinx.rst @@ -0,0 +1,152 @@ +.. _general.docs.add.cpp: + +Sphinx Documentation Pointers +----------------------------- + +References Other Sections of the Documentation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To reference other sections in the documentation, an anchor must first be +created above the target section: + +.. code:: rst + + .. _docs.example.reference: + + Example Section Header + ---------------------- + + NOTES: + + #. The reference anchor must start with an underscore, i.e. ``_``. + + #. !! There must be an empty line between the anchor and its target !! + +The anchor can then be referenced elsewhere in the docs: + +.. code:: rst + + Referencing the section :ref:`docs.example.reference` from + another page in the docs. + + Referencing the section with + :ref:`custom text ` from another page + in the docs. + + Note that the prefix underscore is not needed when referencing the anchor. + + +Referencing the Source Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``literalinclude`` directive can be used to display the source code inside a +Sphinx document. To display the full file content: + +.. code:: rst + + .. literalinclude:: relative/path/from/this/rst/file/to/the/source.txt + + +To display only a section of the file, a pair of unique tags must first be added +to the target source file, as comments with the tag string enclosed in brackets. + +For Python source files: + +.. code:: python + + # [example.tag.start] + + # ... code section that will be referenced ... + + # [example.tag.end] + +For C++ source files: + +.. code:: cpp + + /// @skipline [example.tag.start] + + /// ... code section that will be referenced ... + + /// @skipline [example.tag.end] + +The tags then need to be supplied to the ``literalinclude`` directive: + +.. code:: rst + + .. literalinclude:: relative/path/from/this/rst/file/to/the/source.cpp + :language: cpp + :start-after: example.tag.start + :end-before: example.tag.end + +See the Sphinx documentation +`here `__ +for more information. + + +Adding LaTeX +~~~~~~~~~~~~ + +Math expressions with LaTeX can be added inline to Sphinx docs using the +``math`` directive: + +.. code:: rst + + Example text: :math:`k_{n+1} = n^2 + k_n^2 - k_{n-1}` + +The above example will be rendered as: :math:`k_{n+1} = n^2 + k_n^2 - k_{n-1}`. + +Math expressinos can also be inserted as a code block: + +.. code:: rst + + .. math:: + + \int_a^bu \frac{d^2v}{dx^2} \,dx + = \left.u \frac{dv}{dx} \right|_a^b + - \int_a^b \frac{du}{dx} \frac{dv}{dx} \,dx + +.. math:: + + \int_a^bu \frac{d^2v}{dx^2} \,dx + = \left.u \frac{dv}{dx} \right|_a^b + - \int_a^b \frac{du}{dx} \frac{dv}{dx} \,dx + +See the Sphinx documentation +`here `__ +and `here `__ +for more information. + + +Adding Graphs +~~~~~~~~~~~~~ + +Graphs can be generated in Sphinx using ``graphviz`` directive. Graph +descriptions can be added inside a block: + +.. code:: rst + + .. graphviz:: + + digraph example { + "From" -> "To"; + } + +.. graphviz:: + + digraph example { + "From" -> "To"; + } + +Alternatively, they can be imported from an external ``.dot`` file: + +.. code:: rst + + .. graphviz:: ExampleGraph.dot + +.. graphviz:: ExampleGraph.dot + +See the +`Sphinx `__ +and `Graphviz `__ documentation more +information. diff --git a/fbgemm_gpu/docs/src/index.rst b/fbgemm_gpu/docs/src/index.rst index 189be61da..83e1bc58c 100644 --- a/fbgemm_gpu/docs/src/index.rst +++ b/fbgemm_gpu/docs/src/index.rst @@ -27,7 +27,7 @@ Table of Contents :caption: General Info general/Contributing.rst - general/Documentation.rst + general/documentation/Overview.rst general/ContactUs.rst general/License.rst diff --git a/fbgemm_gpu/docs/src/nitpick.ignore b/fbgemm_gpu/docs/src/nitpick.ignore index 32cd29928..061ad7281 100644 --- a/fbgemm_gpu/docs/src/nitpick.ignore +++ b/fbgemm_gpu/docs/src/nitpick.ignore @@ -1,3 +1,10 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + cpp:identifier at cpp:identifier at::Device cpp:identifier at::SymInt diff --git a/fbgemm_gpu/fbgemm_gpu/docs/jagged_tensor_ops.py b/fbgemm_gpu/fbgemm_gpu/docs/jagged_tensor_ops.py index 3b23191e4..61ce6d2b4 100644 --- a/fbgemm_gpu/fbgemm_gpu/docs/jagged_tensor_ops.py +++ b/fbgemm_gpu/fbgemm_gpu/docs/jagged_tensor_ops.py @@ -4,6 +4,7 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. +# [fbgemm-gpu.autogen.docs.examples.docstring.start] import torch from .common import add_docs @@ -39,6 +40,7 @@ """, ) +# [fbgemm-gpu.autogen.docs.examples.docstring.end] add_docs( torch.ops.fbgemm.jagged_1d_to_dense,