Skip to content

How to Add a New Function to ArrayFire

pradeep edited this page Jul 15, 2021 · 10 revisions

Listed below are the necessary files inside the directory structure that you need to add or modify for implementing a new function in ArrayFire. We have an example function (exampleFunction) built into the library itself, which shows how a new developer might go about implementing a new function in ArrayFire. It demonstrates how the user-facing C/C++ API talks to each backend. You can use its existing files as a guide or as a starting point for your implementation (of course by making a copy of the files and then modifying them). Note, however, that you may need to add or modify other files, depending on the situation.

A quick layout is given below to serve as a quick reference on what files must be added and/or modified, and where they are located. Further below, a more detailed layout is given, which describes the purpose of each file and some important details to take into account when adding/modifying those files.

After you have added and modified all the necessary files for your function, you are welcome to submit a pull request to ArrayFire. Doing so will queue your changes for building and testing in our continuous integration pipeline (make sure that you have created tests indeed!), but at least one of us needs to review and approve your changes before merging them in.

Quick layout

include
 |__ af/<domain>.h
 |__ arrayfire.h

src
 |__ api
 |    |__ c
 |    |    |__ exampleFunction.cpp
 |    |    |__ CMakeLists.txt
 |    |
 |    |__ cpp
 |    |    |__ <domain>.cpp
 |    |    |__ CMakeLists.txt
 |    |
 |    |__ unified
 |         |__ <domain>.cpp
 |         |__ CMakeLists.txt
 |
 |__ backend
      |__ cpu
      |    |__ exampleFunction.[hpp|cpp]
      |    |__ kernel
      |    |    |__ exampleFunction.hpp
      |    |__ CMakeLists.txt
      |
      |__ cuda
      |    |__ exampleFunction.[hpp|cu]
      |    |__ kernel
      |    |    |__ exampleFunction.hpp
      |    |__ CMakeLists.txt
      |
      |__ opencl
           |__ exampleFunction.[hpp|cpp]
           |__ kernel
           |    |__ exampleFunction.hpp
           |    |__ exampleFunction.cl
           |__ CMakeLists.txt

test
 |__ exampleFunction.cpp

docs
 |__ details/<domain>.dox

CMakeModules - CMake Find scripts for ArrayFire dependencies

examples - Code examples using ArrayFire

Detailed Layout

Include

  • include/af/<domain>.h

    • Contains the C and C++ declarations of your new function
    • If you are working on a function that already belongs to an existing group such as image processing, statistics, etc., add your declarations to that group/domain. Otherwise, create a header and include it in include/arrayfire.h
    • Add both the C and C++ declarations for your new function here.
    • Prefix the C function name with af_.
    • If the C++ function has any arguments with default values, initialize those arguments here
    • Add the C and C++ function's documentation here (Doxygen style)
  • include/arrayfire.h

    • Contains the includes for the domain header files
    • Include your new af/<domain>.h header file here if you do create a new one

C API

  • src/api/c/exampleFunction.cpp

    • Contains the definition of the function's C API.
    • If arrayfire already has all the functions needed for this new function, try first to keep all your implementation code here rather than adding code to src/backend
  • src/api/c/CMakeLists.txt

    • Add your include/af/<domain>.h header and src/api/c/exampleFunction.cpp in their appropriate sections here

C++ API

  • src/api/cpp/<domain>.cpp

    • Contains the definition of the function's C++ API. Most of the time, all you essentially have to do here is call the C API function.
    • See the other C++ functions in the same <domain>.cpp file for examples
  • src/api/cpp/CMakeLists.txt (should already exist)

    • Add your <domain>.cpp file here

Unified Backend

  • src/api/unified/<domain>.cpp

    • Contains API delegation from unified level to C API level
    • See the other C++ functions in the same <domain>.cpp file for examples
  • src/api/unified/CMakeLists.txt (should already exist)

    • Add your <domain>.cpp file here

CPU Backend

  • src/backend/cpu/exampleFunction.[hpp|cpp]

    • Wrapper level for the CPU algorithm, which can call your own and/or other existing CPU kernels
    • You can write the whole implementation here if all the necessary kernels already exist
  • src/backend/cpu/kernel/exampleFunction.hpp

    • Contains the CPU-specific implementation of the algorithm here
  • src/backend/cpu/CMakeLists.txt (should already exist)

    • Add your exampleFunction.[hpp|cpp] and kernel/exampleFunction.hpp to their appropriate sections here

CUDA Backend

  • src/backend/cuda/exampleFunction.[hpp|cu]

    • Wrapper level for the CUDA algorithm, which can call your own and/or other existing CUDA kernels
    • You can write the whole implementation here if all the necessary kernels already exist
  • src/backend/cuda/kernel/exampleFunction.hpp

    • Contains the CUDA-specific implementation of the algorithm here
  • src/backend/cuda/CMakeLists.txt (should already exist)

    • Add your exampleFunction.[hpp|cu] and kernel/exampleFunction.hpp to their appropriate sections here

OpenCL Backend

  • src/backend/opencl/exampleFunction.[hpp|cpp]

    • C++ wrapper level for the OpenCL kernel wrappers, which can call your own and/or other existing OpenCL kernel wrappers
    • You can write the whole implementation here if all the necessary OpenCL kernel wrappers already exist
  • src/backend/opencl/kernel/exampleFunction.hpp

    • Contains the OpenCL kernel wrappers
    • Note that because of the nature of how OpenCL operates, this file does not actually link with the exampleFunction.cl file. Rather, this includes kernel_headers/exampleFunction.hpp, which contains the OpenCL kernel in the form of a runtime char array. This char array is passed to OpenCL API calls to dispatch the actual OpenCL kernel.
  • src/backend/opencl/kernel/exampleFunction.cl (OpenCL Kernel file)

    • Contains the actual OpenCL kernels
    • See the note above about how this file is "linked" with exampleFunction.hpp. To support the described scheme above, a header file (in kernel_headers/) is generated during the build process, which basically creates a char array object representation of this file.
  • src/backend/opencl/CMakeLists.txt (should already exist)

    • Add your exampleFunction.[hpp|cpp] and kernel/exampleFunction.hpp to their appropriate sections here

Tests

  • test/exampleFunction.cpp

    • Contains unit tests for the new function. Refer to the Writing unit tests section of the wiki for this part.
    • It is good practice to add a test for the documentation's code snippets here, to verify that the public-facing example indeed works
  • test/build/extern/af_test_data-src/exampleFunction/<test_data_name>.test

    • Test data files are fetched during CMake configure stage from arrayfire-data repository. Any changes to test data are to be raised as pull requests to the arrayfire-data repository. If such changes are done, then corresponding git hash needs to be updated in ArrayFire's test/CMakeLists.txt file.
    • Refer to the Unit test data format page to understand the format in which test data needs to be added to arrayfire-data repository. You can have multiple test files if needed.

Documentation

ArrayFire is documented using Doxygen. The goal with the documentation is to provide function information in the headers and via HTML pages.

  • docs/details/<domain>.dox
    • Contains the Doxygen markup for the domain's functions
    • Add your functions' brief and detailed descriptions here. Note that you can add references to code snippets here for demonstration purposes, which are actually displayed in the description when rendered. Ideally, they would be part of the test suite for the same function(s)
    • See existing documentation sections for examples