|
1 | 1 | <!doctype html> |
2 | 2 |
|
3 | 3 | <html> |
4 | | - <head> |
5 | | - <meta charset="utf-8"/> |
6 | | - <link rel="stylesheet" href="../../Static/css/reveal.css"/> |
7 | | - <link rel="stylesheet" href="../../Static/css/theme/white.css"/> |
8 | | - <link rel="stylesheet" href="../../Static/css/custom.css"/> |
9 | | - <link rel="stylesheet" href="../../Static/css/atom-one-light.css"/> |
10 | | - <script src="../../node_modules/reveal.js/dist/reveal.js" defer></script> |
11 | | - <script src="../../node_modules/reveal.js/dist/plugin/markdown.js" defer></script> |
12 | | - <script src="../../node_modules/reveal.js/dist/plugin/highlight.js" defer></script> |
13 | | - <script src="../../node_modules/reveal.js/dist/plugin/notes.js" defer></script> |
14 | | - <script src="../../js/plugins/merge-html.js" defer></script> |
15 | | - <script src="../../js/setup.js" defer></script> |
16 | | - </head> |
17 | | - <body> |
18 | | - <div class="reveal"> |
19 | | - <div class="slides"> |
20 | | - <!--Slide 1--> |
21 | | - <section class="hbox"> |
22 | | - <h2 style="text-transform: none;"> |
23 | | - oneAPI Math Library (oneMath) |
24 | | - </h2> |
25 | | - </section> |
26 | | - <!--Slide 2--> |
27 | | - <section class="hbox" data-markdown> |
28 | | - ## Learning Objectives |
29 | | - * Learn what the oneMath is and how it works |
30 | | - * Learn how to use GEMM APIs from oneMath with both USM and buffer memory models |
31 | | - </section> |
32 | | - <!--Slide 3--> |
33 | | - <section> |
34 | | - <div class="hbox" data-markdown> |
35 | | - ## Do you need to write your own kernels? |
36 | | - </div> |
37 | 4 |
|
38 | | - <div class="container" data-markdown> |
39 | | - * Many computationally intensive applications spend the most of their time in **common operations / algorithms** |
| 5 | +<head> |
| 6 | + <meta charset="utf-8" /> |
| 7 | + <link rel="stylesheet" href="../../Static/css/reveal.css" /> |
| 8 | + <link rel="stylesheet" href="../../Static/css/theme/white.css" /> |
| 9 | + <link rel="stylesheet" href="../../Static/css/custom.css" /> |
| 10 | + <link rel="stylesheet" href="../../Static/css/atom-one-light.css" /> |
| 11 | + <script src="../../node_modules/reveal.js/dist/reveal.js" defer></script> |
| 12 | + <script src="../../node_modules/reveal.js/dist/plugin/markdown.js" defer></script> |
| 13 | + <script src="../../node_modules/reveal.js/dist/plugin/highlight.js" defer></script> |
| 14 | + <script src="../../node_modules/reveal.js/dist/plugin/notes.js" defer></script> |
| 15 | + <script src="../../js/plugins/merge-html.js" defer></script> |
| 16 | + <script src="../../js/setup.js" defer></script> |
| 17 | +</head> |
| 18 | + |
| 19 | +<body> |
| 20 | + <div class="reveal"> |
| 21 | + <div class="slides"> |
| 22 | + <!--Slide 1--> |
| 23 | + <section class="hbox"> |
| 24 | + <h2 style="text-transform: none;"> |
| 25 | + oneAPI Math Library (oneMath) |
| 26 | + </h2> |
| 27 | + </section> |
| 28 | + <!--Slide 2--> |
| 29 | + <section class="hbox" data-markdown> |
| 30 | + ## Learning Objectives |
| 31 | + * Learn what the oneMath is and how it works |
| 32 | + * Learn how oneMath dispatches work to a backend at run time or compile time |
| 33 | + * Learn what GEMM is |
| 34 | + * Learn how to use the GEMM API from oneMath with the USM memory model |
| 35 | + </section> |
| 36 | + <!--Slide 3--> |
| 37 | + <section> |
| 38 | + <div class="hbox" data-markdown> |
| 39 | + ## Do you need to write your own kernels? |
| 40 | + </div> |
| 41 | + <div class="container" data-markdown> |
| 42 | + * Many computationally intensive applications spend the most of their time in **common operations / |
| 43 | + algorithms** |
40 | 44 | * **Numerical libraries** provide reliable solutions to these common problems |
41 | | - * You can focus on solving higher-level problems instead of technical details |
| 45 | + * You can focus on solving higher-level problems instead of technical details |
42 | 46 | * Libraries optimised for specific hardware provide **superior performance** |
43 | | - </div> |
44 | | - </section> |
45 | | - <!--Slide 4--> |
46 | | - <section> |
47 | | - <div class="hbox" data-markdown> |
48 | | - ## Numerical libraries |
49 | | - </div> |
50 | | - |
51 | | - <div class="container" data-markdown> |
52 | | - * Common APIs like BLAS or LAPACK have multiple CPU implementations and vendor-specific GPU solutions |
53 | | - * **Intel CPU/GPU**: Intel Math Kernels Library (oneMKL) |
54 | | - * **NVIDIA GPU**: cuBLAS, cuSOLVER, cuRAND, cuFFT |
55 | | - * **AMD GPU**: rocBLAS, rocSOLVER, rocRAND, rocFFT |
| 47 | + </div> |
| 48 | + </section> |
| 49 | + <!--Slide 4--> |
| 50 | + <section> |
| 51 | + <div class="hbox" data-markdown> |
| 52 | + ## Numerical libraries |
| 53 | + </div> |
| 54 | + <div class="container" data-markdown> |
| 55 | + * Common APIs like BLAS or LAPACK have multiple CPU implementations and vendor-specific GPU |
| 56 | + solutions |
| 57 | + * **Intel CPU/GPU**: Intel Math Kernels Library (oneMKL) |
| 58 | + * **NVIDIA GPU**: cuBLAS, cuSOLVER, cuRAND, cuFFT |
| 59 | + * **AMD GPU**: rocBLAS, rocSOLVER, rocRAND, rocFFT |
56 | 60 | * Imagine being able to use all of them with *single source code* → **oneMath** |
57 | | - </div> |
58 | | - </section> |
59 | | - <!--Slide 5--> |
60 | | - <section> |
61 | | - <div class="hbox"> |
62 | | - <h2 style="text-transform: none;"> |
63 | | - oneAPI and oneMath |
64 | | - </h2> |
65 | | - </div> |
66 | | - <div class="container" data-markdown> |
67 | | - * Open-source [**oneAPI**](https://oneapi.io/) project governed by the [United Acceleration (UXL) Foundation](https://uxlfoundation.org/): |
68 | | - * defines SYCL-based APIs and provides library implementations |
69 | | - * brings performance and ease of development to SYCL applications |
70 | | - * [**oneMath** specification](https://oneapi-spec.uxlfoundation.org/specifications/oneapi/latest/elements/onemath/source/): |
71 | | - * defines SYCL API for numerical computations across several domains |
72 | | - * Linear Algebra, Discrete Fourier Transforms, Random Number Generators, Statistics, Vector Math |
73 | | - * [**oneMath** library](https://github.com/uxlfoundation/oneMath): |
74 | | - * wrapper implementation dispatching SYCL API calls to a multitude of implementations, both generic and vendor-specific |
75 | | - </div> |
76 | | - <div class="container"> |
77 | | - <img style="height:4em; margin-top:2em;" src="../../Static/images/oneAPI.png"/> |
78 | | - <div style="display: inline; width: 2em;"></div> |
79 | | - <img style="height:4em; margin-top:2em;" src="../../Static/images/uxl.svg"/> |
80 | | - </div> |
81 | | - </section> |
82 | | - <!--Slide 6--> |
83 | | - <section> |
| 61 | + </div> |
| 62 | + </section> |
| 63 | + <!--Slide 5--> |
| 64 | + <section> |
| 65 | + <div class="hbox"> |
84 | 66 | <h2 style="text-transform: none;"> |
85 | | - oneMath library backends |
| 67 | + oneAPI and oneMath |
86 | 68 | </h2> |
87 | | - <object class="r-stretch" data="../../Static/images/oneMath-backends.svg"></object> |
88 | | - </section> |
89 | | - <!--Slide 7--> |
90 | | - <section> |
91 | | - <div class="hbox" data-markdown> |
92 | | - #### Run-time dispatching |
93 | | - </div> |
94 | | - <div class="container"> |
95 | | - <pre><code class="language-cpp" data-line-numbers> |
| 69 | + </div> |
| 70 | + <div class="container" data-markdown> |
| 71 | + * Open-source [**oneAPI**](https://oneapi.io/) project governed by the [United Acceleration (UXL) |
| 72 | + Foundation](https://uxlfoundation.org/): |
| 73 | + * defines SYCL-based APIs and provides library implementations |
| 74 | + * brings performance and ease of development to SYCL applications |
| 75 | + * [**oneMath** |
| 76 | + specification](https://oneapi-spec.uxlfoundation.org/specifications/oneapi/latest/elements/onemath/source/): |
| 77 | + * defines SYCL API for numerical computations across several domains |
| 78 | + * Linear Algebra, Discrete Fourier Transforms, Random Number Generators, Statistics, Vector Math |
| 79 | + * [**oneMath** library](https://github.com/uxlfoundation/oneMath): |
| 80 | + * wrapper implementation dispatching SYCL API calls to a multitude of implementations, both generic |
| 81 | + and vendor-specific |
| 82 | + </div> |
| 83 | + <div class="container"> |
| 84 | + <img style="height:4em; margin-top:2em;" src="../../Static/images/oneAPI.png" /> |
| 85 | + <div style="display: inline; width: 2em;"></div> |
| 86 | + <img style="height:4em; margin-top:2em;" src="../../Static/images/uxl.svg" /> |
| 87 | + </div> |
| 88 | + </section> |
| 89 | + <!--Slide 6--> |
| 90 | + <section> |
| 91 | + <h2 style="text-transform: none;"> |
| 92 | + oneMath library backends |
| 93 | + </h2> |
| 94 | + <object class="r-stretch" data="../../Static/images/oneMath-backends.svg"></object> |
| 95 | + </section> |
| 96 | + <!--Slide 7--> |
| 97 | + <section> |
| 98 | + <div class="hbox" data-markdown> |
| 99 | + #### Dispatching |
| 100 | + </div> |
| 101 | + <div class="container"> |
| 102 | + <div class="col-left-3"> |
| 103 | + <pre><code class="language-cpp" data-line-numbers="|8,11-14|16-20" data-fragment-index="0" data-noescape data-trim> |
| 104 | +#include <cassert> |
96 | 105 | #include <oneapi/math.hpp> |
| 106 | +#include <sycl/sycl.hpp> |
97 | 107 |
|
98 | | -sycl::queue q{myDeviceSelector}; |
| 108 | +int main() { |
| 109 | + int n = 16; |
| 110 | + float alpha = 2; |
| 111 | + <mark class="fragment" data-fragment-index="0">sycl::queue q</mark>; |
| 112 | + float *x = sycl::malloc_device<float>(n, q); |
99 | 113 |
|
100 | | -sycl::buffer<T,1> a{a_host, m*k}; |
101 | | -sycl::buffer<T,1> b{b_host, k*n}; |
102 | | -sycl::buffer<T,1> c{c_host, m*n}; |
| 114 | + // Run-time dispatch: backend chosen from the queue's device |
| 115 | + q.fill(x, 1.0f, n).wait(); |
| 116 | + oneapi::math::blas::column_major::scal( |
| 117 | + <mark class="fragment" data-fragment-index="0">q</mark>, n, alpha, x, 1).wait(); |
103 | 118 |
|
104 | | -// Compute C = A*B+C on the device |
105 | | -oneapi::math::blas::column_major::gemm(q, ..., m, n, k, ..., a, ..., b, ..., c, ... ); |
| 119 | + // Compile-time dispatch: backend fixed at compile time |
| 120 | + oneapi::math::backend_selector<oneapi::math::backend::generic> <mark class="fragment" data-fragment-index="1">sel</mark>{q}; |
| 121 | + q.fill(x, 1.0f, n).wait(); |
| 122 | + oneapi::math::blas::column_major::scal( |
| 123 | + <mark class="fragment" data-fragment-index="1">sel</mark>, n, alpha, x, 1).wait(); |
| 124 | + |
| 125 | + float result; |
| 126 | + q.memcpy(&result, x, sizeof(float)).wait(); |
| 127 | + // x started as 1 and was scaled by alpha |
| 128 | + assert(result == alpha); |
| 129 | + sycl::free(x, q); |
| 130 | +} |
106 | 131 | </code></pre> |
107 | | - </div> |
108 | | - <div class="container" data-markdown> |
109 | | - * Backend is loaded at run time based on the device associated with the SYCL queue |
110 | | - * Both buffer and USM APIs available (mind the different synchronisation) |
111 | | - * The same binary can run on different hardware with a generic device selector |
112 | | - * Can run on CPU or different GPUs without recompiling |
113 | | - * Link the application with the top-level runtime library: `-lonemath` |
114 | 132 | </div> |
115 | | - </section> |
116 | | - <!--Slide 8--> |
117 | | - <section> |
118 | | - <div class="hbox" data-markdown> |
119 | | - #### Compile-time dispatching |
120 | | - </div> |
121 | | - <div class="container"> |
122 | | - <pre><code class="language-cpp" data-line-numbers> |
| 133 | + <div class="col-right-2 stack-fragments"> |
| 134 | + <div class="fragment fade-out" data-fragment-index="0" data-markdown> |
| 135 | + * oneMath chooses which backend runs a routine |
| 136 | + * The first argument decides how that backend is selected |
| 137 | + </div> |
| 138 | + <div class="fragment current-visible" data-fragment-index="0" data-markdown> |
| 139 | + * **Run-time dispatch:** pass the `queue` directly as the first argument |
| 140 | + * The backend is loaded at run time from the device the queue targets |
| 141 | + * The same binary can run on different hardware without recompiling |
| 142 | + * Link the application with the top-level runtime library: `-lonemath` |
| 143 | + </div> |
| 144 | + <div class="fragment current-visible" data-fragment-index="1" data-markdown> |
| 145 | + * **Compile-time dispatch:** wrap the queue in a `backend_selector` and pass that instead |
| 146 | + * The backend is fixed at compile time |
| 147 | + * Reduces the small dispatching overhead at the cost of removed portability |
| 148 | + * Link the application with the specific backend library: `-lonemath_blas_mklcpu` |
| 149 | + </div> |
| 150 | + </div> |
| 151 | + </div> |
| 152 | + </section> |
| 153 | + <!--Slide 8--> |
| 154 | + <section> |
| 155 | + <div class="hbox" data-markdown> |
| 156 | + #### What is GEMM? |
| 157 | + </div> |
| 158 | + <div class="container" data-markdown> |
| 159 | + * GEMM stands for **GE**neral **M**atrix **M**ultiply |
| 160 | + * It is the core Level-3 routine of BLAS (Basic Linear Algebra Subprograms) |
| 161 | + * It computes `C = alpha * A * B + beta * C` |
| 162 | + * `A`, `B` and `C` are dense matrices; `alpha` and `beta` are scalars |
| 163 | + * `A` and/or `B` may optionally be transposed |
| 164 | + * It is the building block of dense linear algebra and machine learning, so every backend optimises it heavily |
| 165 | + </div> |
| 166 | + </section> |
| 167 | + <!--Slide 9--> |
| 168 | + <section> |
| 169 | + <div class="hbox" data-markdown> |
| 170 | + #### GEMM with oneMath |
| 171 | + </div> |
| 172 | + <div class="container"> |
| 173 | + <pre><code class="language-cpp" data-line-numbers="|7-12|16-22|25-27|30-31" data-fragment-index="0" data-noescape data-trim> |
| 174 | +#include <cassert> |
123 | 175 | #include <oneapi/math.hpp> |
| 176 | +#include <sycl/sycl.hpp> |
| 177 | +#include <vector> |
124 | 178 |
|
125 | | -sycl::queue cpu_queue{sycl::cpu_selector_v}; |
| 179 | +int main() { |
| 180 | + // C(m x n) = alpha * A(m x k) * B(k x n) + beta * C(m x n) |
| 181 | + int m = 16, n = 16, k = 16; |
| 182 | + int lda = k, ldb = n, ldc = n; |
| 183 | + float alpha = 1, beta = 0; |
| 184 | + auto transA = oneapi::math::transpose::nontrans; |
| 185 | + auto transB = oneapi::math::transpose::nontrans; |
126 | 186 |
|
127 | | -sycl::buffer<T,1> a{a_host, m*k}; |
128 | | -sycl::buffer<T,1> b{b_host, k*n}; |
129 | | -sycl::buffer<T,1> c{c_host, m*n}; |
| 187 | + sycl::queue q; |
130 | 188 |
|
131 | | -oneapi::math::backend_selector<oneapi::math::backend::mklcpu> cpu_selector(cpu_queue); |
132 | | -// Select the Intel oneMKL CPU backend specifically ^^^^^^ |
| 189 | + // Allocate device memory and copy the inputs across |
| 190 | + float *dA = sycl::malloc_device<float>(m * k, q); |
| 191 | + float *dB = sycl::malloc_device<float>(k * n, q); |
| 192 | + float *dC = sycl::malloc_device<float>(m * n, q); |
| 193 | + std::vector<float> A(m * k, 1), B(k * n, 1), C(m * n); |
| 194 | + q.memcpy(dA, A.data(), sizeof(float) * m * k); |
| 195 | + q.memcpy(dB, B.data(), sizeof(float) * k * n).wait(); |
133 | 196 |
|
134 | | -oneapi::math::blas::column_major::gemm(cpu_selector, ..., m, n, k, ..., a, ..., b, ..., c, ... ); |
135 | | - </code></pre> |
| 197 | + // Compute C = alpha * A * B + beta * C on the device |
| 198 | + oneapi::math::blas::row_major::gemm( |
| 199 | + q, transA, transB, m, n, k, alpha, |
| 200 | + dA, lda, dB, ldb, beta, dC, ldc).wait(); |
| 201 | + |
| 202 | + // Copy the result back and check it |
| 203 | + q.memcpy(C.data(), dC, sizeof(float) * m * n).wait(); |
| 204 | + assert(C[0] == static_cast<float>(k)); |
| 205 | + |
| 206 | + sycl::free(dA, q); sycl::free(dB, q); sycl::free(dC, q); |
| 207 | +} |
| 208 | + </code></pre> |
| 209 | + </div> |
| 210 | + <div class="bottom-bullets stack-fragments"> |
| 211 | + <div class="fragment fade-out" data-fragment-index="0" data-markdown> |
| 212 | + * oneMath exposes GEMM as a single call, with the matrices held in USM device memory |
136 | 213 | </div> |
137 | | - <div class="container" data-markdown> |
138 | | - * Specific backend can be selected at compile-time with a `backend_selector` |
139 | | - * Passed into the API in place of the queue |
140 | | - * Reduces the small dispatching overhead at the cost of removed portability |
141 | | - * Link the application with the specific backend library: `-lonemath_blas_mklcpu` |
142 | | - </div> |
143 | | - </section> |
144 | | - <!--Slide 9--> |
145 | | - <section> |
146 | | - <div class="hbox" data-markdown> |
147 | | - ## Exercise |
| 214 | + <div class="fragment current-visible" data-fragment-index="0" data-markdown> |
| 215 | + * The GEMM call is described by the dimensions `m`, `n`, `k`, the leading dimensions, the `alpha`/`beta` scalars and whether `A` or `B` are transposed |
148 | 216 | </div> |
149 | | - <div class="container" data-markdown> |
150 | | - * Objectives: Learn to use oneMath GEMM buffer and USM APIs |
| 217 | + <div class="fragment current-visible" data-fragment-index="1" data-markdown> |
| 218 | + * Allocate device memory with USM and copy the input matrices across |
| 219 | + </div> |
| 220 | + <div class="fragment current-visible" data-fragment-index="2" data-markdown> |
| 221 | + * A single call computes `C = alpha * A * B + beta * C`; `row_major` matches C/C++ array layout |
| 222 | + </div> |
| 223 | + <div class="fragment current-visible" data-fragment-index="3" data-markdown> |
| 224 | + * Copy the result back and check it: `A` and `B` are all ones, so every element of `C` is `k` |
| 225 | + </div> |
| 226 | + </div> |
| 227 | + </section> |
| 228 | + <!--Slide 10--> |
| 229 | + <section> |
| 230 | + <div class="hbox" data-markdown> |
| 231 | + ## Exercise |
| 232 | + </div> |
| 233 | + <div class="container" data-markdown> |
| 234 | + * Objectives: Learn to use the oneMath GEMM USM API |
151 | 235 | * Boiler-plate code already provided to: |
152 | | - * Initialize matrices on host |
153 | | - * Compute reference result on host |
154 | | - * Compare the host and device results |
| 236 | + * Initialize matrices on host |
| 237 | + * Compute reference result on host |
| 238 | + * Compare the host and device results |
155 | 239 | * Please **complete the TODO tasks** marked in the `source_*.cpp` |
156 | | - * Create buffers or transfer data with USM |
157 | | - * Compute GEMM by calling the oneMath API |
158 | | - * Use the provided `VerifyResult` function |
| 240 | + * Transfer data to the device with USM |
| 241 | + * Compute GEMM by calling the oneMath API |
| 242 | + * Use the provided `VerifyResult` function |
159 | 243 | * If stuck, have a look at `solution_*.cpp` |
160 | | - </div> |
161 | | - </section> |
162 | | - </div> |
| 244 | + </div> |
| 245 | + </section> |
163 | 246 | </div> |
164 | | - </body> |
| 247 | + </div> |
| 248 | +</body> |
| 249 | + |
165 | 250 | </html> |
0 commit comments