Skip to content
This repository was archived by the owner on Mar 28, 2023. It is now read-only.
Merged
255 changes: 255 additions & 0 deletions SYCL/Matrix/element_wise_all_ops_half.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
//==----------- element_wise_all_ops_half.cpp - DPC++ joint_matrix---------==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// REQUIRES: matrix

// RUN: %clangxx -fsycl %s -o %t.out
// RUN: %CPU_RUN_PLACEHOLDER %t.out
// RUN: %GPU_RUN_PLACEHOLDER %t.out

#include <CL/sycl.hpp>
#include <iostream>
#include <random>

using namespace sycl;
using namespace sycl::ext::intel;
using namespace sycl::ext::oneapi::experimental::matrix;

#define SG_SZ 8

#define TM 8
#define TN SG_SZ
#define TK 16

template <typename T, size_t NUM_ROWS, size_t NUM_COLS> struct big_matrix {
public:
T *mat;

public:
T *get_data() { return mat; }
void set_data(T *data) { mat = data; }
big_matrix(T *data) : mat(data) {}
};

template <typename T, size_t M, size_t N>
void assert_ops_ref(/*const T &C*/ accessor<T, 2, access::mode::read,
access::target::host_buffer>
C,
const float ref) {
for (size_t i = 0; i < M; i++)
for (size_t j = 0; j < N; j++) {
auto diff = C[i][j] - ref;
assert(std::fabs(static_cast<float>(diff)) <
std::numeric_limits<float>::epsilon());
}
}
template <typename T, size_t M, size_t N>
void matrix_verify_add(queue q, big_matrix<T, M, N> &A, nd_range<2> &r,
const float ref) {
buffer<half, 2> bufA(A.get_data(), range<2>(M, N));

q.submit([&](handler &cgh) {
auto accA = bufA.get_access<access::mode::read_write>(cgh);

cgh.parallel_for<class imatrix>(r, [accA](nd_item<2> spmd_item) {
const auto global_idx = spmd_item.get_global_id(0);
const auto global_idy = spmd_item.get_global_id(1);
const auto sg_startx = global_idx - spmd_item.get_local_id(0);
const auto sg_starty = global_idy - spmd_item.get_local_id(1);

ext::oneapi::sub_group sg = spmd_item.get_sub_group();
joint_matrix<T, TM, TK> sub_a(sg);

joint_matrix_fill(sg, sub_a, 5.0);

auto wi_slice_a = sub_a.get_wi_data();
for (int i = 0; i < wi_slice_a.length(); i++) {
wi_slice_a[i] = wi_slice_a[i] + 2;
}
joint_matrix_store(sg, sub_a,
accA.get_pointer() + (sg_startx * TM) * N +
sg_starty / SG_SZ * TN,
N, matrix_layout::row_major);
}); // parallel for
}).wait();
assert_ops_ref<T, M, N>(bufA.get_access<access::mode::read>(), ref);
}

template <typename T, size_t M, size_t N>
void matrix_verify_sub(queue q, big_matrix<T, M, N> &A, nd_range<2> &r,
const float ref) {
buffer<half, 2> bufA(A.get_data(), range<2>(M, N));

q.submit([&](handler &cgh) {
auto accA = bufA.get_access<access::mode::read_write>(cgh);

cgh.parallel_for<class imatrix>(r, [accA](nd_item<2> spmd_item) {
const auto global_idx = spmd_item.get_global_id(0);
const auto global_idy = spmd_item.get_global_id(1);
const auto sg_startx = global_idx - spmd_item.get_local_id(0);
const auto sg_starty = global_idy - spmd_item.get_local_id(1);

ext::oneapi::sub_group sg = spmd_item.get_sub_group();
joint_matrix<T, TM, TK> sub_a(sg);

joint_matrix_fill(sg, sub_a, 5.0);

auto wi_slice_a = sub_a.get_wi_data();
for (int i = 0; i < wi_slice_a.length(); i++) {
wi_slice_a[i] = wi_slice_a[i] - 2;
}
joint_matrix_store(sg, sub_a,
accA.get_pointer() + (sg_startx * TM) * N +
sg_starty / SG_SZ * TN,
N, matrix_layout::row_major);
}); // parallel for
}).wait();
assert_ops_ref<T, M, N>(bufA.get_access<access::mode::read>(), ref);
}

template <typename T, size_t M, size_t N>
void matrix_verify_mul(queue q, big_matrix<T, M, N> &A, nd_range<2> &r,
const float ref) {
buffer<half, 2> bufA(A.get_data(), range<2>(M, N));

q.submit([&](handler &cgh) {
auto accA = bufA.get_access<access::mode::read_write>(cgh);

cgh.parallel_for<class imatrix>(r, [accA](nd_item<2> spmd_item) {
const auto global_idx = spmd_item.get_global_id(0);
const auto global_idy = spmd_item.get_global_id(1);
const auto sg_startx = global_idx - spmd_item.get_local_id(0);
const auto sg_starty = global_idy - spmd_item.get_local_id(1);

ext::oneapi::sub_group sg = spmd_item.get_sub_group();
joint_matrix<T, TM, TK> sub_a(sg);

joint_matrix_fill(sg, sub_a, 5.0);

auto wi_slice_a = sub_a.get_wi_data();
for (int i = 0; i < wi_slice_a.length(); i++) {
wi_slice_a[i] = wi_slice_a[i] * 3.0;
}
joint_matrix_store(sg, sub_a,
accA.get_pointer() + (sg_startx * TM) * N +
sg_starty / SG_SZ * TN,
N, matrix_layout::row_major);
}); // parallel for
}).wait();
assert_ops_ref<T, M, N>(bufA.get_access<access::mode::read>(), ref);
}

template <typename T, size_t M, size_t N>
void matrix_verify_div(queue q, big_matrix<T, M, N> &A, nd_range<2> &r,
const float ref) {
buffer<half, 2> bufA(A.get_data(), range<2>(M, N));

q.submit([&](handler &cgh) {
auto accA = bufA.get_access<access::mode::read_write>(cgh);

cgh.parallel_for<class imatrix>(r, [accA](nd_item<2> spmd_item) {
const auto global_idx = spmd_item.get_global_id(0);
const auto global_idy = spmd_item.get_global_id(1);
const auto sg_startx = global_idx - spmd_item.get_local_id(0);
const auto sg_starty = global_idy - spmd_item.get_local_id(1);

ext::oneapi::sub_group sg = spmd_item.get_sub_group();
joint_matrix<T, TM, TK> sub_a(sg);

joint_matrix_fill(sg, sub_a, 4.0);

auto wi_slice_a = sub_a.get_wi_data();
for (int i = 0; i < wi_slice_a.length(); i++) {
wi_slice_a[i] = wi_slice_a[i] / 2.0;
}
joint_matrix_store(sg, sub_a,
accA.get_pointer() + (sg_startx * TM) * N +
sg_starty / SG_SZ * TN,
N, matrix_layout::row_major);
}); // parallel for
}).wait();
assert_ops_ref<T, M, N>(bufA.get_access<access::mode::read>(), ref);
}

template <typename T, size_t M, size_t N>
void matrix_verify_logic(queue q, big_matrix<T, M, N> &A, nd_range<2> &r,
const float ref) {
buffer<half, 2> bufA(A.get_data(), range<2>(M, N));

q.submit([&](handler &cgh) {
auto accA = bufA.get_access<access::mode::read_write>(cgh);

cgh.parallel_for<class imatrix>(r, [accA](nd_item<2> spmd_item) {
const auto global_idx = spmd_item.get_global_id(0);
const auto global_idy = spmd_item.get_global_id(1);
const auto sg_startx = global_idx - spmd_item.get_local_id(0);
const auto sg_starty = global_idy - spmd_item.get_local_id(1);

ext::oneapi::sub_group sg = spmd_item.get_sub_group();
joint_matrix<T, TM, TK> sub_a(sg);

joint_matrix_fill(sg, sub_a, 5.0);

auto wi_slice_a = sub_a.get_wi_data();
for (int i = 0; i < wi_slice_a.length(); i++) {
if (wi_slice_a[i]) {
if (wi_slice_a[i] > 2.0 || wi_slice_a[i] >= 2.0 ||
wi_slice_a[i] < 2.0 || wi_slice_a[i] <= 2.0) {
T val = (wi_slice_a[i] != 2.0) ? wi_slice_a[i] : 2.0;

@yubingex007-a11y yubingex007-a11y Jan 11, 2022

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should change the testcase according to the rules of "?: " and use static_cast for ternary operator in our code.

If the types of the second and third operands are not identical, then complex type conversion rules, as specified in the C++ Standard, are invoked. These conversions may lead to unexpected behavior including construction and destruction of temporary objects. For this reason, we strongly advise you to either (1) avoid using user-defined types as operands with the conditional operator or (2) if you do use user-defined types, then explicitly cast each operand to a common type.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
T val = (wi_slice_a[i] != 2.0) ? wi_slice_a[i] : 2.0;
T val = (wi_slice_a[i] != 2.0) ? wi_slice_a[i] : static_cast<half>(2.0);

@dkhaldi dkhaldi Jan 11, 2022

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yubingex007-a11y thank you for fixing the two bugs related to fill and slicing when type deduction confusion happens, I made this change in a separate PR #727.

val--;
val++;
if (wi_slice_a[i] == 2.0) {
val -= 2;
val *= 3.0;
val /= 2.0;
} else {
val += 2;
}
wi_slice_a[i] = val;
}
}
}
joint_matrix_store(sg, sub_a,
accA.get_pointer() + (sg_startx * TM) * N +
sg_starty / SG_SZ * TN,
N, matrix_layout::row_major);
}); // parallel for
}).wait();
assert_ops_ref<T, M, N>(bufA.get_access<access::mode::read>(), ref);
}

static constexpr size_t MATRIX_M = TM * 2;
static constexpr size_t MATRIX_N = TN * 2;
half A[MATRIX_M][MATRIX_N];
float D[MATRIX_M][MATRIX_N];

void matrix_ops_ref(float *D, int M, int N) {
for (int m = 0; m < M; m++)
for (int n = 0; n < N; n++) {
*(D + m * N + n) = 0;
*(D + m * N + n) *= 2;
}
}

int main() {

big_matrix<float, MATRIX_M, MATRIX_N> MD((float *)&D);
big_matrix<half, MATRIX_M, MATRIX_N> MA((half *)&A);

size_t NDRangeM = MATRIX_M / TM;
size_t NDRangeN = MATRIX_N / TN;
queue q;
nd_range<2> r({NDRangeM, NDRangeN * SG_SZ}, {1, 1 * SG_SZ});

matrix_verify_add<half, MATRIX_M, MATRIX_N>(q, MA, r, 7.0);
matrix_verify_sub<half, MATRIX_M, MATRIX_N>(q, MA, r, 3.0);
matrix_verify_mul<half, MATRIX_M, MATRIX_N>(q, MA, r, 15.0);
matrix_verify_div<half, MATRIX_M, MATRIX_N>(q, MA, r, 2.0);
matrix_verify_logic<half, MATRIX_M, MATRIX_N>(q, MA, r, 7.0);

return 0;
}
Loading