Skip to content

Commit 65fbf1a

Browse files
oneDNN: Support for existing onednn_graph dialect ops + unit tests.
1 parent 766cbcf commit 65fbf1a

16 files changed

+782
-5
lines changed

src/dnnl/JsonParser.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,11 +245,11 @@ inline mlir::Attribute JsonParser::readAttr() {
245245
} else if (_str == "s64[]") {
246246
_ia64.clear();
247247
readNumArray(_ia64);
248-
attr = _builder.getI64ArrayAttr(_ia64);
248+
attr = _builder.getDenseI64ArrayAttr(_ia64);
249249
} else if (_str == "f32[]") {
250250
_fa32.clear();
251251
readNumArray(_fa32);
252-
attr = _builder.getF32ArrayAttr(_fa32);
252+
attr = _builder.getDenseF32ArrayAttr(_fa32);
253253
} else if (_str == "string") {
254254
_reader.read_string(&_str);
255255
attr = _builder.getStringAttr(_str);

src/dnnl/JsonParser.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@
2727
#include <stdfloat>
2828
#else
2929
namespace std {
30+
#if defined(__SIZEOF_FLOAT__) && __SIZEOF_FLOAT__ == 4
3031
using float32_t = float;
32+
#elif defined(__SIZEOF_DOUBLE__) && __SIZEOF_DOUBLE__ == 4
33+
using float32_t = double;
34+
#else
35+
static_assert(false, "Unable to determine 32-bit floating point type");
36+
#endif
3137
} // namespace std
3238
#endif
3339

@@ -145,8 +151,16 @@ class JsonParser {
145151
}
146152
std::unordered_map<std::string, OpBuilderFn> _opBuilders{
147153
GC_OP("Add", mlir::onednn_graph::AddOp),
154+
GC_OP("Divide", mlir::onednn_graph::DivOp),
148155
GC_OP("MatMul", mlir::onednn_graph::MatMulOp),
156+
GC_OP("Multiply", mlir::onednn_graph::MulOp),
157+
GC_OP("Pow", mlir::onednn_graph::PowOp),
158+
GC_OP("ReduceMean", mlir::onednn_graph::ReduceMeanOp),
159+
GC_OP("ReduceSum", mlir::onednn_graph::ReduceSumOp),
149160
GC_OP("ReLU", mlir::onednn_graph::ReLUOp),
161+
GC_OP("Sigmoid", mlir::onednn_graph::SigmoidOp),
162+
GC_OP("Subtract", mlir::onednn_graph::SubOp),
163+
GC_OP("Typecast", mlir::onednn_graph::TypeCastOp),
150164
};
151165
#undef GC_OP
152166

test/dnnl/DnnlTestUtils.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,21 @@
1111
#include <sstream>
1212
#include <string>
1313

14-
static std::string read_str_resource(const std::string &name) {
14+
#if __cplusplus > 202002L
15+
#include <stdfloat>
16+
#else
17+
namespace std {
18+
#if defined(__SIZEOF_FLOAT__) && __SIZEOF_FLOAT__ == 4
19+
using float32_t = float;
20+
#elif defined(__SIZEOF_DOUBLE__) && __SIZEOF_DOUBLE__ == 4
21+
using float32_t = double;
22+
#else
23+
static_assert(false, "No 32-bit floating point type available");
24+
#endif
25+
} // namespace std
26+
#endif
27+
28+
static std::string readStrResource(const std::string &name) {
1529
std::filesystem::path res_dir{"resources"};
1630
auto path = std::filesystem::absolute(res_dir / name);
1731
std::ifstream file(path);

test/dnnl/TestApiBasic.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include "graph/backend/elyzor/include/dnnl_graph_compiler.h"
1414

1515
TEST(TestApiBasic, basicWorkflow) {
16-
auto json = read_str_resource("add.json");
16+
auto json = readStrResource("add.json");
1717

1818
const struct dnnl_graph_compiler_context ctx = {.num_threads = 4};
1919
const struct dnnl_graph_compiler *gc;

test/dnnl/TestApiOps.cpp

Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
//===-- TestApiBasic.cpp - OneDNN operations test ---------------*- C++ -*-===//
2+
//
3+
// This file is licensed under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include <cmath>
10+
#include <gtest/gtest.h>
11+
12+
#include <llvm/ADT/APFloat.h>
13+
14+
#include "DnnlTestUtils.h"
15+
#include "graph/backend/elyzor/include/dnnl_graph_compiler.h"
16+
17+
static void exec(const char *fileName, dnnl_graph_compiler_tensor *inputs,
18+
dnnl_graph_compiler_tensor *outputs) {
19+
auto json = readStrResource(fileName);
20+
const struct dnnl_graph_compiler_context ctx = {0};
21+
const struct dnnl_graph_compiler *gc;
22+
const struct dnnl_graph_compiler_executable *exe;
23+
ASSERT_EQ(dnnl_graph_compiler_create(&ctx, &gc), dnnl_success);
24+
ASSERT_EQ(dnnl_graph_compiler_compile(gc, json.c_str(), &exe), dnnl_success);
25+
ASSERT_EQ(dnnl_graph_compiler_execute(gc, exe, inputs, outputs),
26+
dnnl_success);
27+
dnnl_graph_compiler_destroy_executable(gc, exe);
28+
dnnl_graph_compiler_destroy(gc);
29+
}
30+
31+
TEST(TestApiOps, div) {
32+
dnnl_graph_compiler_tensor inputs[2];
33+
dnnl_graph_compiler_tensor outputs[1];
34+
int64_t dims[1] = {128};
35+
std::float32_t arg1[128];
36+
std::float32_t arg2[128];
37+
std::float32_t arg3[128];
38+
inputs[0] = {.id = 0, .ndims = 1, .dims = dims, .data = arg1};
39+
inputs[1] = {.id = 1, .ndims = 1, .dims = dims, .data = arg2};
40+
outputs[0] = {.id = 2, .ndims = 1, .dims = dims, .data = arg3};
41+
for (auto i = 0; i < 128; i++) {
42+
arg1[i] = static_cast<std::float32_t>(std::pow(i, 2) / 128.f);
43+
arg2[i] = arg1[i] + 1;
44+
}
45+
46+
exec("div.json", inputs, outputs);
47+
48+
for (auto i = 0; i < 128; i++) {
49+
ASSERT_EQ(arg3[i], arg1[i] / arg2[i]);
50+
}
51+
}
52+
53+
TEST(TestApiOps, matMul) {
54+
dnnl_graph_compiler_tensor inputs[3];
55+
dnnl_graph_compiler_tensor outputs[1];
56+
int64_t dimsA[2] = {128, 512};
57+
int64_t dimsB[2] = {128, 64};
58+
int64_t dimsBias[1] = {64};
59+
int64_t dimsOut[2] = {512, 64};
60+
std::float32_t argA[128][512];
61+
std::float32_t argB[128][64];
62+
std::float32_t argBias[64];
63+
std::float32_t argOut[512][64];
64+
inputs[0] = {.id = 0, .ndims = 2, .dims = dimsA, .data = argA};
65+
inputs[1] = {.id = 1, .ndims = 2, .dims = dimsB, .data = argB};
66+
inputs[2] = {.id = 2, .ndims = 1, .dims = dimsBias, .data = argBias};
67+
outputs[0] = {.id = 3, .ndims = 2, .dims = dimsOut, .data = argOut};
68+
69+
// Initialize input tensors
70+
for (auto i = 0; i < 128; i++) {
71+
for (auto j = 0; j < 512; j++) {
72+
argA[i][j] = static_cast<std::float32_t>(i + j);
73+
}
74+
}
75+
for (auto i = 0; i < 128; i++) {
76+
for (auto j = 0; j < 64; j++) {
77+
argB[i][j] = static_cast<std::float32_t>(i - j);
78+
}
79+
}
80+
for (auto i = 0; i < 64; i++) {
81+
argBias[i] = static_cast<std::float32_t>(i);
82+
}
83+
84+
exec("matmul.json", inputs, outputs);
85+
86+
// Calculate expected output
87+
std::float32_t expected[512][64];
88+
for (auto i = 0; i < 512; i++) {
89+
for (auto j = 0; j < 64; j++) {
90+
expected[i][j] = argBias[j];
91+
for (auto k = 0; k < 128; k++) {
92+
expected[i][j] += argA[k][i] * argB[k][j]; // transpose_a = true
93+
}
94+
}
95+
}
96+
97+
// Compare the results
98+
for (auto i = 0; i < 512; i++) {
99+
for (auto j = 0; j < 64; j++) {
100+
ASSERT_EQ(expected[i][j], argOut[i][j]);
101+
}
102+
}
103+
}
104+
105+
TEST(TestApiOps, mul) {
106+
dnnl_graph_compiler_tensor inputs[2];
107+
dnnl_graph_compiler_tensor outputs[1];
108+
int64_t dims[1] = {128};
109+
std::float32_t arg1[128];
110+
std::float32_t arg2[128];
111+
std::float32_t arg3[128];
112+
inputs[0] = {.id = 0, .ndims = 1, .dims = dims, .data = arg1};
113+
inputs[1] = {.id = 1, .ndims = 1, .dims = dims, .data = arg2};
114+
outputs[0] = {.id = 2, .ndims = 1, .dims = dims, .data = arg3};
115+
for (auto i = 0; i < 128; i++) {
116+
arg1[i] = arg2[i] = static_cast<std::float32_t>(i);
117+
}
118+
119+
exec("mul.json", inputs, outputs);
120+
121+
for (auto i = 0; i < 128; i++) {
122+
ASSERT_EQ(arg3[i], static_cast<std::float32_t>(i * i));
123+
}
124+
}
125+
126+
TEST(TestApiOps, sub) {
127+
dnnl_graph_compiler_tensor inputs[2];
128+
dnnl_graph_compiler_tensor outputs[1];
129+
int64_t dims[1] = {128};
130+
std::float32_t arg1[128];
131+
std::float32_t arg2[128];
132+
std::float32_t arg3[128];
133+
inputs[0] = {.id = 0, .ndims = 1, .dims = dims, .data = arg1};
134+
inputs[1] = {.id = 1, .ndims = 1, .dims = dims, .data = arg2};
135+
outputs[0] = {.id = 2, .ndims = 1, .dims = dims, .data = arg3};
136+
for (auto i = 0; i < 128; i++) {
137+
arg1[i] = static_cast<std::float32_t>(i);
138+
arg2[i] = arg1[i] * arg1[i];
139+
}
140+
141+
exec("sub.json", inputs, outputs);
142+
143+
for (auto i = 0; i < 128; i++) {
144+
ASSERT_EQ(arg3[i], arg1[i] - arg2[i]);
145+
}
146+
}
147+
148+
TEST(TestApiOps, pow) {
149+
dnnl_graph_compiler_tensor inputs[1];
150+
dnnl_graph_compiler_tensor outputs[1];
151+
int64_t dims[1] = {64};
152+
std::float32_t arg1[64];
153+
std::float32_t arg2[64];
154+
inputs[0] = {.id = 0, .ndims = 1, .dims = dims, .data = arg1};
155+
outputs[0] = {.id = 1, .ndims = 1, .dims = dims, .data = arg2};
156+
for (auto i = 0; i < 64; i++) {
157+
arg1[i] = static_cast<std::float32_t>(i);
158+
}
159+
160+
exec("pow.json", inputs, outputs);
161+
162+
for (auto i = 0; i < 64; i++) {
163+
ASSERT_EQ(arg1[i] * arg1[i], arg2[i]);
164+
}
165+
}
166+
167+
TEST(TestApiOps, relu) {
168+
dnnl_graph_compiler_tensor inputs[1];
169+
dnnl_graph_compiler_tensor outputs[1];
170+
int64_t dims[1] = {128};
171+
std::float32_t arg1[128];
172+
std::float32_t arg2[128];
173+
inputs[0] = {.id = 0, .ndims = 1, .dims = dims, .data = arg1};
174+
outputs[0] = {.id = 1, .ndims = 1, .dims = dims, .data = arg2};
175+
176+
for (auto i = 0; i < 128; i++) {
177+
arg1[i] = static_cast<std::float32_t>(i - 64);
178+
}
179+
180+
exec("relu.json", inputs, outputs);
181+
182+
for (auto i = 0; i < 128; i++) {
183+
ASSERT_EQ(arg1[i] < 0 ? 0 : arg1[i], arg2[i]);
184+
}
185+
}
186+
187+
TEST(TestApiOps, reduceMean) {
188+
dnnl_graph_compiler_tensor inputs[1];
189+
dnnl_graph_compiler_tensor outputs[1];
190+
int64_t dims1[3] = {16, 64, 32};
191+
int64_t dims2[3] = {16, 1, 32};
192+
std::float32_t arg1[16][64][32];
193+
std::float32_t arg2[16][1][32];
194+
inputs[0] = {.id = 0, .ndims = 3, .dims = dims1, .data = arg1};
195+
outputs[0] = {.id = 1, .ndims = 3, .dims = dims2, .data = arg2};
196+
197+
for (auto i = 0; i < 16; i++) {
198+
for (auto y = 0; y < 64; y++) {
199+
for (auto z = 0; z < 32; z++) {
200+
arg1[i][y][z] = static_cast<std::float32_t>(i * 64 * 32 + y * 32 + z);
201+
}
202+
}
203+
}
204+
205+
exec("reduce_mean.json", inputs, outputs);
206+
207+
std::float32_t expected[16][1][32];
208+
for (auto x = 0; x < 16; x++) {
209+
for (auto z = 0; z < 32; z++) {
210+
expected[x][0][z] = 0;
211+
for (auto y = 0; y < 64; y++) {
212+
expected[x][0][z] += arg1[x][y][z];
213+
}
214+
expected[x][0][z] /= 64;
215+
}
216+
}
217+
218+
for (auto x = 0; x < 16; x++) {
219+
for (auto z = 0; z < 32; z++) {
220+
ASSERT_EQ(expected[x][0][z], arg2[x][0][z]);
221+
}
222+
}
223+
}
224+
225+
TEST(TestApiOps, reduceSum) {
226+
dnnl_graph_compiler_tensor inputs[1];
227+
dnnl_graph_compiler_tensor outputs[1];
228+
int64_t dims1[3] = {16, 64, 32};
229+
int64_t dims2[3] = {16, 1, 32};
230+
std::float32_t arg1[16][64][32];
231+
std::float32_t arg2[16][1][32];
232+
inputs[0] = {.id = 0, .ndims = 3, .dims = dims1, .data = arg1};
233+
outputs[0] = {.id = 1, .ndims = 3, .dims = dims2, .data = arg2};
234+
235+
for (auto i = 0; i < 16; i++) {
236+
for (auto y = 0; y < 64; y++) {
237+
for (auto z = 0; z < 32; z++) {
238+
arg1[i][y][z] = static_cast<std::float32_t>(i * 64 * 32 + y * 32 + z);
239+
}
240+
}
241+
}
242+
243+
exec("reduce_sum.json", inputs, outputs);
244+
245+
std::float32_t expected[16][1][32];
246+
for (auto x = 0; x < 16; x++) {
247+
for (auto z = 0; z < 32; z++) {
248+
expected[x][0][z] = 0;
249+
for (auto y = 0; y < 64; y++) {
250+
expected[x][0][z] += arg1[x][y][z];
251+
}
252+
}
253+
}
254+
255+
for (auto x = 0; x < 16; x++) {
256+
for (auto z = 0; z < 32; z++) {
257+
ASSERT_EQ(expected[x][0][z], arg2[x][0][z]);
258+
}
259+
}
260+
}
261+
262+
TEST(TestApiOps, sigmoid) {
263+
dnnl_graph_compiler_tensor inputs[1];
264+
dnnl_graph_compiler_tensor outputs[1];
265+
int64_t dims[1] = {128};
266+
std::float32_t arg1[128];
267+
std::float32_t arg2[128];
268+
inputs[0] = {.id = 0, .ndims = 1, .dims = dims, .data = arg1};
269+
outputs[0] = {.id = 1, .ndims = 1, .dims = dims, .data = arg2};
270+
for (auto i = 0; i < 128; i++) {
271+
arg1[i] = static_cast<std::float32_t>(i - 64);
272+
}
273+
274+
exec("sigmoid.json", inputs, outputs);
275+
276+
for (auto i = 0; i < 128; i++) {
277+
ASSERT_EQ(1.f / (1.f + std::exp(-arg1[i])), arg2[i]);
278+
}
279+
}
280+
281+
TEST(TestApiOps, typecast) {
282+
dnnl_graph_compiler_tensor inputs[1];
283+
dnnl_graph_compiler_tensor outputs[1];
284+
int64_t dims[1] = {128};
285+
std::float32_t arg1[128];
286+
uint16_t arg2[128];
287+
inputs[0] = {.id = 0, .ndims = 1, .dims = dims, .data = arg1};
288+
outputs[0] = {.id = 1, .ndims = 1, .dims = dims, .data = arg2};
289+
for (auto i = 0; i < 128; i++) {
290+
auto x = i - 64;
291+
arg1[i] = static_cast<std::float32_t>(x / (std::exp(-x)));
292+
}
293+
294+
exec("typecast.json", inputs, outputs);
295+
296+
for (auto i = 0; i < 128; i++) {
297+
llvm::APFloat f(arg1[i]);
298+
bool losesInfo;
299+
f.convert(llvm::APFloat::IEEEhalf(), llvm::APFloat::rmNearestTiesToEven,
300+
&losesInfo);
301+
ASSERT_EQ(static_cast<uint16_t>(f.bitcastToAPInt().getZExtValue()),
302+
arg2[i]);
303+
}
304+
}
305+
306+
int main(int argc, char **argv) {
307+
::testing::InitGoogleTest(&argc, argv);
308+
return RUN_ALL_TESTS();
309+
}

test/dnnl/TestJsonParser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ static mlir::ModuleOp parse(const char *fileName,
3636
#endif
3737
}();
3838

39-
auto json = read_str_resource(fileName);
39+
auto json = readStrResource(fileName);
4040
mlir::ModuleOp module =
4141
JsonParser::parse(context, json, inputIds, outputIds, strides);
4242

0 commit comments

Comments
 (0)