1 Unified Backend {#unifiedbackend}
8 The Unified backend was introduced in ArrayFire with version 3.2.
9 While this is not an independent backend, it allows the user to switch between
10 the different ArrayFire backends (CPU, CUDA, oneAPI and OpenCL) at runtime.
12 # Compiling with Unified
14 The steps to compile with the unified backend are the same as compiling with
15 any of the other backends.
16 The only change being that the executable needs to be linked with the __af__
17 library (`libaf.so` (Linux), `libaf.dylib` (OSX), `af.lib` (Windows)).
19 Check the Using with [Linux](\ref using_on_linux), [OSX](\ref using_on_osx),
20 [Windows](\ref using_on_windows) for more details.
22 To use with CMake, use the __ArrayFire_Unified_LIBRARIES__ variable.
24 # Using the Unified Backend
26 The Unified backend will try to dynamically load the backend libraries. The
27 priority of backends is __CUDA -> oneAPI -> OpenCL -> CPU__
29 The most important aspect to note here is that all the libraries the ArrayFire
30 libs depend on need to be in the environment paths
32 * `LD_LIBRARY_PATH` -> Linux, Unix, OSX
33 * `DYLD_LIBRARY_PATH` -> OSX
36 If any of the libs are missing, then the library will fail to load and the
37 backend will be marked as unavailable.
39 Optionally, The ArrayFire libs may be present in `AF_PATH` or `AF_BUILD_PATH`
40 environment variables if the path is not in the system paths. These are
41 treated as fallback paths in case the files are not found in the system paths.
42 However, all the other upstream libraries for ArrayFire libs must be present
43 in the system path variables shown above.
47 The af_backend enum stores the possible backends.
48 To select a backend, call the af::setBackend function as shown below.
50 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c}
51 af::setBackend(AF_BACKEND_CUDA); // Sets CUDA as current backend
52 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
54 To get the count of the number of backends available (the number of `libaf*`
55 backend libraries loaded successfully), call the af::getBackendCount function.
59 This example is shortened form of [basic.cpp](\ref unified/basic.cpp).
61 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c}
62 #include <arrayfire.h>
67 af_print(af::randu(5, 4));
73 printf("Trying CPU Backend\n");
74 af::setBackend(AF_BACKEND_CPU);
76 } catch (af::exception& e) {
77 printf("Caught exception when trying CPU backend\n");
78 fprintf(stderr, "%s\n", e.what());
82 printf("Trying oneAPI Backend\n");
83 af::setBackend(AF_BACKEND_ONEAPI);
85 } catch (af::exception& e) {
86 printf("Caught exception when trying oneAPI backend\n");
87 fprintf(stderr, "%s\n", e.what());
91 printf("Trying CUDA Backend\n");
92 af::setBackend(AF_BACKEND_CUDA);
94 } catch (af::exception& e) {
95 printf("Caught exception when trying CUDA backend\n");
96 fprintf(stderr, "%s\n", e.what());
100 printf("Trying OpenCL Backend\n");
101 af::setBackend(AF_BACKEND_OPENCL);
103 } catch (af::exception& e) {
104 printf("Caught exception when trying OpenCL backend\n");
105 fprintf(stderr, "%s\n", e.what());
110 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
112 This output would be:
115 ArrayFire v3.9.0 (CPU, 64-bit Linux, build 23ee0650e)
116 [0] AMD: AMD Ryzen Threadripper PRO 3955WX 16-Cores af::randu(5, 4)
118 0.6010 0.5497 0.1583 0.3636
119 0.0278 0.2864 0.3712 0.4165
120 0.9806 0.3410 0.3543 0.5814
121 0.2126 0.7509 0.6450 0.8962
122 0.0655 0.4105 0.9675 0.3712
124 Trying oneAPI Backend
125 ArrayFire v3.9.0 (oneAPI, 64-bit Linux, build 23ee0650e)
126 [0] Intel(R) OpenCL: AMD Ryzen Threadripper PRO 3955WX 16-Cores , 128650 MB (fp64)
129 0.6010 0.5497 0.1583 0.3636
130 0.0278 0.2864 0.3712 0.4165
131 0.9806 0.3410 0.3543 0.5814
132 0.2126 0.7509 0.6450 0.8962
133 0.0655 0.4105 0.9675 0.3712
136 ArrayFire v3.9.0 (CUDA, 64-bit Linux, build 23ee0650e)
137 Platform: CUDA Runtime 12.2, Driver: 535.104.05
138 [0] NVIDIA RTX A5500, 22721 MB, CUDA Compute 8.6
139 -1- NVIDIA RTX A5500, 22719 MB, CUDA Compute 8.6
142 0.6010 0.5497 0.1583 0.3636
143 0.0278 0.2864 0.3712 0.4165
144 0.9806 0.3410 0.3543 0.5814
145 0.2126 0.7509 0.6450 0.8962
146 0.0655 0.4105 0.9675 0.3712
148 Trying OpenCL Backend
149 ArrayFire v3.9.0 (OpenCL, 64-bit Linux, build 23ee0650e)
150 [0] NVIDIA: NVIDIA RTX A5500, 22720 MB
151 -1- NVIDIA: NVIDIA RTX A5500, 22718 MB
152 -2- Intel(R) FPGA Emulation Platform for OpenCL(TM): Intel(R) FPGA Emulation Device, 128650 MB
153 -3- INTEL: AMD Ryzen Threadripper PRO 3955WX 16-Cores , 128650 MB
156 0.6010 0.5497 0.1583 0.3636
157 0.0278 0.2864 0.3712 0.4165
158 0.9806 0.3410 0.3543 0.5814
159 0.2126 0.7509 0.6450 0.8962
160 0.0655 0.4105 0.9675 0.3712
165 It is very easy to run into exceptions if you are not careful with the
166 switching of backends.
168 ### Don't: Do not use arrays between different backends
170 ArrayFire checks the input arrays to functions for mismatches with the active
171 backend. If an array created on one backend, but used when another backend is
172 set to active, an exception with code 503 (`AF_ERR_ARR_BKND_MISMATCH`) is
175 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c}
176 #include <arrayfire.h>
181 af::setBackend(AF_BACKEND_CUDA);
182 af::array A = af::randu(5, 5);
184 af::setBackend(AF_BACKEND_OPENCL);
185 af::array B = af::constant(10, 5, 5);
186 af::array C = af::matmul(A, B); // This will throw an exception
188 } catch (af::exception& e) {
189 fprintf(stderr, "%s\n", e.what());
194 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
196 ### Do: Use a naming scheme to track arrays and backends
198 We recommend that you use a technique to track the arrays on the backends. One
199 suggested technique would be to use a suffix of `_cpu`, `_cuda`, `_opencl`
200 with the array names. So an array created on the CUDA backend would be named
203 If you have not used the af::setBackend function anywhere in your code, then
204 you do not have to worry about this as all the arrays will be created on the
205 same default backend.
207 ### Don't: Do not use custom kernels (CUDA/OpenCL) with the Unified backend
209 This is another area that is a no go when using the Unified backend. It not
210 recommended that you use custom kernels with unified backend. This is mainly
211 becuase the Unified backend is meant to be ultra portable and should use only
212 ArrayFire and native CPU code.