diff --git a/.github/workflows/cpu-build.yml b/.github/workflows/cpu-build.yml new file mode 100644 index 0000000..6dc05c3 --- /dev/null +++ b/.github/workflows/cpu-build.yml @@ -0,0 +1,84 @@ +name: CPU Build + +on: + push: + branches: [main] + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + env: + DEPS_DIR: ${{ github.workspace }}/.deps + KOKKOS_INSTALL: ${{ github.workspace }}/.deps/kokkos/install + CHARM_ROOT: ${{ github.workspace }}/.deps/charm-src/netlrts-linux-x86_64 + CHARM_DIR: ${{ github.workspace }}/.deps/charm-src/netlrts-linux-x86_64 + KOKKOS_DIR: ${{ github.workspace }}/.deps/kokkos/install + BASE_DIR: ${{ github.workspace }} + EIGEN_DIR: /usr/include/eigen3 + COMPREHENSIVE_BUILD_DIR: ${{ github.workspace }}/tests/comprehensive/build + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y build-essential cmake libeigen3-dev python3 + + - name: Prepare dependency directories + run: mkdir -p "${DEPS_DIR}" + + - name: Cache Kokkos install + id: cache-kokkos + uses: actions/cache@v4 + with: + path: ${{ env.KOKKOS_INSTALL }} + key: ${{ runner.os }}-kokkos-4.5.01 + + - name: Build Kokkos + if: steps.cache-kokkos.outputs.cache-hit != 'true' + run: | + set -euxo pipefail + export nproc="$(nproc)" + git clone https://github.com/kokkos/kokkos.git "${DEPS_DIR}/kokkos" + pushd "${DEPS_DIR}/kokkos" + git checkout 4.5.01 + mkdir build + cd build + cmake -DBUILD_SHARED_LIBS=ON .. + make -j"${nproc}" + cd .. + mkdir install + cmake --install build --prefix install + popd + + - name: Cache Charm++ build + id: cache-charm + uses: actions/cache@v4 + with: + path: ${{ env.CHARM_ROOT }} + key: ${{ runner.os }}-charm-default + + - name: Build Charm++ + if: steps.cache-charm.outputs.cache-hit != 'true' + run: | + set -euxo pipefail + git clone --depth 1 https://github.com/UIUC-PPL/charm.git "${DEPS_DIR}/charm-src" + pushd "${DEPS_DIR}/charm-src" + ./build charm++ netlrts-linux-x86_64 --with-production -j"$(nproc)" + popd + + - name: Reset comprehensive build directory + run: rm -rf "${COMPREHENSIVE_BUILD_DIR}" + + - name: Configure comprehensive test suite + run: cmake -S tests/comprehensive -B "${COMPREHENSIVE_BUILD_DIR}" -DCharm_ENABLE_GPU=OFF + + - name: Build comprehensive test suite + run: cmake --build "${COMPREHENSIVE_BUILD_DIR}" --target comprehensive_tests.out -- -j"$(nproc)" + + - name: Run comprehensive test suite + working-directory: ${{ env.COMPREHENSIVE_BUILD_DIR }} + run: | + "${CHARM_DIR}/bin/charmrun" +p2 ./comprehensive_tests.out ++local diff --git a/.gitignore b/.gitignore index 9292e91..6fefcaa 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,14 @@ # libcharmtyles libcharmtyles +# kokkos +kokkos +kokkos-kernels + +# laboratory +playground +pg + # charmrun charmrun diff --git a/Makefile.common b/Makefile.common index 8dda15e..05083cc 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1,11 +1,11 @@ # point these to absolute paths -CHARM_DIR = /path/to/charm/build/directory -BASE_DIR = /path/to/LibCharmtyles +CHARM_DIR = /home/shogo/master/Kale/charm/netlrts-linux-x86_64 +BASE_DIR = /home/shogo/master/Kale/LibCharmtyles EIGEN_DIR = /usr/include/eigen3 # common options CHARMC = $(CHARM_DIR)/bin/charmc -DUSE_ESSL_WRAPPER=0 OPTS = -c++-option -std=c++17 -O3 -march=native -DNDEBUG -I$(EIGEN_DIR) -LD_OPTS = +LD_OPTS= INCS = -I$(BASE_DIR) diff --git a/charmtyles/backend/charmtyles.ci b/charmtyles/backend/charmtyles.ci index f75deff..6e6aed4 100644 --- a/charmtyles/backend/charmtyles.ci +++ b/charmtyles/backend/charmtyles.ci @@ -6,6 +6,8 @@ module libcharmtyles include "limits"; readonly CProxy_scalar_impl scalar_impl_proxy; + readonly CProxy_KokkosGroup kokkosMgmt; + readonly CProxy_reductionGroup reductionMgmt; chare set_future { @@ -62,7 +64,7 @@ module libcharmtyles ++SDAG_INDEX; }} // add_scalar - when reduction[SDAG_INDEX](double value) { + when reduction(double value) { case { when update_scalar[SDAG_INDEX](int sdag_index, int scalar_id) { serial "reduction" { @@ -120,14 +122,10 @@ module libcharmtyles "initialization."); std::size_t vec_dim = get_vec_dim(total_len); - - std::vector gen_vec(vec_dim); - - for (int dimX = 0; dimX != vec_dim; ++dimX) - { - gen_vec[dimX] = gen_ptr->generate(thisIndex * vec_block_size + dimX); - } - vec_map.emplace_back(std::move(gen_vec)); + + // Use public helper method to avoid CUDA lambda visibility issues + Kokkos::View gen_vec = generator_init_impl(vec_dim, gen_ptr); + vec_map.emplace_back(gen_vec); ++SDAG_INDEX; }} @@ -161,13 +159,8 @@ module libcharmtyles when dot[SDAG_INDEX](int sdag_index, int lhs_id, int rhs_id, int scal_sdag_idx) { serial "vector_dot" { - std::vector& lhs = vec_map[lhs_id]; - std::vector& rhs = vec_map[rhs_id]; - - Eigen::Map elhs(lhs.data(), lhs.size()); - Eigen::Map erhs(rhs.data(), rhs.size()); - - double result = elhs.dot(erhs); + // Use public helper method to avoid CUDA lambda visibility issues + double result = vector_dot_impl(lhs_id, rhs_id); CkCallback cb(CkReductionTarget(scalar_impl, reduction), scalar_impl_proxy); contribute(sizeof(double), &result, CkReduction::sum_double, cb, scal_sdag_idx); @@ -176,10 +169,32 @@ module libcharmtyles }} // dot when send_to_matrix[SDAG_INDEX]( - int sdag_index, int vec_idx, int rhs_sdag_idx, CProxy_matrix_impl proxy) { + int sdag_index, int vec_idx, int rhs_sdag_idx, int row_block_len, int col_block_len, int numCharesX, int numCharesY, bool is_vec_mat, CProxy_matrix_impl proxy) { serial "send_to_matrix" { - proxy.receive_to_matrix(rhs_sdag_idx, vec_map[vec_idx].size(), vec_map[vec_idx].data()); - + double* vector_to_send = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), vec_map[vec_idx]).data(); + + if (is_vec_mat) { + std::size_t yIndx = (thisIndex * vec_block_size) / row_block_len; + std::size_t numChunks = std::ceil(vec_map[vec_idx].size() / (row_block_len * 1.0)); + for(std::size_t i = 0; i < numChunks; i++) { + for(std::size_t j = 0; j < numCharesX; j++) { + proxy(j, yIndx + i).receive_to_matrix(rhs_sdag_idx, + (i == (numChunks - 1) ? (vec_map[vec_idx].size() - ((i - 1) * row_block_len)) : row_block_len) + ,vector_to_send + i * row_block_len); + } + } + } else { + std::size_t xIndx = (thisIndex * vec_block_size) / col_block_len; + std::size_t numChunks = std::ceil(vec_map[vec_idx].size() / (col_block_len * 1.0)); + for(std::size_t i = 0; i < numChunks; i++) { + for(std::size_t j = 0; j < numCharesY; j++) { + proxy(xIndx + i, j).receive_to_matrix(rhs_sdag_idx, + (i == (numChunks - 1) ? (vec_map[vec_idx].size() - ((i - 1) * col_block_len)) : col_block_len) + ,vector_to_send + i * col_block_len); + } + } + } + ++SDAG_INDEX; }} // send to matrix @@ -188,20 +203,23 @@ module libcharmtyles serial "update vector" { // TODO: use vector back_inserter here! if (vector_idx == vec_map.size()) - vec_map.emplace_back(std::vector(len)); + vec_map.emplace_back(Kokkos::View("FIXME_2", len)); - std::copy(result, result + len, vec_map[vector_idx].begin()); + auto host_cpy = Kokkos::create_mirror_view(vec_map[vector_idx]); + std::copy(result, result + len, host_cpy.data()); + Kokkos::deep_copy(vec_map[vector_idx], host_cpy); ++SDAG_INDEX; }}} // update index + update vector when reduce_sum[SDAG_INDEX](int sdag_idx, int vector_id, int scal_sdag_idx) { serial "reduce_sum" { - std::vector& lhs = vec_map[vector_id]; + Kokkos::View lhs = vec_map[vector_id]; - Eigen::Map elhs(lhs.data(), lhs.size()); - - double result = elhs.sum(); + double result = 0.0; + Kokkos::parallel_reduce("reduce_sum", lhs.extent(0), KOKKOS_LAMBDA(const int i, double& local_sum) { + local_sum += lhs(i); + }, result); CkCallback cb(CkReductionTarget(scalar_impl, reduction), scalar_impl_proxy); contribute(sizeof(double), &result, CkReduction::sum_double, cb, scal_sdag_idx); @@ -211,7 +229,7 @@ module libcharmtyles when norm_p[SDAG_INDEX](int sdag_idx, int vector_id, int p, int scal_sdag_idx) { serial "norm_p" { - std::vector& lhs = vec_map[vector_id]; + Kokkos::View lhs = vec_map[vector_id]; Eigen::Map elhs(lhs.data(), lhs.size()); @@ -225,7 +243,7 @@ module libcharmtyles when min[SDAG_INDEX](int sdag_idx, int vector_id, int scal_sdag_idx) { serial "min" { - std::vector& lhs = vec_map[vector_id]; + Kokkos::View lhs = vec_map[vector_id]; Eigen::Map elhs(lhs.data(), lhs.size()); @@ -240,7 +258,7 @@ module libcharmtyles when max[SDAG_INDEX](int sdag_idx, int vector_id, int scal_sdag_idx) { serial "max" { - std::vector& lhs = vec_map[vector_id]; + Kokkos::View lhs = vec_map[vector_id]; Eigen::Map elhs(lhs.data(), lhs.size()); @@ -268,8 +286,9 @@ module libcharmtyles std::vector arr_portion(vec_size + 1); arr_portion[0] = static_cast(index); - std::copy(vec_map[vector_id].begin(), vec_map[vector_id].end(), arr_portion.begin() + 1); - + auto host_vector = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), vec_map[vector_id]); + std::copy(host_vector.data(), host_vector.data() + host_vector.size(), arr_portion.begin() + 1); + CkCallback cb(CkReductionTarget(get_vec_future, construct_vector), proxy); contribute(arr_portion, CkReduction::set, cb); ++SDAG_INDEX; @@ -277,7 +296,7 @@ module libcharmtyles when all[SDAG_INDEX](int sdag_index, int vector_id, CProxy_set_future proxy) { serial "all" { - bool res = std::all_of(vec_map[vector_id].begin(), vec_map[vector_id].end(), + bool res = std::all_of(vec_map[vector_id].data(), vec_map[vector_id].data() + vec_map[vector_id].size(), [](double val) { return val != 0.0; }); CkCallback cb(CkReductionTarget(set_future, evaluate_bool), proxy); @@ -287,7 +306,7 @@ module libcharmtyles when any[SDAG_INDEX](int sdag_index, int vector_id, CProxy_set_future proxy) { serial "any" { - bool res = std::any_of(vec_map[vector_id].begin(), vec_map[vector_id].end(), + bool res = std::any_of(vec_map[vector_id].data(), vec_map[vector_id].data() + vec_map[vector_id].size(), [](double val) { return val != 0.0; }); CkCallback cb(CkReductionTarget(set_future, evaluate_bool), proxy); @@ -312,7 +331,7 @@ module libcharmtyles // Check if this global index falls within chares range if (global_index >= start_index && global_index < end_index) { size_t local_index = global_index - start_index; - samples.push_back({static_cast(i), vec_map[vector_id][local_index]}); + samples.push_back({static_cast(i), vec_map[vector_id](local_index)}); } } @@ -353,7 +372,7 @@ module libcharmtyles // Check if this global index falls within chares range if (global_index >= start_index && global_index < end_index) { size_t local_index = global_index - start_index; - samples.push_back({static_cast(i), vec_map[vector_id][local_index]}); + samples.push_back({static_cast(i), vec_map[vector_id](local_index)}); } } @@ -389,7 +408,7 @@ module libcharmtyles // Check if this global index falls within chares range if (global_index >= start_index && global_index < end_index) { size_t local_index = global_index - start_index; - samples.push_back({static_cast(i), vec_map[vector_id][local_index]}); + samples.push_back({static_cast(i), vec_map[vector_id](local_index)}); } } @@ -424,7 +443,7 @@ module libcharmtyles // Check if this global index falls within chares range if (global_index >= start_index && global_index < end_index) { size_t local_index = global_index - start_index; - samples.push_back({static_cast(i), vec_map[vector_id][local_index]}); + samples.push_back({static_cast(i), vec_map[vector_id](local_index)}); } } @@ -476,7 +495,7 @@ module libcharmtyles int count = 0; for (size_t global_idx = intersect_start; global_idx < intersect_end; ++global_idx) { size_t local_idx = global_idx - start_index; - sum += vec_map[vector_id][local_idx]; + sum += vec_map[vector_id](local_idx); count++; } if (count > 0) { @@ -539,7 +558,7 @@ module libcharmtyles double max_val = std::numeric_limits::lowest(); for (size_t global_idx = intersect_start; global_idx < intersect_end; ++global_idx) { size_t local_idx = global_idx - start_index; - max_val = std::max(max_val, vec_map[vector_id][local_idx]); + max_val = std::max(max_val, vec_map[vector_id](local_idx)); } chunk_data.push_back({static_cast(chunk_id), max_val}); } @@ -598,7 +617,7 @@ module libcharmtyles double min_val = std::numeric_limits::max(); for (size_t global_idx = intersect_start; global_idx < intersect_end; ++global_idx) { size_t local_idx = global_idx - start_index; - min_val = std::min(min_val, vec_map[vector_id][local_idx]); + min_val = std::min(min_val, vec_map[vector_id](local_idx)); } chunk_data.push_back({static_cast(chunk_id), min_val}); } @@ -632,8 +651,8 @@ module libcharmtyles entry void compute(int, std::vector>, CProxy_set_future); entry void compute(int, std::vector>); entry void dot(int, int, int, int); - entry void send_to_matrix(int, int, int, CProxy_matrix_impl); - entry [reductiontarget] void update_vector(int len, double result[len]); + entry void send_to_matrix(int, int, int, int, int, int, int, bool, CProxy_matrix_impl); + entry void update_vector(int len, double result[len]); entry void update_index(int, int); entry void reduce_sum(int, int, int); entry void norm_p(int, int, int, int); @@ -671,16 +690,19 @@ module libcharmtyles std::size_t num_rows = get_mat_rows(total_rows); std::size_t num_cols = get_mat_cols(total_cols); - ct::util::matrix_view mat{num_rows, num_cols}; + Kokkos::View mat("mat" + std::to_string(node_id), num_rows, num_cols); + auto mat_host = Kokkos::create_mirror_view(mat); + for (int row_id = 0; row_id != num_rows; ++row_id) { for (int col_id = 0; col_id != num_cols; ++col_id) { - mat(row_id, col_id) = gen_ptr->generate( + mat_host(row_id, col_id) = gen_ptr->generate( thisIndex.y * row_block_len + row_id, thisIndex.x * col_block_len + col_id); } } - mat_map.emplace_back(std::move(mat)); + Kokkos::deep_copy(mat, mat_host); + mat_map.emplace_back(mat); ++SDAG_INDEX; }} @@ -715,79 +737,59 @@ module libcharmtyles ++SDAG_INDEX; }} + when update_active_chares[SDAG_INDEX](int sdag_index) + serial "update_active_chares" { + int process = CkNodeOf(CkMyPe()); + CProxyElement_matrix_impl myProxy = thisProxy(thisIndex.x, thisIndex.y); + reductionMgmtPayload data { process, sdag_index, myProxy }; + + CkCallback cb(CkReductionTarget(reductionGroup, numActiveChares), reductionMgmt); + contribute(sizeof(data), &data, CkReduction::set, cb); + } + when mat_vec_dot[SDAG_INDEX]( - int sdag_index, int mat_idx, int result_sdag_idx, - CProxy_vector_impl result_proxy, int result_vec_idx, int result_size) { + int sdag_index, int mat_idx, + CProxy_vector_impl result_proxy, int result_size) { + when active_chares_set[SDAG_INDEX](int sdag_idx) { when receive_to_matrix[SDAG_INDEX](int sdag_idx, int len, double* data) serial "mat_vec_dot" { + std::size_t local_result_size = mat_map[mat_idx].extent(0); + Kokkos::View local_result("local_result", local_result_size); - // Get the subvector indices - std::size_t block_dim = col_block_len; - std::size_t vec_size = block_dim; - if (thisIndex.x == num_chares_x - 1 && block_dim % col_block_len != 0) { - vec_size = len % col_block_len; - } - - Eigen::Map elhs(data + thisIndex.x * block_dim, vec_size); - Eigen::Map - erhs(mat_map[mat_idx].data(), mat_map[mat_idx].rows(), mat_map[mat_idx].cols()); - - double result[result_size]; - for (int i = 0; i != result_size; ++i) - result[i] = 0; - - Eigen::Map eres(result + thisIndex.y * row_block_len, mat_map[mat_idx].rows()); - eres = erhs * elhs; - - // TODO: Use Section Reduction! - CkCallback cb(CkReductionTarget(vector_impl, update_vector), result_proxy); - contribute((result_size) * sizeof(double), result, CkReduction::sum_double, cb); + mat_vec_dot_impl(mat_idx, data, local_result); + auto local_result_host = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), local_result); + reductionMgmt.ckLocalBranch()->accumulate(result_proxy, result_size, thisIndex.y * row_block_len, local_result_size, local_result_host.data()); ++SDAG_INDEX; - }} // matrix vector dot product + }}} // matrix vector dot product when vec_mat_dot[SDAG_INDEX]( - int sdag_index, int mat_idx, int result_sdag_idx, - CProxy_vector_impl result_proxy, int result_vec_idx, int result_size) { + int sdag_index, int mat_idx, + CProxy_vector_impl result_proxy, int result_size) { + when active_chares_set[SDAG_INDEX](int sdag_idx) { when receive_to_matrix[SDAG_INDEX](int sdag_idx, int len, double* data) serial "vec_mat_dot" { + std::size_t local_result_size = mat_map[mat_idx].extent(1); + Kokkos::View local_result("local_result", local_result_size); - // Get the subvector indices - std::size_t block_dim = row_block_len; - std::size_t vec_size = block_dim; - if (thisIndex.y == num_chares_y - 1 && block_dim % row_block_len != 0) { - vec_size = len % row_block_len; - } - - Eigen::Map elhs(data + thisIndex.y * block_dim, vec_size); - Eigen::Map - erhs(mat_map[mat_idx].data(), mat_map[mat_idx].rows(), mat_map[mat_idx].cols()); - - double result[result_size]; - for (int i = 0; i != result_size; ++i) - result[i] = 0; - - Eigen::Map eres(result + thisIndex.x * col_block_len, mat_map[mat_idx].cols()); - eres = elhs * erhs; - - // TODO: Use Section Reduction! - CkCallback cb(CkReductionTarget(vector_impl, update_vector), result_proxy); - contribute((result_size) * sizeof(double), result, CkReduction::sum_double, cb); + vec_mat_dot_impl(mat_idx, data, local_result); + auto local_result_host = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), local_result); + reductionMgmt.ckLocalBranch()->accumulate(result_proxy, result_size, thisIndex.x * col_block_len, local_result_size, local_result_host.data()); ++SDAG_INDEX; - }} // vector matrix dot product + }}} // vector matrix dot product when mat_mat_mul[SDAG_INDEX]( int sdag_index, int mat_idx, int mat_A_idx, int mat_B_idx) { serial "initial_send" { double* data_A = mat_map[mat_A_idx].data(); - std::size_t rows_A = mat_map[mat_A_idx].rows(); - std::size_t cols_A = mat_map[mat_A_idx].cols(); + std::size_t rows_A = mat_map[mat_A_idx].extent(0); + std::size_t cols_A = mat_map[mat_A_idx].extent(1); thisProxy((thisIndex.x-thisIndex.y+num_chares_y)%num_chares_x, thisIndex.y).inputA(0, data_A, rows_A, cols_A); double* data_B = mat_map[mat_B_idx].data(); - std::size_t rows_B = mat_map[mat_B_idx].rows(); - std::size_t cols_B = mat_map[mat_B_idx].cols(); + std::size_t rows_B = mat_map[mat_B_idx].extent(0); + std::size_t cols_B = mat_map[mat_B_idx].extent(1); thisProxy(thisIndex.x, (thisIndex.y-thisIndex.x+num_chares_x)%num_chares_y).inputB(0, data_B, rows_B, cols_B); } // For all block @@ -803,8 +805,8 @@ module libcharmtyles Eigen::Map matA(blockA, M, KA); Eigen::Map matB(blockB, KB, N); - ct::util::matrix_view& result_mat = mat_map[mat_idx]; - Eigen::Map matC(result_mat.data(), result_mat.rows(), result_mat.cols()); + Kokkos::View& result_mat = mat_map[mat_idx]; + Eigen::Map matC(result_mat.data(), result_mat.extent(0), result_mat.extent(1)); matC += matA * matB; @@ -828,11 +830,12 @@ module libcharmtyles when reduce_sum[SDAG_INDEX](int sdag_idx, int matrix_id, int scal_sdag_idx) { serial "reduce_sum" { - ct::util::matrix_view& lhs = mat_map[matrix_id]; + Kokkos::View& lhs = mat_map[matrix_id]; - Eigen::Map elhs(lhs.data(), lhs.rows(), lhs.cols()); - - double result = elhs.sum(); + double result = 0.0; + Kokkos::parallel_reduce("reduce_sum", Kokkos::MDRangePolicy>({0,0}, {lhs.extent(0), lhs.extent(1)}), KOKKOS_LAMBDA(const int i, const int j, double& local_sum) { + local_sum += lhs(i, j); + }, result); CkCallback cb(CkReductionTarget(scalar_impl, reduction), scalar_impl_proxy); contribute(sizeof(double), &result, CkReduction::sum_double, cb, scal_sdag_idx); @@ -842,9 +845,10 @@ module libcharmtyles when get_value[SDAG_INDEX](int sdag_index, int matrix_id, CProxy_get_mat_future proxy) { serial "get_value" { - ct::util::matrix_view& mat = mat_map[matrix_id]; - size_t row_size = mat.rows(); - size_t col_size = mat.cols(); + Kokkos::View& mat = mat_map[matrix_id]; + auto mat_h = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), mat); + size_t row_size = mat.extent(0); + size_t col_size = mat.extent(1); size_t row_index = thisIndex.y*col_block_len; size_t col_index = thisIndex.x*row_block_len; @@ -853,7 +857,7 @@ module libcharmtyles arr_portion[0] = static_cast(row_index); arr_portion[1] = static_cast(col_index); arr_portion[2] = static_cast(row_size); - std::copy(mat.data(), mat.data()+(row_size*col_size), arr_portion.begin() + 3); + std::copy(mat_h.data(), mat_h.data()+(row_size*col_size), arr_portion.begin() + 3); CkCallback cb(CkReductionTarget(get_mat_future, construct_matrix), proxy); contribute(arr_portion, CkReduction::set, cb); @@ -862,9 +866,9 @@ module libcharmtyles when any[SDAG_INDEX](int sdag_index, int matrix_id, CProxy_set_future proxy) { serial "any" { - ct::util::matrix_view& mat = mat_map[matrix_id]; - size_t row_size = mat.rows(); - size_t col_size = mat.cols(); + Kokkos::View& mat = mat_map[matrix_id]; + size_t row_size = mat.extent(0); + size_t col_size = mat.extent(1); bool res = std::any_of(mat.data(), mat.data()+(row_size*col_size), [](double val) { return val != 0.0; }); @@ -876,9 +880,9 @@ module libcharmtyles when all[SDAG_INDEX](int sdag_index, int matrix_id, CProxy_set_future proxy) { serial "all" { - ct::util::matrix_view& mat = mat_map[matrix_id]; - size_t row_size = mat.rows(); - size_t col_size = mat.cols(); + Kokkos::View& mat = mat_map[matrix_id]; + size_t row_size = mat.extent(0); + size_t col_size = mat.extent(1); bool res = std::all_of(mat.data(), mat.data()+(row_size*col_size), [](double val) { return val != 0.0; }); @@ -899,8 +903,10 @@ module libcharmtyles entry void compute(int, std::vector>); entry void synchronize(int, CProxy_set_future); - entry void mat_vec_dot(int, int, int, CProxy_vector_impl, int, int); - entry void vec_mat_dot(int, int, int, CProxy_vector_impl, int, int); + entry void update_active_chares(int); + entry void active_chares_set(int); + entry void mat_vec_dot(int, int, CProxy_vector_impl, int); + entry void vec_mat_dot(int, int, CProxy_vector_impl, int); entry void receive_to_matrix(int, int len, double data[len]); entry void reduce_sum(int, int, int); @@ -908,4 +914,18 @@ module libcharmtyles entry void any(int sdag_index, int matrix_id, CProxy_set_future proxy); entry void all(int sdag_index, int matrix_id, CProxy_set_future proxy); } + + group KokkosGroup { + entry KokkosGroup(); + entry void finalize(); + entry void dkload(uint64_t); + }; + + nodegroup reductionGroup { + entry reductionGroup(); + entry void accumulate(CProxy_vector_impl result_proxy, int result_size, int indx, int len, double data[len]); + entry void reduce(bool dummy, int len, double data[len]); + entry void reset(); + entry [reductiontarget] void numActiveChares(CkReductionMsg *msg); + } } diff --git a/charmtyles/backend/charmtyles_base.hpp b/charmtyles/backend/charmtyles_base.hpp index 9898110..6655790 100644 --- a/charmtyles/backend/charmtyles_base.hpp +++ b/charmtyles/backend/charmtyles_base.hpp @@ -1,17 +1,172 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include class CProxy_vector_impl; class CProxy_matrix_impl; class CProxy_scalar_impl; class CProxy_get_partial_vec_future; +class CProxy_KokkosGroup; +#include #include +class KokkosGroup : public CBase_KokkosGroup +{ +private: + std::map kernelHandles; + std::string to_string(uint64_t const hash) + { + std::ostringstream oss; + oss << std::hex << std::setw(16) << std::setfill('0') << hash; + return oss.str(); + } + +public: + KokkosGroup() + { + Kokkos::initialize(); + } + + void finalize() + { + // Kokkos::finalize(); + } + + void dkload(uint64_t hash) + { + if (kernelHandles.find(hash) != kernelHandles.end()) + return; + std::string lib_name("libkernel-" + to_string(hash) + ".so"); + void* handle = dlopen(std::string("./" + lib_name).c_str(), RTLD_NOW); + void* functor = dlsym(handle, "run_kernel"); + kernelHandles[hash] = functor; + } + + void* getHandle(uint64_t hash) + { + return kernelHandles[hash]; + } +}; + +CProxy_KokkosGroup kokkosMgmt; + +struct reductionMgmtPayload { + int process; + int sdag_indx; + CProxyElement_matrix_impl proxy; +}; + +class reductionGroup : public CBase_reductionGroup { +private: + int num_active_chares; + std::vector sdag_indexes; + std::vector chunkProxies; + + int resultSize; + int contributeCnt; + std::vector localArr; + CProxy_vector_impl result_proxy; + + int resultCnt; + std::vector resultArr; +public: + reductionGroup() { + num_active_chares = 0; + chunkProxies.reserve(5); + sdag_indexes.reserve(5); + + contributeCnt = 0; + resultSize = 0; + + resultCnt = 0; + } + + void accumulate(CProxy_vector_impl _result_proxy, int result_size, int indx, int len, double* data) { + contributeCnt++; + + if (localArr.size() != result_size) { + localArr.resize(result_size); + std::fill(localArr.begin(), localArr.end(), 0.0); + resultSize = result_size; + result_proxy = _result_proxy; + } + + for (int i = 0; i < len; ++i) + localArr[indx + i] += data[i]; + + if (contributeCnt == num_active_chares) { + thisProxy[0].reduce(false, resultSize, localArr.data()); + } + } + + void reduce(bool dummy, int len, double* data) { + resultCnt++; + + if (!dummy) { + if (resultArr.size() != len) { + resultArr.resize(len); + std::fill(resultArr.begin(), resultArr.end(), 0.0); + } + + for (int i = 0; i < len; ++i) + resultArr[i] += data[i]; + } + + if(resultCnt == CkNumNodes()) { + std::size_t vec_len = CT_ACCESS_SINGLETON(ct::util::array_block_len); + for(int i = 0; ;i++) { + if(i * vec_len >= resultSize) break; + int length = (((i + 1) * vec_len) >= resultSize) ? (resultSize - (i * vec_len)) : vec_len; + result_proxy[i].update_vector(length, resultArr.data() + i * vec_len); + } + } + } + + void numActiveChares(CkReductionMsg *msg) { + CkReduction::setElement* current = (CkReduction::setElement*) msg->getData(); + while (current != NULL) + { + reductionMgmtPayload result = *(reductionMgmtPayload*)(¤t->data); + int process = result.process; + if (process == thisIndex) { + num_active_chares++; + sdag_indexes.emplace_back(result.sdag_indx); + chunkProxies.emplace_back(result.proxy); + } + current = current->next(); + } + + for(int i = 0; i < num_active_chares; i++) + chunkProxies[i].active_chares_set(sdag_indexes[i]); + + if (num_active_chares == 0) + thisProxy[0].reduce(true, 0, nullptr); + } + + void reset() { + num_active_chares = 0; + chunkProxies.clear(); + sdag_indexes.clear(); + + contributeCnt = 0; + resultSize = 0; + localArr.clear(); + + resultCnt = 0; + resultArr.clear(); + } +}; + +CProxy_reductionGroup reductionMgmt; + +#include "codegen.hpp" + /* readonly */ CProxy_scalar_impl scalar_impl_proxy; class set_future : public CBase_set_future @@ -69,8 +224,7 @@ class get_vec_future : public CBase_get_vec_future void construct_vector(CkReductionMsg* msg) { std::vector out(len, 0.); - CkReduction::setElement* current = - (CkReduction::setElement*) msg->getData(); + CkReduction::setElement* current = (CkReduction::setElement*) msg->getData(); while (current != NULL) { double* result = (double*) ¤t->data; @@ -202,131 +356,142 @@ class scalar_impl : public CBase_scalar_impl thisProxy.main_kernel(); } -private: std::vector scal_map; int SDAG_INDEX; }; +#define CHECK_IF_EXIST_ELSE_ADD_VECTOR(node) \ + if (node.name_ == vec_map.size()) \ + { \ + std::size_t vec_dim = get_vec_dim(node.vec_len_); \ + \ + Kokkos::View vec( \ + "vec" + std::to_string(node.name_), vec_dim); \ + vec_map.emplace_back(vec); \ + } + class vector_impl : public CBase_vector_impl { - // Helper private functions -private: - std::size_t get_vec_dim(std::size_t vec_len) +public: + void update_partitions( + std::vector> const& instr_list) { - if (vec_len % vec_block_size == 0) - return vec_block_size; - - if (thisIndex != num_chares - 1) - return vec_block_size; + for (size_t i = 0; i < instr_list.size();) + { + std::vector> region = + ct::util::carveRegion(instr_list, i); - return vec_len % vec_block_size; + if (!region.empty()) + { + for (const auto& instr : region) + CHECK_IF_EXIST_ELSE_ADD_VECTOR(instr[0]); + execute_instruction(region); + i += region.size(); + } + else + { + execute_instruction({instr_list[i]}); + ++i; + } + } } - void print_instructions( - std::vector> const& instr_list) + // Helper method for generator initialization - must be public for CUDA lambdas + Kokkos::View generator_init_impl( + std::size_t vec_dim, std::shared_ptr gen_ptr) { - ckout << "Printing Instructions:" << endl; + Kokkos::View gen_vec("Label", vec_dim); - for (int num_instr = 0; num_instr != instr_list.size(); ++num_instr) + for (int dimX = 0; dimX != vec_dim; ++dimX) { - ckout << "Instruction " << num_instr << ": "; - ct::util::parse_ast(instr_list[num_instr], 0); - ckout << endl; + gen_vec(dimX) = + gen_ptr->generate(thisIndex * vec_block_size + dimX); } + + return gen_vec; } - // Instruction related private functions -private: - void update_partitions( - std::vector> const& instr_list) + // Helper method for vector dot product - must be public for CUDA lambdas + double vector_dot_impl(int lhs_id, int rhs_id) { - for (auto const& ast : instr_list) - execute_instruction(ast); + Kokkos::View lhs = vec_map[lhs_id]; + Kokkos::View rhs = vec_map[rhs_id]; + + double result = 0.0; + Kokkos::parallel_reduce( + lhs.size(), + KOKKOS_LAMBDA(const int i, double& local_sum) { + local_sum += lhs(i) * rhs(i); + }, + result); + + return result; } void execute_instruction( - std::vector const& instruction, - std::size_t index = 0) + std::vector> const& region) { - ct::vec_impl::vec_node const& node = instruction[index]; + const std::vector& instruction = region[0]; + const ct::vec_impl::vec_node& node = instruction[0]; std::size_t node_id = node.name_; - // Useful variables in switch statement - std::size_t vec_dim{0}; - std::size_t total_size{0}; - std::size_t unrolled_size{0}; - std::size_t remainder_start{0}; - std::size_t copy_id{0}; - - std::shared_ptr const& unary_expr = - node.unary_expr_; - - std::shared_ptr const& binary_expr = - node.binary_expr_; - - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_real_distribution<> dist(0., 1.); - - switch (instruction[index].operation_) + switch (node.operation_) { case ct::util::Operation::init_random: - + { CkAssert((vec_map.size() == node_id) && "A vector is initialized before a dependent vector " "initialization."); - vec_dim = get_vec_dim(node.vec_len_); - - // TODO: Do Random Initialization here - vec_map.emplace_back(std::vector(vec_dim)); - - for (double& val : vec_map[node.name_]) - { - val = dist(gen); - } - + std::size_t vec_dim = get_vec_dim(node.vec_len_); + Kokkos::View vec("vec" + std::to_string(node_id), vec_dim); + vec_map.emplace_back(vec); + unsigned int seed = + static_cast(time(nullptr)) + node_id; + Kokkos::Random_XorShift64_Pool<> rand_pool(seed); + + Kokkos::parallel_for( + "init_random_" + std::to_string(node_id), + vec_map[node_id].size(), KOKKOS_LAMBDA(int i) { + auto gen = rand_pool.get_state(); + double r = gen.drand(); + vec_map[node_id](i) = r; + rand_pool.free_state(gen); + }); + } return; - case ct::util::Operation::init_value: + { CkAssert((vec_map.size() == node_id) && "A vector is initialized before a dependent vector " "initialization."); - vec_dim = get_vec_dim(node.vec_len_); + std::size_t vec_dim = get_vec_dim(node.vec_len_); // TODO: Do Random Initialization here - vec_map.emplace_back(std::vector(vec_dim, node.value_)); - + Kokkos::View vec("vec" + std::to_string(node_id), vec_dim); + Kokkos::deep_copy(vec, node.value_); + vec_map.emplace_back(vec); + } return; - case ct::util::Operation::copy: - copy_id = node.copy_id_; + { + std::size_t copy_id = node.copy_id_; if (node_id == vec_map.size()) vec_map.emplace_back( - std::vector(vec_map[copy_id].size())); + Kokkos::View("FIXME", vec_map[copy_id].size())); - total_size = vec_map[node_id].size(); - unrolled_size = vec_map[node_id].size() / 4; - remainder_start = unrolled_size * 4; - - for (std::size_t i = 0; i != remainder_start; i += 4) - { - vec_map[node_id][i] = vec_map[copy_id][i]; - vec_map[node_id][i + 1] = vec_map[copy_id][i + 1]; - vec_map[node_id][i + 2] = vec_map[copy_id][i + 2]; - vec_map[node_id][i + 3] = vec_map[copy_id][i + 3]; - } - - for (std::size_t i = remainder_start; i != total_size; ++i) - { - vec_map[node_id][i] = vec_map[copy_id][i]; - } + auto dest = vec_map[node_id]; + auto src = vec_map[copy_id]; + Kokkos::parallel_for( + "copy_" + std::to_string(copy_id) + "_" + + std::to_string(node_id), + dest.size(), KOKKOS_LAMBDA(int i) { dest(i) = src(i); }); + } return; - case ct::util::Operation::add: case ct::util::Operation::sub: case ct::util::Operation::multiply: @@ -343,274 +508,121 @@ class vector_impl : public CBase_vector_impl case ct::util::Operation::unary_expr: case ct::util::Operation::binary_expr: case ct::util::Operation::where: - - if (node_id == vec_map.size()) - { - vec_dim = get_vec_dim(node.vec_len_); - - vec_map.emplace_back(std::vector(vec_dim)); - } - - total_size = vec_map[node_id].size(); - unrolled_size = vec_map[node_id].size() / 4; - remainder_start = unrolled_size * 4; - - for (std::size_t i = 0; i != remainder_start; i += 4) - { - vec_map[node_id][i] = execute_ast_for_idx(instruction, 0, i); - vec_map[node_id][i + 1] = - execute_ast_for_idx(instruction, 0, i + 1); - vec_map[node_id][i + 2] = - execute_ast_for_idx(instruction, 0, i + 2); - vec_map[node_id][i + 3] = - execute_ast_for_idx(instruction, 0, i + 3); - } - - for (std::size_t i = remainder_start; i != total_size; ++i) - { - vec_map[node_id][i] = execute_ast_for_idx(instruction, 0, i); - } - + { + CHECK_IF_EXIST_ELSE_ADD_VECTOR(node); + Codegen::execute, ct::vec_impl::vec_node, 1>( + instruction[0].kernel, {vec_map[node_id].size()}, vec_map, + region); + } return; case ct::util::Operation::inplace_add: - copy_id = node.copy_id_; - if (node_id == vec_map.size()) + { + CHECK_IF_EXIST_ELSE_ADD_VECTOR(node); + std::size_t copy_id = node.copy_id_; + if (copy_id == -1) { - vec_dim = get_vec_dim(node.vec_len_); - vec_map.emplace_back(std::vector(vec_dim)); + Codegen::execute, ct::vec_impl::vec_node, + 1>(node.kernel, {vec_map[node_id].size()}, vec_map, region); } - total_size = vec_map[node_id].size(); - unrolled_size = total_size / 4; - remainder_start = unrolled_size * 4; - - for (std::size_t i = 0; i != remainder_start; i += 4) + else { - if (copy_id == static_cast(-1)) - { - vec_map[node_id][i] += - execute_ast_for_idx(instruction, 1, i); - vec_map[node_id][i + 1] += - execute_ast_for_idx(instruction, 1, i + 1); - vec_map[node_id][i + 2] += - execute_ast_for_idx(instruction, 1, i + 2); - vec_map[node_id][i + 3] += - execute_ast_for_idx(instruction, 1, i + 3); - } - else - { - vec_map[node_id][i] += vec_map[copy_id][i]; - vec_map[node_id][i + 1] += vec_map[copy_id][i + 1]; - vec_map[node_id][i + 2] += vec_map[copy_id][i + 2]; - vec_map[node_id][i + 3] += vec_map[copy_id][i + 3]; - } - } + auto dest = vec_map[node_id]; + auto src = vec_map[copy_id]; - for (std::size_t i = remainder_start; i != total_size; ++i) - { - if (copy_id == static_cast(-1)) - vec_map[node_id][i] += - execute_ast_for_idx(instruction, 1, i); - else - vec_map[node_id][i] += vec_map[copy_id][i]; + Kokkos::parallel_for( + "copy_" + std::to_string(copy_id) + "_" + + std::to_string(node_id), + dest.size(), KOKKOS_LAMBDA(int i) { dest(i) += src(i); }); } - + } return; case ct::util::Operation::inplace_sub: - copy_id = node.copy_id_; - if (node_id == vec_map.size()) + { + CHECK_IF_EXIST_ELSE_ADD_VECTOR(node); + std::size_t copy_id = node.copy_id_; + if (copy_id == -1) { - vec_dim = get_vec_dim(node.vec_len_); - vec_map.emplace_back(std::vector(vec_dim)); + Codegen::execute, ct::vec_impl::vec_node, + 1>(node.kernel, {vec_map[node_id].size()}, vec_map, region); } - total_size = vec_map[node_id].size(); - unrolled_size = total_size / 4; - remainder_start = unrolled_size * 4; - for (std::size_t i = 0; i != remainder_start; i += 4) + else { - if (copy_id == static_cast(-1)) - { - vec_map[node_id][i] -= - execute_ast_for_idx(instruction, 1, i); - vec_map[node_id][i + 1] -= - execute_ast_for_idx(instruction, 1, i + 1); - vec_map[node_id][i + 2] -= - execute_ast_for_idx(instruction, 1, i + 2); - vec_map[node_id][i + 3] -= - execute_ast_for_idx(instruction, 1, i + 3); - } - else - { - vec_map[node_id][i] -= vec_map[copy_id][i]; - vec_map[node_id][i + 1] -= vec_map[copy_id][i + 1]; - vec_map[node_id][i + 2] -= vec_map[copy_id][i + 2]; - vec_map[node_id][i + 3] -= vec_map[copy_id][i + 3]; - } - } + auto dest = vec_map[node_id]; + auto src = vec_map[copy_id]; - for (std::size_t i = remainder_start; i != total_size; ++i) - { - if (copy_id == static_cast(-1)) - vec_map[node_id][i] -= - execute_ast_for_idx(instruction, 1, i); - else - vec_map[node_id][i] -= vec_map[copy_id][i]; + Kokkos::parallel_for( + "copy_" + std::to_string(copy_id) + "_" + + std::to_string(node_id), + dest.size(), KOKKOS_LAMBDA(int i) { dest(i) -= src(i); }); } + } return; case ct::util::Operation::inplace_divide: - copy_id = node.copy_id_; - if (node_id == vec_map.size()) - { - vec_dim = get_vec_dim(node.vec_len_); - vec_map.emplace_back(std::vector(vec_dim)); - } - total_size = vec_map[node_id].size(); - unrolled_size = total_size / 4; - remainder_start = unrolled_size * 4; - for (std::size_t i = 0; i != remainder_start; i += 4) - { - if (copy_id == static_cast(-1)) - { - vec_map[node_id][i] /= - execute_ast_for_idx(instruction, 1, i); - vec_map[node_id][i + 1] /= - execute_ast_for_idx(instruction, 1, i + 1); - vec_map[node_id][i + 2] /= - execute_ast_for_idx(instruction, 1, i + 2); - vec_map[node_id][i + 3] /= - execute_ast_for_idx(instruction, 1, i + 3); - } - else - { - vec_map[node_id][i] /= vec_map[copy_id][i]; - vec_map[node_id][i + 1] /= vec_map[copy_id][i + 1]; - vec_map[node_id][i + 2] /= vec_map[copy_id][i + 2]; - vec_map[node_id][i + 3] /= vec_map[copy_id][i + 3]; - } - } - - for (std::size_t i = remainder_start; i != total_size; ++i) + { + CHECK_IF_EXIST_ELSE_ADD_VECTOR(node); + std::size_t copy_id = node.copy_id_; + if (copy_id == -1) { - if (copy_id == static_cast(-1)) - vec_map[node_id][i] /= - execute_ast_for_idx(instruction, 1, i); - else - vec_map[node_id][i] /= vec_map[copy_id][i]; + Codegen::execute, ct::vec_impl::vec_node, + 1>(node.kernel, {vec_map[node_id].size()}, vec_map, region); } - return; - case ct::util::Operation::axpy: - { - if (node_id == vec_map.size()) + else { - vec_dim = get_vec_dim(node.vec_len_); + auto dest = vec_map[node_id]; + auto src = vec_map[copy_id]; - vec_map.emplace_back(std::vector(vec_dim)); + Kokkos::parallel_for( + "copy_" + std::to_string(copy_id) + "_" + + std::to_string(node_id), + dest.size(), KOKKOS_LAMBDA(int i) { dest(i) /= src(i); }); } - - double alpha = node.value_; - std::vector& x = vec_map[node.left_]; - std::vector& y = vec_map[node.right_]; - std::vector& res = vec_map[node.name_]; - - Eigen::Map ex(x.data(), x.size()); - Eigen::Map ey(y.data(), y.size()); - Eigen::Map er(res.data(), res.size()); - - er = alpha * ex + ey; - - return; } + return; + case ct::util::Operation::dealloc: { + /** + * TODO: This might fail due to a double free depending on how charm runtime + * destroys the charmArrays. + */ + Kokkos::View releivingRef; + vec_map[node_id] = releivingRef; + } return; case ct::util::Operation::custom_expr: { - if (node_id == vec_map.size()) - { - vec_dim = get_vec_dim(node.vec_len_); - - vec_map.emplace_back(std::vector(vec_dim)); - } + CHECK_IF_EXIST_ELSE_ADD_VECTOR(node); const ct::vec_impl::vec_node& node = instruction[0]; - node.custom_expr_->operator()(vec_dim, vec_map[node_id], - vec_map[instruction[node.left_].name_]); - return; - } + auto a_host = Kokkos::create_mirror_view_and_copy( + Kokkos::HostSpace(), vec_map[node_id]); + const std::size_t n = a_host.extent(0); + auto a = std::vector(a_host.data(), a_host.data() + n); - default: - CmiAbort("Operation not implemented"); - } - } + auto b_host = Kokkos::create_mirror_view_and_copy( + Kokkos::HostSpace(), vec_map[instruction[node.left_].name_]); + auto b = std::vector(b_host.data(), b_host.data() + n); - double execute_ast_for_idx( - std::vector const& instruction, - std::size_t curr_idx, std::size_t iter_idx) - { - const ct::vec_impl::vec_node& node = instruction[curr_idx]; + node.custom_expr_->operator()(n, a, b); - switch (node.operation_) - { - case ct::util::Operation::noop: - return vec_map[node.name_][iter_idx]; - case ct::util::Operation::add: - return execute_ast_for_idx(instruction, node.left_, iter_idx) + - execute_ast_for_idx(instruction, node.right_, iter_idx); - case ct::util::Operation::sub: - return execute_ast_for_idx(instruction, node.left_, iter_idx) - - execute_ast_for_idx(instruction, node.right_, iter_idx); - case ct::util::Operation::divide: - return execute_ast_for_idx(instruction, node.left_, iter_idx) / - execute_ast_for_idx(instruction, node.right_, iter_idx); - case ct::util::Operation::multiply: - return execute_ast_for_idx(instruction, node.left_, iter_idx) * - execute_ast_for_idx(instruction, node.right_, iter_idx); - case ct::util::Operation::eq: - return execute_ast_for_idx(instruction, node.left_, iter_idx) == - execute_ast_for_idx(instruction, node.right_, iter_idx); - case ct::util::Operation::neq: - return execute_ast_for_idx(instruction, node.left_, iter_idx) != - execute_ast_for_idx(instruction, node.right_, iter_idx); - case ct::util::Operation::geq: - return execute_ast_for_idx(instruction, node.left_, iter_idx) >= - execute_ast_for_idx(instruction, node.right_, iter_idx); - case ct::util::Operation::leq: - return execute_ast_for_idx(instruction, node.left_, iter_idx) <= - execute_ast_for_idx(instruction, node.right_, iter_idx); - case ct::util::Operation::greater: - return execute_ast_for_idx(instruction, node.left_, iter_idx) > - execute_ast_for_idx(instruction, node.right_, iter_idx); - case ct::util::Operation::lesser: - return execute_ast_for_idx(instruction, node.left_, iter_idx) < - execute_ast_for_idx(instruction, node.right_, iter_idx); - case ct::util::Operation::logical_and: - return execute_ast_for_idx(instruction, node.left_, iter_idx) && - execute_ast_for_idx(instruction, node.right_, iter_idx); - case ct::util::Operation::logical_or: - return execute_ast_for_idx(instruction, node.left_, iter_idx) || - execute_ast_for_idx(instruction, node.right_, iter_idx); - case ct::util::Operation::logical_not: - return !execute_ast_for_idx(instruction, node.left_, iter_idx); - case ct::util::Operation::unary_expr: - return node.unary_expr_->operator()(iter_idx, - execute_ast_for_idx(instruction, node.left_, iter_idx)); - case ct::util::Operation::binary_expr: - return node.binary_expr_->operator()(iter_idx, - execute_ast_for_idx(instruction, node.left_, iter_idx), - execute_ast_for_idx(instruction, node.right_, iter_idx)); - case ct::util::Operation::broadcast: - return node.value_; - case ct::util::Operation::where: - if (execute_ast_for_idx(instruction, node.ter_, iter_idx)) - { - return execute_ast_for_idx(instruction, node.left_, iter_idx); - } - else + Kokkos::View a_new("vec" + std::to_string(node_id), n); + Kokkos::View b_new( + "vec" + std::to_string(instruction[node.left_].name_), n); + + auto a_new_host = Kokkos::create_mirror_view(a_new); + auto b_new_host = Kokkos::create_mirror_view(b_new); + + for (auto i = 0; i < n; i++) { - return execute_ast_for_idx(instruction, node.right_, iter_idx); + a_new_host(i) = a[i]; + b_new_host(i) = b[i]; } + Kokkos::deep_copy(a_new, a_new_host); + Kokkos::deep_copy(b_new, b_new_host); + vec_map[node_id] = a_new; + vec_map[instruction[node.left_].name_] = b_new; + } + return; default: CmiAbort("Operation not implemented"); } - - // Control should not reach here! - return 0.; } public: @@ -627,14 +639,49 @@ class vector_impl : public CBase_vector_impl } private: + std::size_t get_vec_dim(std::size_t vec_len) + { + if (vec_len % vec_block_size == 0) + return vec_block_size; + + if (thisIndex != num_chares - 1) + return vec_block_size; + + return vec_len % vec_block_size; + } + + void print_instructions( + std::vector> const& instr_list) + { + ckout << "Printing Instructions:" << endl; + + for (int num_instr = 0; num_instr != instr_list.size(); ++num_instr) + { + ckout << "Instruction " << num_instr << ": "; + ct::util::parse_ast(instr_list[num_instr], 0); + ckout << endl; + } + } + int num_chares; - std::vector> vec_map; + std::vector> vec_map; int SDAG_INDEX; int vec_block_size; int dot_counter = 0; }; +#define CHECK_IF_EXIST_ELSE_ADD_MATRIX(node) \ + if (node.name_ == mat_map.size()) \ + { \ + std::size_t num_rows = get_mat_rows(node.mat_row_len_); \ + std::size_t num_cols = get_mat_cols(node.mat_col_len_); \ + \ + Kokkos::View mat( \ + "mat" + std::to_string(node.name_), num_rows, num_cols); \ + mat_map.emplace_back(mat); \ + } + class matrix_impl : public CBase_matrix_impl { // Helper private functions @@ -674,110 +721,140 @@ class matrix_impl : public CBase_matrix_impl } } - // Instruction related private functions -private: + // Instruction related functions - must be public for CUDA lambdas +public: void update_partitions( std::vector> const& instr_list) { - for (auto const& ast : instr_list) - execute_instruction(ast); + for (size_t i = 0; i < instr_list.size();) + { + std::vector> region = + ct::util::carveRegion(instr_list, i); + + if (!region.empty()) + { + for (const auto& instr : region) + CHECK_IF_EXIST_ELSE_ADD_MATRIX(instr[0]); + execute_instruction(region); + i += region.size(); + } + else + { + execute_instruction({instr_list[i]}); + ++i; + } + } + } + + // Helper method for matrix-vector multiplication - must be public for CUDA lambdas + void mat_vec_dot_impl(int mat_idx, const double* vec_in_data, Kokkos::View& local_result) + { + Kokkos::View mat = mat_map[mat_idx]; + std::size_t num_rows = mat.extent(0); + std::size_t num_cols = mat.extent(1); + + using HostConstVector = Kokkos::View>; + HostConstVector vec_in_host(vec_in_data, num_cols); + + using DeviceVector = Kokkos::View; + DeviceVector vec_in("vec_in_tile", num_cols); + Kokkos::deep_copy(vec_in, vec_in_host); + + // Perform matrix-vector multiplication: result = mat * vec + KokkosBlas::gemv("N" , 1.0 , mat , vec_in , 0.0, local_result); + Kokkos::fence(); + } + + // Helper method for vector-matrix multiplication - must be public for CUDA lambdas + void vec_mat_dot_impl(int mat_idx, const double* vec_in_data, Kokkos::View& local_result) + { + Kokkos::View mat = mat_map[mat_idx]; + std::size_t num_rows = mat.extent(0); + std::size_t num_cols = mat.extent(1); + + using HostConstVector = Kokkos::View>; + HostConstVector vec_in_host(vec_in_data, num_rows); + + using DeviceVector = Kokkos::View; + DeviceVector vec_in("vec_in_tile", num_rows); + Kokkos::deep_copy(vec_in, vec_in_host); + + // Perform vector-matrix multiplication: result = vec * mat + KokkosBlas::gemv("T",1.0,mat,vec_in,0.0,local_result); + Kokkos::fence(); } void execute_instruction( - std::vector const& instruction, - std::size_t index = 0) + std::vector> const& region) { - ct::mat_impl::mat_node const& node = instruction[index]; + const std::vector& instruction = region[0]; + ct::mat_impl::mat_node const& node = instruction[0]; std::size_t node_id = node.name_; - std::shared_ptr const& unary_expr = - node.unary_expr_; - std::shared_ptr const& binary_expr = - node.binary_expr_; - - // Useful variables in switch statement - std::size_t num_rows{0}; - std::size_t num_cols{0}; - std::size_t total_size{0}; - std::size_t unrolled_size{0}; - std::size_t remainder_start{0}; - std::size_t copy_id{0}; - ct::util::matrix_view mat{}; - - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_real_distribution<> dist(0., 1.); switch (node.operation_) { case ct::util::Operation::init_random: - + { CkAssert((mat_map.size() == node_id) && "A matrix is initialized before a dependent matrix " "initialization."); - num_rows = get_mat_rows(node.mat_row_len_); - num_cols = get_mat_cols(node.mat_col_len_); - - mat = ct::util::matrix_view{num_rows, num_cols}; - for (int row = 0; row != mat.rows(); ++row) - for (int col = 0; col != mat.cols(); ++col) - mat(row, col) = dist(gen); - - mat_map.emplace_back(std::move(mat)); - + std::size_t num_rows = get_mat_rows(node.mat_row_len_); + std::size_t num_cols = get_mat_cols(node.mat_col_len_); + + Kokkos::View mat( + "mat" + std::to_string(node_id), num_rows, num_cols); + unsigned int seed = + static_cast(time(nullptr)) + node_id; + Kokkos::Random_XorShift64_Pool<> rand_pool(seed); + + Kokkos::parallel_for( + "init_random_mat_" + std::to_string(node_id), + Kokkos::MDRangePolicy>( + {0, 0}, {num_rows, num_cols}), + KOKKOS_LAMBDA(int i, int j) { + auto gen = rand_pool.get_state(); + double r = gen.drand(); + mat(i, j) = r; + rand_pool.free_state(gen); + }); + mat_map.emplace_back(mat); + } return; - case ct::util::Operation::init_value: + { CkAssert((mat_map.size() == node_id) && "A matrix is initialized before a dependent matrix " "initialization."); - num_rows = get_mat_rows(node.mat_row_len_); - num_cols = get_mat_cols(node.mat_col_len_); - - mat = ct::util::matrix_view{num_rows, num_cols, node.value_}; - mat_map.emplace_back(std::move(mat)); + std::size_t num_rows = get_mat_rows(node.mat_row_len_); + std::size_t num_cols = get_mat_cols(node.mat_col_len_); + Kokkos::View mat( + "mat" + std::to_string(node_id), num_rows, num_cols); + Kokkos::deep_copy(mat, node.value_); + mat_map.emplace_back(mat); + } return; - case ct::util::Operation::copy: - copy_id = node.copy_id_; - - if (node_id == mat_map.size()) - { - num_rows = get_mat_rows(node.mat_row_len_); - num_cols = get_mat_cols(node.mat_col_len_); - - mat = ct::util::matrix_view{num_rows, num_cols}; - - mat_map.emplace_back(std::move(mat)); - } - - total_size = mat_map[node_id].rows(); - unrolled_size = mat_map[node_id].rows() / 4; - remainder_start = unrolled_size * 4; - - for (std::size_t i = 0; i != remainder_start; i += 4) - { - for (std::size_t j = 0; j != mat_map[node_id].cols(); ++j) - { - mat_map[node_id](i, j) = mat_map[copy_id](i, j); - mat_map[node_id](i + 1, j) = mat_map[copy_id](i + 1, j); - mat_map[node_id](i + 2, j) = mat_map[copy_id](i + 2, j); - mat_map[node_id](i + 3, j) = mat_map[copy_id](i + 3, j); - } - } - - for (std::size_t i = remainder_start; i != total_size; ++i) - { - for (std::size_t j = 0; j != mat_map[node_id].cols(); ++j) - { - mat_map[node_id](i, j) = mat_map[copy_id](i, j); - } - } - + { + std::size_t copy_id = node.copy_id_; + CHECK_IF_EXIST_ELSE_ADD_MATRIX(node); + auto dest = mat_map[node_id]; + auto src = mat_map[copy_id]; + + Kokkos::parallel_for( + "copy_mat_" + std::to_string(copy_id) + "_" + + std::to_string(node_id), + Kokkos::MDRangePolicy>( + {0, 0}, {dest.extent(0), dest.extent(1)}), + KOKKOS_LAMBDA(int i, int j) { dest(i, j) = src(i, j); }); + } return; - case ct::util::Operation::add: case ct::util::Operation::sub: case ct::util::Operation::multiply: @@ -794,324 +871,149 @@ class matrix_impl : public CBase_matrix_impl case ct::util::Operation::logical_or: case ct::util::Operation::logical_not: case ct::util::Operation::where: - if (node_id == mat_map.size()) - { - num_rows = get_mat_rows(node.mat_row_len_); - num_cols = get_mat_cols(node.mat_col_len_); - - mat = ct::util::matrix_view{num_rows, num_cols}; - - mat_map.emplace_back(std::move(mat)); - } - - total_size = mat_map[node_id].rows(); - unrolled_size = mat_map[node_id].rows() / 4; - remainder_start = unrolled_size * 4; - - for (std::size_t i = 0; i != remainder_start; i += 4) - { - for (std::size_t j = 0; j != mat_map[node_id].cols(); ++j) - { - mat_map[node_id](i, j) = - execute_ast_for_idx(instruction, 0, i, j); - mat_map[node_id](i + 1, j) = - execute_ast_for_idx(instruction, 0, i + 1, j); - mat_map[node_id](i + 2, j) = - execute_ast_for_idx(instruction, 0, i + 2, j); - mat_map[node_id](i + 3, j) = - execute_ast_for_idx(instruction, 0, i + 3, j); - } - } - - for (std::size_t i = remainder_start; i != total_size; ++i) - { - for (std::size_t j = 0; j != mat_map[node_id].cols(); ++j) - { - mat_map[node_id](i, j) = - execute_ast_for_idx(instruction, 0, i, j); - } - } - + { + CHECK_IF_EXIST_ELSE_ADD_MATRIX(node); + Codegen::execute, ct::mat_impl::mat_node, 2>( + instruction[0].kernel, + {mat_map[node_id].extent(0), mat_map[node_id].extent(1)}, + mat_map, region); + } return; case ct::util::Operation::inplace_add: - copy_id = node.copy_id_; - if (node_id == mat_map.size()) - { - num_rows = get_mat_rows(node.mat_row_len_); - num_cols = get_mat_cols(node.mat_col_len_); - - mat = ct::util::matrix_view{num_rows, num_cols}; - - mat_map.emplace_back(std::move(mat)); - } - - total_size = mat_map[node_id].rows(); - unrolled_size = mat_map[node_id].rows() / 4; - remainder_start = unrolled_size * 4; - - for (std::size_t i = 0; i != remainder_start; i += 4) + { + CHECK_IF_EXIST_ELSE_ADD_MATRIX(node); + std::size_t copy_id = node.copy_id_; + if (copy_id == -1) { - for (std::size_t j = 0; j != mat_map[node_id].cols(); ++j) - { - if (copy_id == -1) - { - mat_map[node_id](i, j) += - execute_ast_for_idx(instruction, 1, i, j); - mat_map[node_id](i + 1, j) += - execute_ast_for_idx(instruction, 1, i + 1, j); - mat_map[node_id](i + 2, j) += - execute_ast_for_idx(instruction, 1, i + 2, j); - mat_map[node_id](i + 3, j) += - execute_ast_for_idx(instruction, 1, i + 3, j); - } - else - { - mat_map[node_id](i, j) += mat_map[copy_id](i, j); - mat_map[node_id](i + 1, j) += - mat_map[copy_id](i + 1, j); - mat_map[node_id](i + 2, j) += - mat_map[copy_id](i + 2, j); - mat_map[node_id](i + 3, j) += - mat_map[copy_id](i + 3, j); - } - } + Codegen::execute, ct::mat_impl::mat_node, + 2>(instruction[0].kernel, + {mat_map[node_id].extent(0), mat_map[node_id].extent(1)}, + mat_map, region); } - - for (std::size_t i = remainder_start; i != total_size; ++i) + else { - for (std::size_t j = 0; j != mat_map[node_id].cols(); ++j) - { - if (copy_id == static_cast(-1)) - mat_map[node_id](i, j) += - execute_ast_for_idx(instruction, 1, i, j); - else - mat_map[node_id](i, j) += mat_map[copy_id](i, j); - } + auto dest = mat_map[node_id]; + auto src = mat_map[copy_id]; + + Kokkos::parallel_for( + "inplace_add_mat_" + std::to_string(node_id), + Kokkos::MDRangePolicy>( + {0, 0}, {dest.extent(0), dest.extent(1)}), + KOKKOS_LAMBDA(int i, int j) { dest(i, j) += src(i, j); }); } - + } return; case ct::util::Operation::inplace_sub: - copy_id = node.copy_id_; - if (node_id == mat_map.size()) + { + CHECK_IF_EXIST_ELSE_ADD_MATRIX(node); + std::size_t copy_id = node.copy_id_; + if (copy_id == -1) { - num_rows = get_mat_rows(node.mat_row_len_); - num_cols = get_mat_cols(node.mat_col_len_); - mat = ct::util::matrix_view{num_rows, num_cols}; - mat_map.emplace_back(std::move(mat)); + Codegen::execute, ct::mat_impl::mat_node, + 2>(instruction[0].kernel, + {mat_map[node_id].extent(0), mat_map[node_id].extent(1)}, + mat_map, region); } - - total_size = mat_map[node_id].rows(); - unrolled_size = mat_map[node_id].rows() / 4; - remainder_start = unrolled_size * 4; - - for (std::size_t i = 0; i != remainder_start; i += 4) + else { - for (std::size_t j = 0; j != mat_map[node_id].cols(); ++j) - { - if (copy_id == static_cast(-1)) - { - mat_map[node_id](i, j) -= - execute_ast_for_idx(instruction, 1, i, j); - mat_map[node_id](i + 1, j) -= - execute_ast_for_idx(instruction, 1, i + 1, j); - mat_map[node_id](i + 2, j) -= - execute_ast_for_idx(instruction, 1, i + 2, j); - mat_map[node_id](i + 3, j) -= - execute_ast_for_idx(instruction, 1, i + 3, j); - } - else - { - mat_map[node_id](i, j) -= mat_map[copy_id](i, j); - mat_map[node_id](i + 1, j) -= - mat_map[copy_id](i + 1, j); - mat_map[node_id](i + 2, j) -= - mat_map[copy_id](i + 2, j); - mat_map[node_id](i + 3, j) -= - mat_map[copy_id](i + 3, j); - } - } - } - - for (std::size_t i = remainder_start; i != total_size; ++i) - { - for (std::size_t j = 0; j != mat_map[node_id].cols(); ++j) - { - if (copy_id == static_cast(-1)) - mat_map[node_id](i, j) -= - execute_ast_for_idx(instruction, 1, i, j); - else - mat_map[node_id](i, j) -= mat_map[copy_id](i, j); - } + auto dest = mat_map[node_id]; + auto src = mat_map[copy_id]; + + Kokkos::parallel_for( + "inplace_add_mat_" + std::to_string(node_id), + Kokkos::MDRangePolicy>( + {0, 0}, {dest.extent(0), dest.extent(1)}), + KOKKOS_LAMBDA(int i, int j) { dest(i, j) -= src(i, j); }); } + } return; - case ct::util::Operation::inplace_divide: - copy_id = node.copy_id_; - if (node_id == mat_map.size()) + { + CHECK_IF_EXIST_ELSE_ADD_MATRIX(node); + std::size_t copy_id = node.copy_id_; + if (copy_id == -1) { - num_rows = get_mat_rows(node.mat_row_len_); - num_cols = get_mat_cols(node.mat_col_len_); - mat = ct::util::matrix_view{num_rows, num_cols}; - mat_map.emplace_back(std::move(mat)); + Codegen::execute, ct::mat_impl::mat_node, + 2>(instruction[0].kernel, + {mat_map[node_id].extent(0), mat_map[node_id].extent(1)}, + mat_map, region); } - - total_size = mat_map[node_id].rows(); - unrolled_size = mat_map[node_id].rows() / 4; - remainder_start = unrolled_size * 4; - - for (std::size_t i = 0; i != remainder_start; i += 4) - { - for (std::size_t j = 0; j != mat_map[node_id].cols(); ++j) - { - if (copy_id == static_cast(-1)) - { - mat_map[node_id](i, j) /= - execute_ast_for_idx(instruction, 1, i, j); - mat_map[node_id](i + 1, j) /= - execute_ast_for_idx(instruction, 1, i + 1, j); - mat_map[node_id](i + 2, j) /= - execute_ast_for_idx(instruction, 1, i + 2, j); - mat_map[node_id](i + 3, j) /= - execute_ast_for_idx(instruction, 1, i + 3, j); - } - else - { - mat_map[node_id](i, j) /= mat_map[copy_id](i, j); - mat_map[node_id](i + 1, j) /= - mat_map[copy_id](i + 1, j); - mat_map[node_id](i + 2, j) /= - mat_map[copy_id](i + 2, j); - mat_map[node_id](i + 3, j) /= - mat_map[copy_id](i + 3, j); - } - } - } - - for (std::size_t i = remainder_start; i != total_size; ++i) + else { - for (std::size_t j = 0; j != mat_map[node_id].cols(); ++j) - { - if (copy_id == static_cast(-1)) - mat_map[node_id](i, j) /= - execute_ast_for_idx(instruction, 1, i, j); - else - mat_map[node_id](i, j) /= mat_map[copy_id](i, j); - } + auto dest = mat_map[node_id]; + auto src = mat_map[copy_id]; + + Kokkos::parallel_for( + "inplace_add_mat_" + std::to_string(node_id), + Kokkos::MDRangePolicy>( + {0, 0}, {dest.extent(0), dest.extent(1)}), + KOKKOS_LAMBDA(int i, int j) { dest(i, j) /= src(i, j); }); } + } return; - + case ct::util::Operation::dealloc: { + /** + * TODO: This might fail due to a double free depending on how charm runtime + * destroys the charmArrays. + */ + Kokkos::View releivingRef; + mat_map[node_id] = releivingRef; + } return; case ct::util::Operation::custom_expr: { - if (node_id == mat_map.size()) - { - num_rows = get_mat_rows(node.mat_row_len_); - num_cols = get_mat_cols(node.mat_col_len_); + CHECK_IF_EXIST_ELSE_ADD_MATRIX(node); - mat = ct::util::matrix_view{num_rows, num_cols}; + const ct::mat_impl::mat_node& node = instruction[0]; + auto a_host = Kokkos::create_mirror_view_and_copy( + Kokkos::HostSpace(), mat_map[node_id]); + const std::size_t rows = a_host.extent(0); + const std::size_t cols = a_host.extent(1); - mat_map.emplace_back(std::move(mat)); + std::vector> a; + for (int i = 0; i < rows; i++) + { + a.push_back(std::vector( + a_host.data() + i * cols, a_host.data() + i * cols + cols)); } - const ct::mat_impl::mat_node& node = instruction[0]; - node.custom_expr_->operator()(num_rows, num_cols, mat_map[node_id], - mat_map[instruction[node.left_].name_]); - return; - } - - default: - CmiAbort("Operation not implemented"); - } - } + auto b_host = Kokkos::create_mirror_view_and_copy( + Kokkos::HostSpace(), mat_map[instruction[node.left_].name_]); + std::vector> b; + for (int i = 0; i < rows; i++) + { + b.push_back(std::vector( + b_host.data() + i * cols, b_host.data() + i * cols + cols)); + } - double execute_ast_for_idx( - std::vector const& instruction, - std::size_t curr_idx, std::size_t iter_i, std::size_t iter_j) - { - const ct::mat_impl::mat_node& node = instruction[curr_idx]; + node.custom_expr_->operator()(rows, cols, a, b); - switch (node.operation_) - { - case ct::util::Operation::noop: - return mat_map[node.name_](iter_i, iter_j); + Kokkos::View a_new( + "mat" + std::to_string(node_id), rows, cols); + Kokkos::View b_new( + "mat" + std::to_string(instruction[node.left_].name_), rows, + cols); - case ct::util::Operation::add: - return execute_ast_for_idx( - instruction, node.left_, iter_i, iter_j) + - execute_ast_for_idx(instruction, node.right_, iter_i, iter_j); + auto a_new_host = Kokkos::create_mirror_view(a_new); + auto b_new_host = Kokkos::create_mirror_view(b_new); - case ct::util::Operation::sub: - return execute_ast_for_idx( - instruction, node.left_, iter_i, iter_j) - - execute_ast_for_idx(instruction, node.right_, iter_i, iter_j); - case ct::util::Operation::multiply: - return execute_ast_for_idx( - instruction, node.left_, iter_i, iter_j) * - execute_ast_for_idx(instruction, node.right_, iter_i, iter_j); - case ct::util::Operation::divide: - return execute_ast_for_idx( - instruction, node.left_, iter_i, iter_j) / - execute_ast_for_idx(instruction, node.right_, iter_i, iter_j); - case ct::util::Operation::greater: - return execute_ast_for_idx( - instruction, node.left_, iter_i, iter_j) > - execute_ast_for_idx(instruction, node.right_, iter_i, iter_j); - case ct::util::Operation::lesser: - return execute_ast_for_idx( - instruction, node.left_, iter_i, iter_j) < - execute_ast_for_idx(instruction, node.right_, iter_i, iter_j); - case ct::util::Operation::geq: - return execute_ast_for_idx( - instruction, node.left_, iter_i, iter_j) >= - execute_ast_for_idx(instruction, node.right_, iter_i, iter_j); - case ct::util::Operation::leq: - return execute_ast_for_idx( - instruction, node.left_, iter_i, iter_j) <= - execute_ast_for_idx(instruction, node.right_, iter_i, iter_j); - case ct::util::Operation::eq: - return execute_ast_for_idx( - instruction, node.left_, iter_i, iter_j) == - execute_ast_for_idx(instruction, node.right_, iter_i, iter_j); - case ct::util::Operation::neq: - return execute_ast_for_idx( - instruction, node.left_, iter_i, iter_j) != - execute_ast_for_idx(instruction, node.right_, iter_i, iter_j); - case ct::util::Operation::unary_expr: - return node.unary_expr_->operator()(iter_i, iter_j, - execute_ast_for_idx(instruction, node.left_, iter_i, iter_j)); - case ct::util::Operation::binary_expr: - return node.binary_expr_->operator()(iter_i, iter_j, - execute_ast_for_idx(instruction, node.left_, iter_i, iter_j), - execute_ast_for_idx(instruction, node.right_, iter_i, iter_j)); - case ct::util::Operation::broadcast: - return node.value_; - case ct::util::Operation::logical_and: - return execute_ast_for_idx( - instruction, node.left_, iter_i, iter_j) && - execute_ast_for_idx(instruction, node.right_, iter_i, iter_j); - case ct::util::Operation::logical_or: - return execute_ast_for_idx( - instruction, node.left_, iter_i, iter_j) || - execute_ast_for_idx(instruction, node.right_, iter_i, iter_j); - case ct::util::Operation::logical_not: - return !execute_ast_for_idx( - instruction, node.left_, iter_i, iter_j); - case ct::util::Operation::where: - if (execute_ast_for_idx(instruction, node.ter_, iter_i, iter_j)) - { - return execute_ast_for_idx( - instruction, node.left_, iter_i, iter_j); - } - else + for (int i = 0; i < rows; i++) { - return execute_ast_for_idx( - instruction, node.right_, iter_i, iter_j); + for (int j = 0; j < cols; j++) + { + a_new_host(i, j) = a[i][j]; + b_new_host(i, j) = b[i][j]; + } } + + Kokkos::deep_copy(a_new, a_new_host); + Kokkos::deep_copy(b_new, b_new_host); + mat_map[node_id] = a_new; + mat_map[instruction[node.left_].name_] = b_new; + } + return; default: CmiAbort("Operation not implemented"); } - - // Control should not reach here! - return 0.; } public: @@ -1130,7 +1032,7 @@ class matrix_impl : public CBase_matrix_impl } private: - std::vector mat_map; + std::vector> mat_map; int num_chares_y; int num_chares_x; diff --git a/charmtyles/backend/codegen.hpp b/charmtyles/backend/codegen.hpp new file mode 100644 index 0000000..65ef829 --- /dev/null +++ b/charmtyles/backend/codegen.hpp @@ -0,0 +1,568 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +class Codegen +{ +private: + // a vector that stores node_id which is used to get the corresponding views from view_map + std::vector kkViewsOrder; + // a map from node_id -> kkVecViews Index + std::map nodeToKkViewMap; + std::size_t kkViewIdx = 0; + // a stream to store the generated kernel + std::stringstream kk; + std::size_t kkTmpVar; + // a vector that stores: + // 1 -> index into the merged region of instructions + // 2 -> the index(in ast) of the node that uses some custom binary/unary ops defined by the user. + // 3 -> flag that indicates if this is a unary or binary op. + std::vector> kkCustomOpsOrder; + // a map from kernel hash -> Kokkos functor + std::map kernel_cache; + // indexing scheme for the corresponding n rank view + std::string kkViewIndxScheme{}; + // View type corresponding to the given rank + std::string kkViewType{}; + // Function declaration to run the kokkos kernel + std::string kkFuncDecl{}; + // RangePolicy for the corresponding to the given rank + std::string kkRangePolicy{}; + // list of indices to be sent as input to the custom unary / binary ops + std::size_t kkCustomOpArgIdx{}; + // definition for the custom unops/binops that will be called in the kernel + std::set kkCustomOpsDef{}; + // list of scalars used by the generated kernel + std::vector kkScalarVals{}; + std::size_t kkScalarValIdx{}; + // offset into a region of multiple fused ASTs + size_t kkRegionOffset = 0; + + long long getViewIdx(size_t node_id) + { + if (nodeToKkViewMap.find(node_id) == nodeToKkViewMap.end()) + { + kkViewsOrder.emplace_back(node_id); + nodeToKkViewMap[node_id] = kkViewIdx; + return kkViewIdx++; + } + else + { + return nodeToKkViewMap[node_id]; + } + } + + uint64_t kernel_hash(std::string_view data) + { + const uint64_t FNV_OFFSET = 0xcbf29ce484222325ULL; + const uint64_t FNV_PRIME = 0x100000001b3ULL; + uint64_t hash = FNV_OFFSET; + for (unsigned char c : data) + { + hash ^= static_cast(c); + hash *= FNV_PRIME; + } + return hash; + } + + std::string to_string(uint64_t const hash) + { + std::ostringstream oss; + oss << std::hex << std::setw(16) << std::setfill('0') << hash; + return oss.str(); + } + + template + static inline void* getFuncPtr(ct::unary_operator* op) + { + void** vtable = *reinterpret_cast(op); + if constexpr (dim == 1) + return vtable[5]; + else if constexpr (dim == 2) + return vtable[6]; + } + + template + static inline void* getFuncPtr(ct::binary_operator* op) + { + void** vtable = *reinterpret_cast(op); + if constexpr (dim == 1) + return vtable[5]; + else if constexpr (dim == 2) + return vtable[6]; + } + + uint64_t compile() + { + Kokkos::Timer timer; + timer.reset(); + std::string kernel_ops(kk.str()); + uint64_t hash = kernel_hash(kernel_ops); + if (kernel_cache.find(hash) != kernel_cache.end()) + return hash; + std::string file_name("kernel-" + to_string(hash) + ".cc"); + std::string lib_name("libkernel-" + to_string(hash) + ".so"); + std::string kkPreamble{}; + for (auto customOpsDef : kkCustomOpsDef) + { + kkPreamble += customOpsDef + "\n"; + } + std::string kernel(R"( + #include + )" + kkPreamble + + R"(struct ASTFunctor { + Kokkos::View<)" + + kkViewType + R"(*> view_map; + Kokkos::View custom_ops_args; + Kokkos::View scalar_vals; + + KOKKOS_INLINE_FUNCTION ASTFunctor(Kokkos::View<)" + + kkViewType + + R"(*> _view_map, Kokkos::View custom_ops_args_, Kokkos::View scalar_vals_) + : view_map(_view_map), custom_ops_args(custom_ops_args_), scalar_vals(scalar_vals_) {} + + KOKKOS_INLINE_FUNCTION + void operator()()" + + kkFuncDecl + R"() const { + )" + kernel_ops + + R"( + } + }; + + extern "C" void run_kernel(Kokkos::View<)" + + kkViewType + + R"(*> view_map, Kokkos::View custom_ops_args, Kokkos::View scalar_vals, std::vector dims) { + ASTFunctor kernel(view_map, custom_ops_args, scalar_vals); + Kokkos::parallel_for("debug_label", )" + + kkRangePolicy + R"(, kernel); + } + )"); + + std::fstream ofs(file_name, std::ios::out); + ofs << kernel; + ofs.close(); +#ifdef GPU_BACKEND + system(std::string(std::string(KOKKOS_DIR) + + "/bin/nvcc_wrapper -O3 -march=native -std=c++20 -I" + + std::string(KOKKOS_DIR) + + "/include " + "-fPIC -shared -o " + + lib_name + " " + file_name + " -L" + std::string(KOKKOS_DIR) + + "/lib64 " + "-lkokkoscore --extended-lambda") + .c_str()); +#else + system(std::string("g++ -O3 -march=native -std=c++20 -I" + + std::string(KOKKOS_DIR) + "/include -shared -fPIC -o " + lib_name + + " " + file_name + " -L" + std::string(KOKKOS_DIR) + + "/lib -lkokkoscore") + .c_str()); +#endif + kernel_cache[hash] = true; + return hash; + } + +#define BINOP_CODEGEN(op) \ + { \ + long long leftid = codegen_ast(instruction, node.left_, dim); \ + long long rightid = codegen_ast(instruction, node.right_, dim); \ + kkTmpVar++; \ + kk << "auto tmp" << kkTmpVar << " = "; \ + if (leftid < 0) \ + { \ + kk << "tmp" << -leftid; \ + } \ + else \ + { \ + kk << "view_map[" << leftid << "](" << kkViewIndxScheme << ")"; \ + } \ + kk << " " << op << " "; \ + if (rightid < 0) \ + { \ + kk << "tmp" << -rightid; \ + } \ + else \ + { \ + kk << "view_map[" << rightid << "](" << kkViewIndxScheme << ")"; \ + } \ + kk << ";\n"; \ + } \ + return -static_cast(kkTmpVar); + + inline void genIndxScheme(const size_t dim) noexcept + { + for (size_t i = 0; i < dim; i++) + { + kkViewIndxScheme += std::string(1, (char) (97 + i)); + kkFuncDecl += "const int " + std::string(1, (char) (97 + i)); + if (i != dim - 1) + { + kkViewIndxScheme += ", "; + kkFuncDecl += ", "; + } + } + } + + inline void genKkViewType(const size_t dim) noexcept + { + kkViewType += "Kokkos::View>({"; + for (size_t i = 0; i < dim; i++) + { + kkRangePolicy += "0"; + if (i != dim - 1) + kkRangePolicy += ","; + } + kkRangePolicy += "}, {"; + for (size_t i = 0; i < dim; i++) + { + kkRangePolicy += "dims[" + std::to_string(i) + "]"; + if (i != dim - 1) + kkRangePolicy += ","; + } + kkRangePolicy += "})"; + } + } + + template + long long codegen_ast(std::vector const& instruction, + std::size_t curr_idx, std::size_t dim) + { + const T& node = instruction[curr_idx]; + + switch (node.operation_) + { + case ct::util::Operation::noop: + return getViewIdx(node.name_); + case ct::util::Operation::add: + BINOP_CODEGEN("+") + case ct::util::Operation::sub: + BINOP_CODEGEN("-") + case ct::util::Operation::divide: + BINOP_CODEGEN("/") + case ct::util::Operation::multiply: + BINOP_CODEGEN("*") + case ct::util::Operation::eq: + BINOP_CODEGEN("==") + case ct::util::Operation::neq: + BINOP_CODEGEN("!=") + case ct::util::Operation::geq: + BINOP_CODEGEN(">=") + case ct::util::Operation::leq: + BINOP_CODEGEN("<=") + case ct::util::Operation::greater: + BINOP_CODEGEN(">") + case ct::util::Operation::lesser: + BINOP_CODEGEN("<") + case ct::util::Operation::logical_and: + BINOP_CODEGEN("&&") + case ct::util::Operation::logical_or: + BINOP_CODEGEN("||") + case ct::util::Operation::logical_not: + { + long long leftid = codegen_ast(instruction, node.left_, dim); + kkTmpVar++; + kk << "auto tmp" << kkTmpVar << " = !"; + if (leftid < 0) + { + kk << "tmp" << -leftid; + } + else + { + kk << "view_map[" << leftid << "](" << kkViewIndxScheme << ")"; + } + kk << ";\n"; + } + return -static_cast(kkTmpVar); + case ct::util::Operation::unary_expr: + { + long long leftid = codegen_ast(instruction, node.left_, dim); + kkTmpVar++; + kkCustomOpsOrder.push_back({kkRegionOffset, curr_idx, true}); + kk << "auto tmp" << kkTmpVar << " = "; + + std::string signature; + if (dim == 1) + signature = node.unary_expr_->get_vec_signature(); + else if (dim == 2) + signature = node.unary_expr_->get_mat_signature(); + + kkCustomOpsDef.insert("KOKKOS_INLINE_FUNCTION double " + + node.unary_expr_->get_name() + signature); + kk << node.unary_expr_->get_name() << "(" << kkViewIndxScheme + << ", "; + + if (leftid < 0) + { + kk << "tmp" << -leftid; + } + else + { + kk << "view_map[" << leftid << "](" << kkViewIndxScheme << ")"; + } + + size_t argc = node.unary_expr_->get_extra_params().size(); + if (argc) + kk << ", "; + for (int i = 0; i < argc; i++) + { + kk << "custom_ops_args[" << kkCustomOpArgIdx << "]"; + if (i < argc - 1) + kk << ","; + kkCustomOpArgIdx++; + } + kk << ");\n"; + } + return -static_cast(kkTmpVar); + case ct::util::Operation::binary_expr: + { + long long leftid = codegen_ast(instruction, node.left_, dim); + long long rightid = codegen_ast(instruction, node.right_, dim); + kkTmpVar++; + kkCustomOpsOrder.push_back({kkRegionOffset, curr_idx, false}); + kk << "auto tmp" << kkTmpVar << " = "; + + std::string signature; + if (dim == 1) + signature = node.binary_expr_->get_vec_signature(); + else if (dim == 2) + signature = node.binary_expr_->get_mat_signature(); + + kkCustomOpsDef.insert("KOKKOS_INLINE_FUNCTION double " + + node.binary_expr_->get_name() + signature); + kk << node.binary_expr_->get_name() << "(" << kkViewIndxScheme + << ", "; + + if (leftid < 0) + { + kk << "tmp" << -leftid; + } + else + { + kk << "view_map[" << leftid << "](" << kkViewIndxScheme << ")"; + } + kk << ", "; + if (rightid < 0) + { + kk << "tmp" << -rightid; + } + else + { + kk << "view_map[" << rightid << "](" << kkViewIndxScheme << ")"; + } + size_t argc = node.binary_expr_->get_extra_params().size(); + if (argc) + kk << ", "; + for (int i = 0; i < argc; i++) + { + kk << "custom_ops_args[" << kkCustomOpArgIdx << "]"; + if (i < argc - 1) + kk << ","; + kkCustomOpArgIdx++; + } + kk << ");\n"; + } + return -static_cast(kkTmpVar); + case ct::util::Operation::broadcast: + { + kkTmpVar++; + kk << "auto tmp" << kkTmpVar << " = scalar_vals[" + << kkScalarValIdx++ << "];\n"; + kkScalarVals.emplace_back(node.value_); + } + return -static_cast(kkTmpVar); + case ct::util::Operation::where: + { + long long terid = codegen_ast(instruction, node.ter_, dim); + kkTmpVar++; + size_t kkResIndx = kkTmpVar; + kk << "double tmp" << kkResIndx << ";\n"; + kk << "if ("; + if (terid < 0) + { + kk << "tmp" << -terid; + } + else + { + kk << "view_map[" << terid << "](" << kkViewIndxScheme << ")"; + } + kk << ") {\n"; + long long leftid = codegen_ast(instruction, node.left_, dim); + kk << "tmp" << kkResIndx << " = "; + if (leftid < 0) + { + kk << "tmp" << -leftid; + } + else + { + kk << "view_map[" << leftid << "](" << kkViewIndxScheme << ")"; + } + kk << ";\n"; + kk << "} else {\n"; + long long rightid = codegen_ast(instruction, node.right_, dim); + kk << "tmp" << kkResIndx << " = "; + if (rightid < 0) + { + kk << "tmp" << -rightid; + } + else + { + kk << "view_map[" << rightid << "](" << kkViewIndxScheme << ")"; + } + kk << ";\n"; + kk << "}\n"; + return -static_cast(kkResIndx); + } + default: + CmiAbort("Operation not implemented"); + } + return 0.; + } + +public: + void reset() + { + kk.str(""); + kkTmpVar = 0; + kkCustomOpsOrder.clear(); + kkViewsOrder.clear(); + nodeToKkViewMap.clear(); + kkViewIdx = 0; + kkViewIndxScheme.clear(); + kkViewType.clear(); + kkFuncDecl.clear(); + kkRangePolicy.clear(); + kkCustomOpsDef.clear(); + kkCustomOpArgIdx = 0; + kkScalarVals.clear(); + kkScalarValIdx = 0; + kkRegionOffset = 0; + } + + template + static void execute(ct::util::kernelInfo const& kernel, + std::vector dims, std::vector const& view_map, + std::vector> const& region) + { + using kernelType = + void (*)(Kokkos::View, Kokkos::View, + Kokkos::View, std::vector); + + // Arrays used in the kernel + Kokkos::View kkVecViews( + "kkViews", std::get<1>(kernel).size()); + auto kkVecViews_h = Kokkos::create_mirror_view(kkVecViews); + for (int i = 0; i < std::get<1>(kernel).size(); i++) + kkVecViews_h(i) = view_map[std::get<1>(kernel)[i]]; + Kokkos::deep_copy(kkVecViews, kkVecViews_h); + + // Arguments to the custom operations (unop/binop) used in the kernel + std::vector kkCustomOpsArgs; + for (const auto& it : std::get<2>(kernel)) + { + if (std::get<2>(it)) + { + auto extra_params = region[std::get<0>(it)][std::get<1>(it)] + .unary_expr_->get_extra_params(); + if (extra_params.size() == 0) + continue; + kkCustomOpsArgs.insert(kkCustomOpsArgs.end(), + extra_params.begin(), extra_params.end()); + } + else + { + auto extra_params = region[std::get<0>(it)][std::get<1>(it)] + .binary_expr_->get_extra_params(); + if (extra_params.size() == 0) + continue; + kkCustomOpsArgs.insert(kkCustomOpsArgs.end(), + extra_params.begin(), extra_params.end()); + } + } + + Kokkos::View kkCustomOpsArgs_d( + "kkCustomOpsArgs_d", kkCustomOpsArgs.size()); + auto kkCustomOpsArgs_h = Kokkos::create_mirror_view(kkCustomOpsArgs_d); + for (int i = 0; i < kkCustomOpsArgs.size(); i++) + kkCustomOpsArgs_h(i) = kkCustomOpsArgs[i]; + Kokkos::deep_copy(kkCustomOpsArgs_d, kkCustomOpsArgs_h); + + // Scalars used in the kernel + Kokkos::View kkScalarVals( + "kkScalarVals", std::get<3>(kernel).size()); + auto kkScalarVals_h = Kokkos::create_mirror_view(kkScalarVals); + for (int i = 0; i < std::get<3>(kernel).size(); i++) + kkScalarVals_h(i) = std::get<3>(kernel)[i]; + Kokkos::deep_copy(kkScalarVals, kkScalarVals_h); + + void* functor = + kokkosMgmt.ckLocalBranch()->getHandle(std::get<0>(kernel)); + ((kernelType) functor)(std::move(kkVecViews), + std::move(kkCustomOpsArgs_d), std::move(kkScalarVals), + std::move(dims)); + } + + template + ct::util::kernelInfo generate_kernel( + std::vector> const& instructions) + { + genIndxScheme(dim); + genKkViewType(dim); + genkkRangePolicy(dim); + for (auto instruction : instructions) + { + const size_t node_id = instruction[0].name_; + long long resid = codegen_ast(instruction, 0, dim); + kk << "view_map[" << getViewIdx(node_id) << "](" << kkViewIndxScheme + << ") "; + if (instruction[0].operation_ == ct::util::Operation::inplace_add) + { + kk << "+="; + } + else if (instruction[0].operation_ == + ct::util::Operation::inplace_sub) + { + kk << "-="; + } + else if (instruction[0].operation_ == + ct::util::Operation::inplace_divide) + { + kk << "/="; + } + else + { + kk << "="; + } + kk << " tmp" << -resid << ";\n"; + ++kkRegionOffset; + } + + return {compile(), std::move(kkViewsOrder), std::move(kkCustomOpsOrder), + std::move(kkScalarVals)}; + } +}; diff --git a/charmtyles/charmtyles.hpp b/charmtyles/charmtyles.hpp index 459fc99..290dfea 100644 --- a/charmtyles/charmtyles.hpp +++ b/charmtyles/charmtyles.hpp @@ -4,16 +4,15 @@ #include #include -#include #include #include +#include +#include #include #include #include #include -#include -#include namespace ct { @@ -35,6 +34,14 @@ namespace ct { col_len = 1 << 10; ckout << "Matrix Col Block Length Set to: " << col_len << endl; + + kokkosMgmt = CProxy_KokkosGroup::ckNew(); + reductionMgmt = CProxy_reductionGroup::ckNew(); + } + + void finalize() + { + kokkosMgmt.finalize(); } void sync(ct::mat_impl::mat_shape_t const& matrix_shape) diff --git a/charmtyles/frontend/basic_binary_operators.hpp b/charmtyles/frontend/basic_binary_operators.hpp index cb5d16c..df32c57 100644 --- a/charmtyles/frontend/basic_binary_operators.hpp +++ b/charmtyles/frontend/basic_binary_operators.hpp @@ -14,18 +14,6 @@ namespace ct { using ct::binary_operator::binary_operator; - virtual double operator()( - std::size_t index, double lhs, double rhs) final - { - return lhs + rhs; - } - - virtual double operator()( - std::size_t i, std::size_t j, double lhs, double rhs) final - { - return lhs + rhs; - } - PUPable_decl(add_op); add_op(CkMigrateMessage* m) : ct::binary_operator(m) @@ -35,6 +23,22 @@ namespace ct { { ct::binary_operator::pup(p); } + std::string get_name() + { + return "add"; + } + std::string get_vec_signature() + { + return "(int a, double lhs, double rhs){return lhs+rhs;}"; + } + std::string get_mat_signature() + { + return "(int a, int b, double lhs, double rhs){return lhs+rhs;}"; + } + std::vector get_extra_params() + { + return {}; + } }; class subtract_op : public ct::binary_operator @@ -45,18 +49,6 @@ namespace ct { using ct::binary_operator::binary_operator; - virtual double operator()( - std::size_t index, double lhs, double rhs) final - { - return lhs - rhs; - } - - virtual double operator()( - std::size_t i, std::size_t j, double lhs, double rhs) final - { - return lhs - rhs; - } - PUPable_decl(subtract_op); subtract_op(CkMigrateMessage* m) : ct::binary_operator(m) @@ -66,6 +58,22 @@ namespace ct { { ct::binary_operator::pup(p); } + std::string get_name() + { + return "subtract"; + } + std::string get_vec_signature() + { + return "(int a, double lhs, double rhs){return lhs-rhs;}"; + } + std::string get_mat_signature() + { + return "(int a, int b, double lhs, double rhs){return lhs-rhs;}"; + } + std::vector get_extra_params() + { + return {}; + } }; class multiply_op : public ct::binary_operator @@ -76,18 +84,6 @@ namespace ct { using ct::binary_operator::binary_operator; - virtual double operator()( - std::size_t index, double lhs, double rhs) final - { - return lhs * rhs; - } - - virtual double operator()( - std::size_t i, std::size_t j, double lhs, double rhs) final - { - return lhs * rhs; - } - PUPable_decl(multiply_op); multiply_op(CkMigrateMessage* m) : ct::binary_operator(m) @@ -97,6 +93,22 @@ namespace ct { { ct::binary_operator::pup(p); } + std::string get_name() + { + return "multiply"; + } + std::string get_vec_signature() + { + return "(int a, double lhs, double rhs){return lhs*rhs;}"; + } + std::string get_mat_signature() + { + return "(int a, int b, double lhs, double rhs){return lhs*rhs;}"; + } + std::vector get_extra_params() + { + return {}; + } }; class divide_op : public ct::binary_operator @@ -107,18 +119,6 @@ namespace ct { using ct::binary_operator::binary_operator; - virtual double operator()( - std::size_t index, double lhs, double rhs) final - { - return lhs / rhs; - } - - virtual double operator()( - std::size_t i, std::size_t j, double lhs, double rhs) final - { - return lhs / rhs; - } - PUPable_decl(divide_op); divide_op(CkMigrateMessage* m) : ct::binary_operator(m) @@ -128,6 +128,22 @@ namespace ct { { ct::binary_operator::pup(p); } + std::string get_name() + { + return "divide"; + } + std::string get_vec_signature() + { + return "(int a, double lhs, double rhs){return lhs/rhs;}"; + } + std::string get_mat_signature() + { + return "(int a, int b, double lhs, double rhs){return lhs/rhs;}"; + } + std::vector get_extra_params() + { + return {}; + } }; class power_op : public ct::binary_operator @@ -138,18 +154,6 @@ namespace ct { using ct::binary_operator::binary_operator; - virtual double operator()( - std::size_t index, double lhs, double rhs) final - { - return std::pow(lhs, rhs); - } - - virtual double operator()( - std::size_t i, std::size_t j, double lhs, double rhs) final - { - return std::pow(lhs, rhs); - } - PUPable_decl(power_op); power_op(CkMigrateMessage* m) : ct::binary_operator(m) @@ -159,6 +163,24 @@ namespace ct { { ct::binary_operator::pup(p); } + std::string get_name() + { + return "power"; + } + std::string get_vec_signature() + { + return "(int a, double lhs, double rhs){return Kokkos::pow(lhs, " + "rhs);}"; + } + std::string get_mat_signature() + { + return "(int a, int b, double lhs, double rhs){return " + "Kokkos::pow(lhs, rhs);}"; + } + std::vector get_extra_params() + { + return {}; + } }; class modulo_op : public ct::binary_operator @@ -169,18 +191,6 @@ namespace ct { using ct::binary_operator::binary_operator; - virtual double operator()( - std::size_t index, double& lhs, double& rhs) final - { - return std::fmod(lhs, rhs); - } - - virtual double operator()( - std::size_t i, std::size_t j, double lhs, double rhs) final - { - return std::fmod(lhs, rhs); - } - PUPable_decl(modulo_op); modulo_op(CkMigrateMessage* m) : ct::binary_operator(m) @@ -190,6 +200,22 @@ namespace ct { { ct::binary_operator::pup(p); } + std::string get_name() + { + return "modulo"; + } + std::string get_vec_signature() + { + return "(int a, double lhs, double rhs){return lhs%rhs;}"; + } + std::string get_mat_signature() + { + return "(int a, int b, double lhs, double rhs){return lhs%rhs;}"; + } + std::vector get_extra_params() + { + return {}; + } }; class max_op : public ct::binary_operator @@ -200,18 +226,6 @@ namespace ct { using ct::binary_operator::binary_operator; - virtual double operator()( - std::size_t index, double& lhs, double& rhs) final - { - return std::max(lhs, rhs); - } - - virtual double operator()( - std::size_t i, std::size_t j, double lhs, double rhs) final - { - return std::max(lhs, rhs); - } - PUPable_decl(max_op); max_op(CkMigrateMessage* m) : ct::binary_operator(m) @@ -221,6 +235,24 @@ namespace ct { { ct::binary_operator::pup(p); } + std::string get_name() + { + return "max"; + } + std::string get_vec_signature() + { + return "(int a, double lhs, double rhs){return Kokkos::max(lhs, " + "rhs);}"; + } + std::string get_mat_signature() + { + return "(int a, int b, double lhs, double rhs){return " + "Kokkos::max(lhs, rhs);}"; + } + std::vector get_extra_params() + { + return {}; + } }; class min_op : public ct::binary_operator @@ -231,18 +263,6 @@ namespace ct { using ct::binary_operator::binary_operator; - virtual double operator()( - std::size_t index, double lhs, double rhs) final - { - return std::min(lhs, rhs); - } - - virtual double operator()( - std::size_t i, std::size_t j, double lhs, double rhs) final - { - return std::min(lhs, rhs); - } - PUPable_decl(min_op); min_op(CkMigrateMessage* m) : ct::binary_operator(m) @@ -252,6 +272,24 @@ namespace ct { { ct::binary_operator::pup(p); } + std::string get_name() + { + return "min"; + } + std::string get_vec_signature() + { + return "(int a, double lhs, double rhs){return Kokkos::min(lhs, " + "rhs);}"; + } + std::string get_mat_signature() + { + return "(int a, int b, double lhs, double rhs){return " + "Kokkos::min(lhs, rhs);}"; + } + std::vector get_extra_params() + { + return {}; + } }; class greater_than_op : public ct::binary_operator @@ -262,18 +300,6 @@ namespace ct { using ct::binary_operator::binary_operator; - virtual double operator()( - std::size_t index, double lhs, double rhs) final - { - return (lhs > rhs) ? 1.0 : 0.0; - } - - virtual double operator()( - std::size_t i, std::size_t j, double lhs, double rhs) final - { - return (lhs > rhs) ? 1.0 : 0.0; - } - PUPable_decl(greater_than_op); greater_than_op(CkMigrateMessage* m) : ct::binary_operator(m) @@ -283,6 +309,23 @@ namespace ct { { ct::binary_operator::pup(p); } + std::string get_name() + { + return "greater_than"; + } + std::string get_vec_signature() + { + return "(int a, double lhs, double rhs){return (lhs>rhs)?1.0:0.0;}"; + } + std::string get_mat_signature() + { + return "(int a, int b, double lhs, double rhs){return " + "(lhs>rhs)?1.0:0.0;}"; + } + std::vector get_extra_params() + { + return {}; + } }; class less_than_op : public ct::binary_operator @@ -293,18 +336,6 @@ namespace ct { using ct::binary_operator::binary_operator; - virtual double operator()( - std::size_t index, double lhs, double rhs) final - { - return (lhs < rhs) ? 1.0 : 0.0; - } - - virtual double operator()( - std::size_t i, std::size_t j, double lhs, double rhs) final - { - return (lhs < rhs) ? 1.0 : 0.0; - } - PUPable_decl(less_than_op); less_than_op(CkMigrateMessage* m) : ct::binary_operator(m) @@ -314,6 +345,23 @@ namespace ct { { ct::binary_operator::pup(p); } + std::string get_name() + { + return "less_than"; + } + std::string get_vec_signature() + { + return "(int a, double lhs, double rhs){return (lhs get_extra_params() + { + return {}; + } }; class equal_op : public ct::binary_operator @@ -331,18 +379,6 @@ namespace ct { using ct::binary_operator::binary_operator; - virtual double operator()( - std::size_t index, double lhs, double rhs) final - { - return (std::abs(lhs - rhs) < epsilon_) ? 1.0 : 0.0; - } - - virtual double operator()( - std::size_t i, std::size_t j, double lhs, double rhs) final - { - return (std::abs(lhs - rhs) < epsilon_) ? 1.0 : 0.0; - } - PUPable_decl(equal_op); equal_op(CkMigrateMessage* m) : ct::binary_operator(m) @@ -354,6 +390,25 @@ namespace ct { ct::binary_operator::pup(p); p | epsilon_; } + std::string get_name() + { + return "equal"; + } + std::string get_vec_signature() + { + return "(int a, double lhs, double rhs, double epsilon){return " + "(Kokkos::abs(lhs-rhs) get_extra_params() + { + return {epsilon_}; + } private: double epsilon_; @@ -367,18 +422,6 @@ namespace ct { using ct::binary_operator::binary_operator; - virtual double operator()( - std::size_t index, double lhs, double rhs) final - { - return std::atan2(lhs, rhs); - } - - virtual double operator()( - std::size_t i, std::size_t j, double lhs, double rhs) final - { - return std::atan2(lhs, rhs); - } - PUPable_decl(atan2_op); atan2_op(CkMigrateMessage* m) : ct::binary_operator(m) @@ -388,6 +431,24 @@ namespace ct { { ct::binary_operator::pup(p); } + std::string get_name() + { + return "atan2"; + } + std::string get_vec_signature() + { + return "(int a, double lhs, double rhs){return Kokkos::atan2(lhs, " + "rhs);}"; + } + std::string get_mat_signature() + { + return "(int a, int b, double lhs, double rhs){return " + "Kokkos::atan2(lhs, rhs);}"; + } + std::vector get_extra_params() + { + return {}; + } }; class weighted_average_op : public ct::binary_operator @@ -407,18 +468,6 @@ namespace ct { using ct::binary_operator::binary_operator; - virtual double operator()( - std::size_t index, double lhs, double rhs) final - { - return (w1_ * lhs + w2_ * rhs) / (w1_ + w2_); - } - - virtual double operator()( - std::size_t i, std::size_t j, double lhs, double rhs) final - { - return (w1_ * lhs + w2_ * rhs) / (w1_ + w2_); - } - PUPable_decl(weighted_average_op); weighted_average_op(CkMigrateMessage* m) : ct::binary_operator(m) @@ -431,78 +480,140 @@ namespace ct { p | w1_; p | w2_; } + std::string get_name() + { + return "weighted_average"; + } + std::string get_vec_signature() + { + return "(int a, double lhs, double rhs, double w1, double " + "w2){return (w1 * lhs + w2 * rhs) / (w1 + w2);}"; + } + std::string get_mat_signature() + { + return "(int a, int b, double lhs, double rhs, double w1, double " + "w2){return (w1 * lhs + w2 * rhs) / (w1 + w2);}"; + } + std::vector get_extra_params() + { + return {w1_, w2_}; + } private: double w1_, w2_; }; + class axpy_op : public ct::binary_operator{ + public: + axpy_op() = delete; + axpy_op(double alpha) + : alpha_(alpha) + { + } + ~axpy_op() = default; + + using ct::binary_operator::binary_operator; + + PUPable_decl(axpy_op); + axpy_op(CkMigrateMessage* m) + : ct::binary_operator(m) + { + } + void pup(PUP::er& p) final + { + ct::binary_operator::pup(p); + p | alpha_; + } + std::string get_name() + { + return "axpy"; + } + std::string get_vec_signature() + { + return "(int a, double lhs, double rhs, double alpha){return alpha*lhs + rhs;}"; + } + std::string get_mat_signature() + { + return "(int a, int b, double lhs, double rhs, double alpha){return alpha*lhs + rhs;;}"; + } + std::vector get_extra_params() + { + return {alpha_}; + } + + private: + double alpha_; + }; + namespace binary_ops { - inline std::shared_ptr add() + inline std::shared_ptr add(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr subtract() + inline std::shared_ptr subtract(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr multiply() + inline std::shared_ptr multiply(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr divide() + inline std::shared_ptr divide(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr power() + inline std::shared_ptr power(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr modulo() + inline std::shared_ptr modulo(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr max() + inline std::shared_ptr max(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr min() + inline std::shared_ptr min(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr greater_than() + inline std::shared_ptr greater_than(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr less_than() + inline std::shared_ptr less_than(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr equal( - double epsilon = 1e-10) + inline std::shared_ptr equal(const std::vector& args) { - return std::make_shared(epsilon); + return std::make_shared(args[0]); } - inline std::shared_ptr atan2() + inline std::shared_ptr atan2(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr weighted_average( - double w1, double w2) + inline std::shared_ptr weighted_average(const std::vector& args) + { + return std::make_shared(args[0], args[1]); + } + inline std::shared_ptr axpy(const std::vector& args) { - return std::make_shared(w1, w2); + return std::make_shared(args[0]); } } // namespace binary_ops diff --git a/charmtyles/frontend/basic_unary_operators.hpp b/charmtyles/frontend/basic_unary_operators.hpp index 4754886..d8e1132 100644 --- a/charmtyles/frontend/basic_unary_operators.hpp +++ b/charmtyles/frontend/basic_unary_operators.hpp @@ -13,17 +13,6 @@ namespace ct { using ct::unary_operator::unary_operator; - virtual double operator()(std::size_t index, double value) final - { - return -value; - } - - virtual double operator()( - std::size_t i, std::size_t j, double value) final - { - return -value; - } - PUPable_decl(negate_op); negate_op(CkMigrateMessage* m) : ct::unary_operator(m) @@ -33,6 +22,23 @@ namespace ct { { ct::unary_operator::pup(p); } + std::string get_name() + { + return "negate"; + } + std::string get_vec_signature() + { + return "(int a, double val){return -val;}"; + } + + std::string get_mat_signature() + { + return "(int a, int b, double val){return -val;}"; + } + std::vector get_extra_params() + { + return {}; + } }; class abs_op : public ct::unary_operator @@ -43,17 +49,6 @@ namespace ct { using ct::unary_operator::unary_operator; - virtual double operator()(std::size_t index, double value) final - { - return std::abs(value); - } - - virtual double operator()( - std::size_t i, std::size_t j, double value) final - { - return std::abs(value); - } - PUPable_decl(abs_op); abs_op(CkMigrateMessage* m) : ct::unary_operator(m) @@ -63,6 +58,22 @@ namespace ct { { ct::unary_operator::pup(p); } + std::string get_name() + { + return "abs"; + } + std::string get_vec_signature() + { + return "(int a, double val){return Kokkos::abs(val);}"; + } + std::string get_mat_signature() + { + return "(int a, int b, double val){Kokkos::abs(val);}"; + } + std::vector get_extra_params() + { + return {}; + } }; class square_op : public ct::unary_operator @@ -73,17 +84,6 @@ namespace ct { using ct::unary_operator::unary_operator; - virtual double operator()(std::size_t index, double value) final - { - return value * value; - } - - virtual double operator()( - std::size_t i, std::size_t j, double value) final - { - return value * value; - } - PUPable_decl(square_op); square_op(CkMigrateMessage* m) : ct::unary_operator(m) @@ -93,6 +93,24 @@ namespace ct { { ct::unary_operator::pup(p); } + std::string get_name() + { + return "square"; + } + std::string get_vec_signature() + { + return "(int a, double val){return Kokkos::sqaure(val);}"; + } + + std::string get_mat_signature() + { + return "(int a, int b, double val){return Kokkos::sqaure(val);}"; + } + + std::vector get_extra_params() + { + return {}; + } }; class sqrt_op : public ct::unary_operator @@ -103,17 +121,6 @@ namespace ct { using ct::unary_operator::unary_operator; - virtual double operator()(std::size_t index, double value) final - { - return std::sqrt(value); - } - - virtual double operator()( - std::size_t i, std::size_t j, double value) final - { - return std::sqrt(value); - } - PUPable_decl(sqrt_op); sqrt_op(CkMigrateMessage* m) : ct::unary_operator(m) @@ -123,6 +130,24 @@ namespace ct { { ct::unary_operator::pup(p); } + std::string get_name() + { + return "sqrt"; + } + std::string get_vec_signature() + { + return "(int a, double val){return Kokkos::sqrt(val);}"; + } + + std::string get_mat_signature() + { + return "(int a, int b, double val){return Kokkos::sqrt(val);}"; + } + + std::vector get_extra_params() + { + return {}; + } }; class reciprocal_op : public ct::unary_operator @@ -133,17 +158,6 @@ namespace ct { using ct::unary_operator::unary_operator; - virtual double operator()(std::size_t index, double value) final - { - return 1.0 / value; - } - - virtual double operator()( - std::size_t i, std::size_t j, double value) final - { - return 1.0 / value; - } - PUPable_decl(reciprocal_op); reciprocal_op(CkMigrateMessage* m) : ct::unary_operator(m) @@ -153,6 +167,24 @@ namespace ct { { ct::unary_operator::pup(p); } + std::string get_name() + { + return "reciprocal"; + } + std::string get_vec_signature() + { + return "(int a, double val){return 1.0/val;}"; + } + + std::string get_mat_signature() + { + return "(int a, int b, double val){return 1.0/val;}"; + } + + std::vector get_extra_params() + { + return {}; + } }; class sin_op : public ct::unary_operator @@ -163,17 +195,6 @@ namespace ct { using ct::unary_operator::unary_operator; - virtual double operator()(std::size_t index, double value) final - { - return std::sin(value); - } - - virtual double operator()( - std::size_t i, std::size_t j, double value) final - { - return std::sin(value); - } - PUPable_decl(sin_op); sin_op(CkMigrateMessage* m) : ct::unary_operator(m) @@ -183,6 +204,24 @@ namespace ct { { ct::unary_operator::pup(p); } + std::string get_name() + { + return "sin"; + } + std::string get_vec_signature() + { + return "(int a, double val){return Kokkos::sin(val);}"; + } + + std::string get_mat_signature() + { + return "(int a, int b, double val){return Kokkos::sin(val);}"; + } + + std::vector get_extra_params() + { + return {}; + } }; class cos_op : public ct::unary_operator @@ -193,17 +232,6 @@ namespace ct { using ct::unary_operator::unary_operator; - virtual double operator()(std::size_t index, double value) final - { - return std::cos(value); - } - - virtual double operator()( - std::size_t i, std::size_t j, double value) final - { - return std::cos(value); - } - PUPable_decl(cos_op); cos_op(CkMigrateMessage* m) : ct::unary_operator(m) @@ -213,26 +241,37 @@ namespace ct { { ct::unary_operator::pup(p); } + std::string get_name() + { + return "cos"; + } + std::string get_vec_signature() + { + return "(int a, double val){return Kokkos::cos(val);}"; + } + + std::string get_mat_signature() + { + return "(int a, int b, double val){return Kokkos::cos(val);}"; + } + + std::vector get_extra_params() + { + return {}; + } }; class log_op : public ct::unary_operator { public: - log_op() = default; - ~log_op() = default; - - using ct::unary_operator::unary_operator; - - virtual double operator()(std::size_t index, double value) final + log_op() = delete; + log_op(double base) + : base_(base) { - return std::log(value); } + ~log_op() = default; - virtual double operator()( - std::size_t i, std::size_t j, double value) final - { - return std::log(value); - } + using ct::unary_operator::unary_operator; PUPable_decl(log_op); log_op(CkMigrateMessage* m) @@ -242,7 +281,29 @@ namespace ct { void pup(PUP::er& p) final { ct::unary_operator::pup(p); + p|base_; + } + std::string get_name() + { + return "log"; + } + std::string get_vec_signature() + { + return "(int a, double val, double base){return Kokkos::log(val)/Kokkos::log(base);}"; } + + std::string get_mat_signature() + { + return "(int a, int b, double val, double base){return Kokkos::log(val)/Kokkos::log(base);}"; + } + + std::vector get_extra_params() + { + return {base_}; + } + private: + double base_; + }; class exp_op : public ct::unary_operator @@ -253,17 +314,6 @@ namespace ct { using ct::unary_operator::unary_operator; - virtual double operator()(std::size_t index, double value) final - { - return std::exp(value); - } - - virtual double operator()( - std::size_t i, std::size_t j, double value) final - { - return std::exp(value); - } - PUPable_decl(exp_op); exp_op(CkMigrateMessage* m) : ct::unary_operator(m) @@ -273,6 +323,24 @@ namespace ct { { ct::unary_operator::pup(p); } + std::string get_name() + { + return "exp"; + } + std::string get_vec_signature() + { + return "(int a, double val){return Kokkos::exp(val);}"; + } + + std::string get_mat_signature() + { + return "(int a, int b, double val){return Kokkos::exp(val);}"; + } + + std::vector get_extra_params() + { + return {}; + } }; class scale_op : public ct::unary_operator @@ -287,17 +355,6 @@ namespace ct { using ct::unary_operator::unary_operator; - virtual double operator()(std::size_t index, double value) final - { - return scale_factor_ * value; - } - - virtual double operator()( - std::size_t i, std::size_t j, double value) final - { - return scale_factor_ * value; - } - PUPable_decl(scale_op); scale_op(CkMigrateMessage* m) : ct::unary_operator(m) @@ -309,6 +366,26 @@ namespace ct { ct::unary_operator::pup(p); p | scale_factor_; } + std::string get_name() + { + return "scale"; + } + std::string get_vec_signature() + { + return "(int a, double val, double scale_factor){return " + "scale_factor*val;}"; + } + + std::string get_mat_signature() + { + return "(int a, int b, double val, double scale_factor){return " + "scale_factor*val;}"; + } + + std::vector get_extra_params() + { + return {scale_factor_}; + } private: double scale_factor_; @@ -326,17 +403,6 @@ namespace ct { using ct::unary_operator::unary_operator; - virtual double operator()(std::size_t index, double value) final - { - return value + constant_; - } - - virtual double operator()( - std::size_t i, std::size_t j, double value) final - { - return value + constant_; - } - PUPable_decl(add_constant_op); add_constant_op(CkMigrateMessage* m) : ct::unary_operator(m) @@ -348,6 +414,25 @@ namespace ct { ct::unary_operator::pup(p); p | constant_; } + std::string get_name() + { + return "add_constant"; + } + std::string get_vec_signature() + { + return "(int a, double val, double constant){return val + constant;}"; + } + + std::string get_mat_signature() + { + return "(int a, int b, double val, double constant){return val + " + "constant;}"; + } + + std::vector get_extra_params() + { + return {constant_}; + } private: double constant_; @@ -361,17 +446,6 @@ namespace ct { using ct::unary_operator::unary_operator; - virtual double operator()(std::size_t index, double value) final - { - return std::max(0.0, value); - } - - virtual double operator()( - std::size_t i, std::size_t j, double value) final - { - return std::max(0.0, value); - } - PUPable_decl(relu_op); relu_op(CkMigrateMessage* m) : ct::unary_operator(m) @@ -381,66 +455,84 @@ namespace ct { { ct::unary_operator::pup(p); } + std::string get_name() + { + return "relu"; + } + std::string get_vec_signature() + { + return "(int a, double val){return Kokkos::max(0.0,val);}"; + } + + std::string get_mat_signature() + { + return "(int a, int b, double val){return Kokkos::max(0.0,val);}"; + } + + std::vector get_extra_params() + { + return {}; + } }; namespace unary_ops { - inline std::shared_ptr negate() + inline std::shared_ptr negate(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr abs() + inline std::shared_ptr abs(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr square() + inline std::shared_ptr square(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr sqrt() + inline std::shared_ptr sqrt(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr reciprocal() + inline std::shared_ptr reciprocal(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr sin() + inline std::shared_ptr sin(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr cos() + inline std::shared_ptr cos(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr log() + inline std::shared_ptr log(const std::vector& args) { - return std::make_shared(); + return std::make_shared(args[0]); } - inline std::shared_ptr exp() + inline std::shared_ptr exp(const std::vector& args) { return std::make_shared(); } - inline std::shared_ptr scale(double factor) + inline std::shared_ptr scale(const std::vector& args) { - return std::make_shared(factor); + return std::make_shared(args[0]); } - inline std::shared_ptr add_constant(double constant) + inline std::shared_ptr add_constant(const std::vector& args) { - return std::make_shared(constant); + return std::make_shared(args[0]); } - inline std::shared_ptr relu() + inline std::shared_ptr relu(const std::vector& args) { return std::make_shared(); } diff --git a/charmtyles/frontend/matrix.hpp b/charmtyles/frontend/matrix.hpp index 2943341..464ee63 100644 --- a/charmtyles/frontend/matrix.hpp +++ b/charmtyles/frontend/matrix.hpp @@ -89,6 +89,21 @@ namespace ct { return dispatch_count; } + void codegen(instr_t& instructions) { + for (size_t i = 0; i < instructions.size();) { + instr_t region = ct::util::carveRegion(instructions, i); + + if (!region.empty()) { + cgen.reset(); + instructions[i][0].kernel = cgen.generate_kernel(region); + kokkosMgmt.dkload(std::get<0>(instructions[i][0].kernel)); + i += region.size(); + } else { + ++i; + } + } + } + void print_instructions() const { ckout << "Printing Instructions:" << endl; @@ -116,6 +131,7 @@ namespace ct { // Dispatch all non-empty vectors! if (shape_matrix_queue_[i].size() != 0) { + codegen(shape_matrix_queue_[i]); is_dispatched = true; std::size_t& sdag_index = sdag_index_[i]; @@ -137,9 +153,11 @@ namespace ct { void dispatch(std::size_t shape_id) { + //print_instructions(); // Send instruction for execution if (shape_matrix_queue_[shape_id].size() != 0) { + codegen(shape_matrix_queue_[shape_id]); std::size_t& sdag_index = sdag_index_[shape_id]; CProxy_matrix_impl dispatch_proxy = @@ -179,6 +197,8 @@ namespace ct { private: std::vector shape_matrix_queue_; std::vector sdag_index_; + + Codegen cgen; }; CT_GENERATE_SINGLETON(mat_instr_queue_t, mat_instr_queue); @@ -212,13 +232,8 @@ namespace ct { if (it == shape_info.end()) { // Create a new proxy for this shape and assign it to shape_info - CProxy_matrix_impl proxy = - CProxy_matrix_impl::ckNew(num_chares_y, num_chares_x, - CT_ACCESS_SINGLETON(ct::util::matrix_block_rows), - CT_ACCESS_SINGLETON(ct::util::matrix_block_cols), - num_chares_x, num_chares_y); - shape_info.emplace_back(ct::mat_impl::mat_shape_t{ - 0, num_chares_x, num_chares_y, proxy}); + CProxy_matrix_impl proxy = CProxy_matrix_impl::ckNew(num_chares_y, num_chares_x, row_block_len, col_block_len, num_chares_x, num_chares_y); + shape_info.emplace_back(ct::mat_impl::mat_shape_t{0, num_chares_x, num_chares_y, proxy}); ct::mat_impl::mat_shape_t matrix_shape = shape_info.back(); @@ -715,15 +730,12 @@ namespace ct { return *this; } - // TODO: Figure out why this is necessary! matrix(matrix&& other) : row_size_(other.row_size_) , col_size_(other.col_size_) , matrix_shape_(other.matrix_shape_) , node_(other.node_) - { - // ckout << "Move constructor called!" << endl; - } + {} template matrix(ct::mat_impl::mat_expression const& e) @@ -744,6 +756,23 @@ namespace ct { queue.insert(instr, matrix_shape_.shape_id); } + matrix(std::vector& instr) + { + ct::mat_impl::mat_node& root = instr.front(); + row_size_ = root.mat_row_len_; + col_size_ = root.mat_col_len_; + + matrix_shape_ = ct::mat_impl::get_mat_shape(row_size_, col_size_); + + root.name_ = matrix_shape_.matrix_id; + node_ = ct::mat_impl::mat_node{root}; + + ct::mat_impl::mat_instr_queue_t& queue = + CT_ACCESS_SINGLETON(ct::mat_impl::mat_instr_queue); + + queue.insert(instr, matrix_shape_.shape_id); + } + template matrix(ct::mat_impl::ter_mat_expression const& e) { @@ -981,7 +1010,6 @@ namespace ct { return fval.get(); } - private: std::vector operator()() const { ct::mat_impl::mat_node new_node{node_}; @@ -990,25 +1018,15 @@ namespace ct { return std::vector{new_node}; } + ~matrix() { + ct::mat_impl::mat_node delNode(matrix_shape_.matrix_id, ct::util::Operation::dealloc, row_size_, col_size_); + ct::mat_impl::mat_instr_queue_t& queue = CT_ACCESS_SINGLETON(ct::mat_impl::mat_instr_queue); + queue.insert(delNode, matrix_shape_.shape_id); + } + private: std::size_t row_size_; std::size_t col_size_; ct::mat_impl::mat_shape_t matrix_shape_; ct::mat_impl::mat_node node_; }; - - namespace traits { - template - struct is_mat_type_impl - { - constexpr static bool value = false; - }; - - template <> - struct is_mat_type_impl - { - constexpr static bool value = true; - }; - - } // namespace traits - } // namespace ct diff --git a/charmtyles/frontend/operations.hpp b/charmtyles/frontend/operations.hpp index 6b52f26..24def50 100644 --- a/charmtyles/frontend/operations.hpp +++ b/charmtyles/frontend/operations.hpp @@ -5,222 +5,229 @@ #include #include +#include namespace ct { - namespace traits { - template - struct is_vec_type_impl> - { - constexpr static bool value = true; - }; + namespace internal { + template + struct is_vec_type_impl + { + constexpr static bool value = false; + }; + + template <> + struct is_vec_type_impl + { + constexpr static bool value = true; + }; + + template + struct is_vec_type_impl> + { + constexpr static bool value = true; + }; + + template + struct is_vec_type_impl> + { + constexpr static bool value = true; + }; + } - template - struct is_vec_type_impl> - { - constexpr static bool value = true; - }; + template + constexpr static bool is_vec_type_v = internal::is_vec_type_impl::value; - template - struct is_mat_type_impl> - { - constexpr static bool value = true; - }; + template + constexpr static bool is_bin_vec_type_v = is_vec_type_v && is_vec_type_v; - template - struct is_mat_type_impl> - { - constexpr static bool value = true; - }; + template + constexpr static bool is_ter_vec_type_v = is_bin_vec_type_v && is_vec_type_v; - template - struct is_vec_type - { - constexpr static bool value = - is_vec_type_impl::type>::value && - is_vec_type_impl::type>::value; - }; + namespace internal { + template + struct is_mat_type_impl + { + constexpr static bool value = false; + }; + + template <> + struct is_mat_type_impl + { + constexpr static bool value = true; + }; + + template + struct is_mat_type_impl> + { + constexpr static bool value = true; + }; + + template + struct is_mat_type_impl> + { + constexpr static bool value = true; + }; + } - template - struct is_ter_vec_type - { - constexpr static bool value = - is_vec_type_impl::type>::value && - is_vec_type_impl::type>::value && - is_vec_type_impl::type>::value; - }; + template + constexpr static bool is_mat_type_v = internal::is_mat_type_impl::value; - template - struct is_mat_type - { - constexpr static bool value = - is_mat_type_impl::type>::value && - is_mat_type_impl::type>::value; - }; + template + constexpr static bool is_bin_mat_type_v = is_mat_type_v && is_mat_type_v; - template - struct is_ter_mat_type - { - constexpr static bool value = - is_mat_type_impl::type>::value && - is_mat_type_impl::type>::value && - is_mat_type_impl::type>::value; - }; + template + constexpr static bool is_ter_mat_type_v = is_bin_mat_type_v && is_mat_type_v; - } // namespace traits + template + concept is_tensor_type = is_vec_type_v> || is_mat_type_v>; + } template - auto operator_impl(LHS const& lhs, RHS const& rhs, ct::util::Operation op) + auto inline operator_impl(LHS const& lhs, RHS const& rhs, ct::util::Operation op) { - if constexpr (ct::traits::is_vec_type::value) + using LHS_T = std::decay_t; + using RHS_T = std::decay_t; + + if constexpr (ct::traits::is_bin_vec_type_v) { - return ct::vec_impl::vec_expression{ - lhs, rhs, lhs.size(), op}; + return ct::vec_impl::vec_expression{lhs, rhs, lhs.size(), op}; } - else if constexpr (ct::traits::is_mat_type::value) + else if constexpr (ct::traits::is_bin_mat_type_v) { - return ct::mat_impl::mat_expression{ - lhs, rhs, lhs.rows(), lhs.cols(), op}; + return ct::mat_impl::mat_expression{lhs, rhs, lhs.rows(), lhs.cols(), op}; } - else if constexpr (traits::is_vec_type_impl< - typename std::decay::type>::value || - traits::is_vec_type_impl::type>::value) + else if constexpr (ct::traits::is_vec_type_v || ct::traits::is_vec_type_v) { - if constexpr (std::is_arithmetic_v::type>) + if constexpr (std::is_arithmetic_v) { - return ct::vec_impl::vec_expression{ - lhs, rhs, rhs.size(), op}; + return ct::vec_impl::vec_expression{lhs, rhs, rhs.size(), op}; } - else if constexpr (std::is_same_v::type, - ct::scalar>) + else if constexpr (std::is_same_v) { return ct::vec_impl::vec_expression{ lhs.get(), rhs, rhs.size(), op}; } - else if constexpr (std::is_arithmetic_v< - typename std::decay::type>) + else if constexpr (std::is_arithmetic_v) { - return ct::vec_impl::vec_expression{ - lhs, rhs, lhs.size(), op}; + return ct::vec_impl::vec_expression{lhs, rhs, lhs.size(), op}; } - else if constexpr (std::is_same_v::type, - ct::scalar>) + else if constexpr (std::is_same_v) { - return ct::vec_impl::vec_expression{ - lhs, rhs.get(), lhs.size(), op}; + return ct::vec_impl::vec_expression{lhs, rhs.get(), lhs.size(), op}; } else { CkAbort("Vectors to matrix broadcasting not yet supported"); } } - else if constexpr (traits::is_mat_type_impl< - typename std::decay::type>::value || - traits::is_mat_type_impl::type>::value) + else if constexpr (ct::traits::is_mat_type_v || ct::traits::is_mat_type_v) { - if constexpr (std::is_arithmetic_v::type>) + if constexpr (std::is_arithmetic_v) { - return ct::mat_impl::mat_expression{ - lhs, rhs, rhs.rows(), rhs.cols(), op}; + return ct::mat_impl::mat_expression{lhs, rhs, rhs.rows(), rhs.cols(), op}; } - else if constexpr (std::is_same_v::type, - ct::scalar>) + else if constexpr (std::is_same_v) { - return ct::mat_impl::mat_expression{ - lhs.get(), rhs, rhs.rows(), rhs.cols(), op}; + return ct::mat_impl::mat_expression{lhs.get(), rhs, rhs.rows(), rhs.cols(), op}; } - else if constexpr (std::is_arithmetic_v< - typename std::decay::type>) + else if constexpr (std::is_arithmetic_v) { - return ct::mat_impl::mat_expression{ - lhs, rhs, lhs.rows(), lhs.cols(), op}; + return ct::mat_impl::mat_expression{lhs, rhs, lhs.rows(), lhs.cols(), op}; } - else if constexpr (std::is_same_v::type, - ct::scalar>) + else if constexpr (std::is_same_v) { - return ct::mat_impl::mat_expression{ - lhs, rhs.get(), lhs.rows(), lhs.cols(), op}; + return ct::mat_impl::mat_expression{lhs, rhs.get(), lhs.rows(), lhs.cols(), op}; } } - else - { - CkAbort("At least one operand must be a vector or a matrix"); - } } - template + template + requires ct::traits::is_tensor_type || ct::traits::is_tensor_type auto operator+(LHS const& lhs, RHS const& rhs) { return operator_impl(lhs, rhs, ct::util::Operation::add); } template + requires ct::traits::is_tensor_type || ct::traits::is_tensor_type auto operator-(LHS const& lhs, RHS const& rhs) { return operator_impl(lhs, rhs, ct::util::Operation::sub); } template + requires ct::traits::is_tensor_type || ct::traits::is_tensor_type auto operator/(LHS const& lhs, RHS const& rhs) { return operator_impl(lhs, rhs, ct::util::Operation::divide); } template + requires ct::traits::is_tensor_type || ct::traits::is_tensor_type auto operator*(LHS const& lhs, RHS const& rhs) { return operator_impl(lhs, rhs, ct::util::Operation::multiply); } template + requires ct::traits::is_tensor_type || ct::traits::is_tensor_type auto operator>(LHS const& lhs, RHS const& rhs) { return operator_impl(lhs, rhs, ct::util::Operation::greater); } template + requires ct::traits::is_tensor_type || ct::traits::is_tensor_type auto operator<(LHS const& lhs, RHS const& rhs) { return operator_impl(lhs, rhs, ct::util::Operation::lesser); } template + requires ct::traits::is_tensor_type || ct::traits::is_tensor_type auto operator==(LHS const& lhs, RHS const& rhs) { return operator_impl(lhs, rhs, ct::util::Operation::eq); } template + requires ct::traits::is_tensor_type || ct::traits::is_tensor_type auto operator!=(LHS const& lhs, RHS const& rhs) { return operator_impl(lhs, rhs, ct::util::Operation::neq); } template + requires ct::traits::is_tensor_type || ct::traits::is_tensor_type auto operator>=(LHS const& lhs, RHS const& rhs) { return operator_impl(lhs, rhs, ct::util::Operation::geq); } template + requires ct::traits::is_tensor_type || ct::traits::is_tensor_type auto operator<=(LHS const& lhs, RHS const& rhs) { return operator_impl(lhs, rhs, ct::util::Operation::leq); } template + requires ct::traits::is_tensor_type || ct::traits::is_tensor_type auto operator&&(LHS const& lhs, RHS const& rhs) { return operator_impl(lhs, rhs, ct::util::Operation::logical_and); } template + requires ct::traits::is_tensor_type || ct::traits::is_tensor_type auto operator||(LHS const& lhs, RHS const& rhs) { return operator_impl(lhs, rhs, ct::util::Operation::logical_or); } template + requires ct::traits::is_tensor_type auto operator!(LHS const& lhs) { return operator_impl(lhs, lhs, ct::util::Operation::logical_not); @@ -270,6 +277,7 @@ namespace ct { bool vec_mat = true) : lhs(lhs_) , rhs(rhs_) + , is_vec_mat(vec_mat) { } @@ -318,17 +326,19 @@ namespace ct { CProxy_matrix_impl dispatch_proxy = rhs_shape.proxy; CProxy_vector_impl lhs_proxy = lhs_shape.proxy; - lhs_proxy.send_to_matrix( - lhs_sdag_idx, lhs_shape.vector_id, rhs_sdag_idx, dispatch_proxy); + std::size_t numCharesY = rhs_shape.num_chares_y; + std::size_t numCharesX = rhs_shape.num_chares_x; + std::size_t row_len = CT_ACCESS_SINGLETON(ct::util::matrix_block_rows); + std::size_t col_len = CT_ACCESS_SINGLETON(ct::util::matrix_block_cols); + + lhs_proxy.send_to_matrix(lhs_sdag_idx, lhs_shape.vector_id, rhs_sdag_idx, row_len, col_len, numCharesX, numCharesY, expr.is_vec_mat, dispatch_proxy); + reductionMgmt.reset(); + dispatch_proxy.update_active_chares(rhs_sdag_idx); if (expr.is_vec_mat) - dispatch_proxy.vec_mat_dot(rhs_sdag_idx, rhs_shape.matrix_id, - result_sdag_idx, vector_shape_.proxy, vector_shape_.vector_id, - size_); + dispatch_proxy.vec_mat_dot(rhs_sdag_idx, rhs_shape.matrix_id, vector_shape_.proxy, size_); else - dispatch_proxy.mat_vec_dot(rhs_sdag_idx, rhs_shape.matrix_id, - result_sdag_idx, vector_shape_.proxy, vector_shape_.vector_id, - size_); + dispatch_proxy.mat_vec_dot(rhs_sdag_idx, rhs_shape.matrix_id, vector_shape_.proxy, size_); if (lhs_shape.shape_id == vector_shape_.shape_id) vector_shape_.proxy.update_index( @@ -367,16 +377,19 @@ namespace ct { CProxy_matrix_impl dispatch_proxy = rhs_shape.proxy; CProxy_vector_impl lhs_proxy = lhs_shape.proxy; - lhs_proxy.send_to_matrix( - lhs_sdag_idx, lhs_shape.vector_id, rhs_sdag_idx, dispatch_proxy); + std::size_t numCharesY = rhs_shape.num_chares_y; + std::size_t numCharesX = rhs_shape.num_chares_x; + std::size_t row_len = CT_ACCESS_SINGLETON(ct::util::matrix_block_rows); + std::size_t col_len = CT_ACCESS_SINGLETON(ct::util::matrix_block_cols); + + lhs_proxy.send_to_matrix(lhs_sdag_idx, lhs_shape.vector_id, rhs_sdag_idx, row_len, col_len, numCharesX, numCharesY, expr.is_vec_mat, dispatch_proxy); + reductionMgmt.reset(); + dispatch_proxy.update_active_chares(rhs_sdag_idx); + if (expr.is_vec_mat) - dispatch_proxy.vec_mat_dot(rhs_sdag_idx, rhs_shape.matrix_id, - result_sdag_idx, vector_shape_.proxy, vector_shape_.vector_id, - size_); + dispatch_proxy.vec_mat_dot(rhs_sdag_idx, rhs_shape.matrix_id, vector_shape_.proxy, size_); else - dispatch_proxy.mat_vec_dot(rhs_sdag_idx, rhs_shape.matrix_id, - result_sdag_idx, vector_shape_.proxy, vector_shape_.vector_id, - size_); + dispatch_proxy.mat_vec_dot(rhs_sdag_idx, rhs_shape.matrix_id, vector_shape_.proxy, size_); if (lhs_shape.shape_id == vector_shape_.shape_id) vector_shape_.proxy.update_index( @@ -448,87 +461,7 @@ namespace ct { CkAbort( "Dot Product with rvalue reference parameter is not supported."); } - - // BLAS L1: AXPY - namespace blas_impl { - - class vec_axpy_expr - { - friend class ct::vector; - - public: - vec_axpy_expr(double a_, ct::vector const& x_, ct::vector const& y_) - : a(a_) - , x(x_) - , y(y_) - { - } - - std::size_t size() const - { - return x.size(); - } - - private: - double a; - ct::vector const& x; - ct::vector const& y; - }; - } // namespace blas_impl - - inline vector::vector(blas_impl::vec_axpy_expr const& expr) - : size_(expr.size()) - , vector_shape_(ct::vec_impl::get_vector_shape(size_)) - , node_(vector_shape_.vector_id, ct::util::Operation::axpy, expr.a, size_, - expr.x.vector_shape().vector_id, expr.y.vector_shape().vector_id) - { - ct::vec_impl::vec_instr_queue_t& queue = - CT_ACCESS_SINGLETON(ct::vec_impl::vec_instr_queue); - - queue.insert(node_, vector_shape_.shape_id); - } - - inline vector& vector::operator=(blas_impl::vec_axpy_expr const& expr) - { - ct::vec_impl::vec_node node{vector_shape_.vector_id, - ct::util::Operation::axpy, expr.a, size_, - expr.x.vector_shape_.vector_id, expr.y.vector_shape_.vector_id}; - - ct::vec_impl::vec_instr_queue_t& queue = - CT_ACCESS_SINGLETON(ct::vec_impl::vec_instr_queue); - - queue.insert(node, vector_shape_.shape_id); - - return *this; - } - - inline blas_impl::vec_axpy_expr axpy( - double a, ct::vector const& x, ct::vector const& y) - { - std::size_t x_len = x.size(); - std::size_t y_len = y.size(); - CkAssert(x_len == y_len && - "Invalid vector dimensions passed to a*x + y Blas operation."); - - return ct::blas_impl::vec_axpy_expr{a, x, y}; - } - - // Non-implemented axpy variants - inline void axpy(double a, ct::vector&& x, ct::vector const& y) - { - CkAbort("AXPY with rvalue reference parameter is not supported."); - } - - inline void axpy(double a, ct::vector const& x, ct::vector&& y) - { - CkAbort("AXPY with rvalue reference parameter is not supported."); - } - - inline void axpy(double a, ct::vector&& x, ct::vector&& y) - { - CkAbort("AXPY with rvalue reference parameter is not supported."); - } - + namespace mat_mul_impl { class mat_mul_expr { @@ -564,14 +497,12 @@ namespace ct { , node_(matrix_shape_.matrix_id, ct::util::Operation::init_value, 0, row_size_, col_size_) { - ct::mat_impl::mat_shape_t const& lhs_shape = expr.lhs.matrix_shape(); - ct::mat_impl::mat_shape_t const& rhs_shape = expr.rhs.matrix_shape(); - - // Dispatch previous instructions belonging to this shape - ct::mat_impl::mat_instr_queue_t& mat_queue = - CT_ACCESS_SINGLETON(ct::mat_impl::mat_instr_queue); + ct::mat_impl::mat_instr_queue_t& mat_queue = CT_ACCESS_SINGLETON(ct::mat_impl::mat_instr_queue); + mat_queue.insert(node_, matrix_shape_.shape_id); mat_queue.dispatch(matrix_shape_.shape_id); + ct::mat_impl::mat_shape_t const& lhs_shape = expr.lhs.matrix_shape(); + ct::mat_impl::mat_shape_t const& rhs_shape = expr.rhs.matrix_shape(); std::size_t& curr_sdag_idx = mat_queue.sdag_idx(matrix_shape_.shape_id); CProxy_matrix_impl dispatch_proxy = matrix_shape_.proxy; @@ -605,25 +536,23 @@ namespace ct { return *this; } - inline ct::mat_mul_impl::mat_mul_expr operator*( - matrix const& lhs, matrix const& rhs) - { + inline ct::mat_mul_impl::mat_mul_expr matmul(matrix const& lhs, matrix const& rhs) { return mat_mul_impl::mat_mul_expr(lhs, rhs); } - inline mat_mul_impl::mat_mul_expr operator*(matrix const& lhs, matrix&& rhs) + inline mat_mul_impl::mat_mul_expr matmul(matrix const& lhs, matrix&& rhs) { CkAbort( "Matrix Multiplication not implemented for complex operations."); } - inline mat_mul_impl::mat_mul_expr operator*(matrix&& lhs, matrix const& rhs) + inline mat_mul_impl::mat_mul_expr matmul(matrix&& lhs, matrix const& rhs) { CkAbort( "Matrix Multiplication not implemented for complex operations."); } - inline mat_mul_impl::mat_mul_expr operator*(matrix&& lhs, matrix&& rhs) + inline mat_mul_impl::mat_mul_expr matmul(matrix&& lhs, matrix&& rhs) { CkAbort( "Matrix Multiplication not implemented for complex operations."); @@ -901,8 +830,8 @@ namespace ct { auto unary_expr( Operand const& operand, std::shared_ptr unary_op) { - if constexpr (traits::is_vec_type_impl< - typename std::decay::type>::value) + if constexpr (ct::traits::is_vec_type_v< + std::decay_t>) { return ct::vec_impl::vec_expression{operand, operand.size(), ct::util::Operation::unary_expr, unary_op}; @@ -919,8 +848,7 @@ namespace ct { auto custom_expr( Operand const& operand, std::shared_ptr custom_op) { - if constexpr (traits::is_vec_type_impl< - typename std::decay::type>::value) + if constexpr (ct::traits::is_vec_type_v>) { return ct::vec_impl::vec_expression{operand, operand.size(), ct::util::Operation::custom_expr, custom_op}; @@ -936,7 +864,7 @@ namespace ct { template auto where(LHS const& lhs, RHS const& rhs, THS const& ths) { - if constexpr (ct::traits::is_ter_vec_type::value) + if constexpr (ct::traits::is_ter_vec_type_v) { return ct::vec_impl::ter_vec_expression{ lhs, rhs, ths, lhs.size(), ct::util::Operation::where}; @@ -952,7 +880,7 @@ namespace ct { auto binary_expr(LHS const& lhs, RHS const& rhs, std::shared_ptr binary_op) { - if constexpr (ct::traits::is_vec_type::value) + if constexpr (ct::traits::is_bin_vec_type_v) { return ct::vec_impl::vec_expression{lhs, rhs, lhs.size(), ct::util::Operation::binary_expr, binary_op}; @@ -983,6 +911,10 @@ namespace ct { size, std::make_shared(data, size)); } + inline std::unique_ptr from_vector_unique(const double* data, uint64_t size) { + return std::make_unique(size, std::make_shared(data, size)); + } + inline ct::matrix from_matrix( const double* data, uint64_t rows, uint64_t cols) { @@ -990,4 +922,8 @@ namespace ct { std::make_shared(data, rows, cols)); } + inline std::unique_ptr from_matrix_unique(const double* data, uint64_t rows, uint64_t cols) { + return std::make_unique(rows, cols, std::make_shared(data, rows, cols)); + } + } // namespace ct diff --git a/charmtyles/frontend/scalar.hpp b/charmtyles/frontend/scalar.hpp index d6453d5..94c6ff6 100644 --- a/charmtyles/frontend/scalar.hpp +++ b/charmtyles/frontend/scalar.hpp @@ -52,20 +52,24 @@ namespace ct { return scalar_id_; } - double get() const + double get() { + if (evaluated) return most_recent_value_; ck::future fval; std::size_t& sdag_idx = CT_ACCESS_SINGLETON(ct::scal_impl::scalar_sdag_idx); proxy.get_value(sdag_idx, scalar_id_, fval); ++sdag_idx; - return fval.get(); + most_recent_value_ = fval.get(); + evaluated = true; + return most_recent_value_; } private: std::size_t scalar_id_; double most_recent_value_; + bool evaluated = false; mutable CProxy_scalar_impl proxy = scalar_impl_proxy; }; } // namespace ct diff --git a/charmtyles/frontend/vector.hpp b/charmtyles/frontend/vector.hpp index 79d850a..1a8659e 100644 --- a/charmtyles/frontend/vector.hpp +++ b/charmtyles/frontend/vector.hpp @@ -20,6 +20,11 @@ namespace ct { return curr_id; } + /** + * NOTE: + * shape_id is the number of vector shapes that exist + * vector_id is the number of vectors of that particular shape that exist + */ struct vec_shape_t { std::size_t shape_id; @@ -88,6 +93,20 @@ namespace ct { return dispatch_count; } + void codegen(instr_t& instructions) { + for (size_t i = 0; i < instructions.size();) { + instr_t region = ct::util::carveRegion(instructions, i); + + if (!region.empty()) { + cgen.reset(); + instructions[i][0].kernel = cgen.generate_kernel(region); + kokkosMgmt.dkload(std::get<0>(instructions[i][0].kernel)); + i += region.size(); + } else { + ++i; + } + } + } void print_instructions() const { ckout << "Printing Instructions:" << endl; @@ -115,6 +134,7 @@ namespace ct { // Dispatch all non-empty vectors! if (shape_vector_queue_[i].size() != 0) { + codegen(shape_vector_queue_[i]); is_dispatched = true; std::size_t& sdag_index = sdag_index_[i]; @@ -136,9 +156,11 @@ namespace ct { void dispatch(std::size_t shape_id) { + //print_instructions(); // Send instructions for execution if (shape_vector_queue_[shape_id].size() != 0) { + codegen(shape_vector_queue_[shape_id]); std::size_t& sdag_index = sdag_index_[shape_id]; CProxy_vector_impl dispatch_proxy = @@ -179,6 +201,8 @@ namespace ct { // Shape -> Instructions -> AST (per instruction) std::vector shape_vector_queue_; std::vector sdag_index_; + + Codegen cgen; }; CT_GENERATE_SINGLETON(vec_instr_queue_t, vec_instr_queue); @@ -365,23 +389,22 @@ namespace ct { std::copy(left.begin(), left.end(), std::back_inserter(ast)); if (op != ct::util::Operation::unary_expr) - std::copy( - right.begin(), right.end(), std::back_inserter(ast)); + std::copy(right.begin(), right.end(), std::back_inserter(ast)); // Update left and right neighbors for (int i = 1; i != left.size(); ++i) { - if (ast[i].left_ != static_cast(-1)) + if (ast[i].left_ != -1) { ast[i].left_ += 1; } - if (ast[i].right_ != static_cast(-1)) + if (ast[i].right_ != -1) { ast[i].right_ += 1; } - if (ast[i].ter_ != static_cast(-1)) + if (ast[i].ter_ != -1) { ast[i].ter_ += 1; } @@ -389,17 +412,17 @@ namespace ct { for (int i = 1 + left.size(); i != ast.size(); ++i) { - if (ast[i].left_ != static_cast(-1)) + if (ast[i].left_ != -1) { ast[i].left_ += 1 + left.size(); } - if (ast[i].right_ != static_cast(-1)) + if (ast[i].right_ != -1) { ast[i].right_ += 1 + left.size(); } - if (ast[i].ter_ != static_cast(-1)) + if (ast[i].ter_ != -1) { ast[i].ter_ += 1 + left.size(); } @@ -465,17 +488,17 @@ namespace ct { // Update left and right neighbors for (int i = 1; i != left.size(); ++i) { - if (ast[i].left_ != static_cast(-1)) + if (ast[i].left_ != -1) { ast[i].left_ += 1; } - if (ast[i].right_ != static_cast(-1)) + if (ast[i].right_ != -1) { ast[i].right_ += 1; } - if (ast[i].ter_ != static_cast(-1)) + if (ast[i].ter_ != -1) { ast[i].ter_ += 1; } @@ -484,17 +507,17 @@ namespace ct { for (int i = 1 + left.size(); i != left.size() + right.size(); ++i) { - if (ast[i].left_ != static_cast(-1)) + if (ast[i].left_ != -1) { ast[i].left_ += 1 + left.size(); } - if (ast[i].right_ != static_cast(-1)) + if (ast[i].right_ != -1) { ast[i].right_ += 1 + left.size(); } - if (ast[i].ter_ != static_cast(-1)) + if (ast[i].ter_ != -1) { ast[i].ter_ += 1 + left.size(); } @@ -503,17 +526,17 @@ namespace ct { for (int i = 1 + left.size() + right.size(); i != ast.size(); ++i) { - if (ast[i].left_ != static_cast(-1)) + if (ast[i].left_ != -1) { ast[i].left_ += 1 + left.size() + right.size(); } - if (ast[i].right_ != static_cast(-1)) + if (ast[i].right_ != -1) { ast[i].right_ += 1 + left.size() + right.size(); } - if (ast[i].ter_ != static_cast(-1)) + if (ast[i].ter_ != -1) { ast[i].ter_ += 1 + left.size() + right.size(); } @@ -541,10 +564,6 @@ namespace ct { class dot_expression; } - namespace blas_impl { - class vec_axpy_expr; - } - class vector { template @@ -626,14 +645,11 @@ namespace ct { return *this; } - // TODO: Figure out why this is necessary! vector(vector&& other) : size_(other.size_) , vector_shape_(other.vector_shape_) , node_(other.node_) - { - // ckout << "Move constructor called!" << endl; - } + {} template vector(ct::vec_impl::vec_expression const& e) @@ -653,6 +669,20 @@ namespace ct { queue.insert(instr, vector_shape_.shape_id); } + vector(std::vector& instr) { + ct::vec_impl::vec_node& root = instr.front(); + size_ = root.vec_len_; + + vector_shape_ = ct::vec_impl::get_vector_shape(size_); + + root.name_ = vector_shape_.vector_id; + node_ = ct::vec_impl::vec_node{root}; + + ct::vec_impl::vec_instr_queue_t& queue = CT_ACCESS_SINGLETON(ct::vec_impl::vec_instr_queue); + + queue.insert(instr, vector_shape_.shape_id); + } + template vector& operator=(ct::vec_impl::vec_expression const& e) { @@ -672,9 +702,6 @@ namespace ct { vector(dot_impl::dot_expression const&); vector& operator=(dot_impl::dot_expression const&); - vector(blas_impl::vec_axpy_expr const&); - vector& operator=(blas_impl::vec_axpy_expr const&); - template vector(ct::vec_impl::ter_vec_expression const& e) { @@ -746,14 +773,14 @@ namespace ct { auto instr = e(); instr.front().name_ = vector_shape_.vector_id; ct::vec_impl::vec_node root{ct::util::Operation::inplace_add, size_}; - root.left_ = static_cast(-1); + root.left_ = -1; root.right_ = 1; root.name_ = vector_shape_.vector_id; instr.insert(instr.begin(), root); for (std::size_t i = 1; i < instr.size(); ++i) { - if (instr[i].left_ != static_cast(-1)) instr[i].left_ += 1; - if (instr[i].right_ != static_cast(-1)) instr[i].right_ += 1; + if (instr[i].left_ != -1) instr[i].left_ += 1; + if (instr[i].right_ != -1) instr[i].right_ += 1; } ct::vec_impl::vec_instr_queue_t& queue = CT_ACCESS_SINGLETON(ct::vec_impl::vec_instr_queue); @@ -767,14 +794,14 @@ namespace ct { auto instr = e(); instr.front().name_ = vector_shape_.vector_id; ct::vec_impl::vec_node root{ct::util::Operation::inplace_sub, size_}; - root.left_ = static_cast(-1); + root.left_ = -1; root.right_ = 1; root.name_ = vector_shape_.vector_id; instr.insert(instr.begin(), root); for (std::size_t i = 1; i < instr.size(); ++i) { - if (instr[i].left_ != static_cast(-1)) instr[i].left_ += 1; - if (instr[i].right_ != static_cast(-1)) instr[i].right_ += 1; + if (instr[i].left_ != -1) instr[i].left_ += 1; + if (instr[i].right_ != -1) instr[i].right_ += 1; } ct::vec_impl::vec_instr_queue_t& queue = CT_ACCESS_SINGLETON(ct::vec_impl::vec_instr_queue); @@ -788,14 +815,14 @@ namespace ct { auto instr = e(); instr.front().name_ = vector_shape_.vector_id; ct::vec_impl::vec_node root{ct::util::Operation::inplace_divide, size_}; - root.left_ = static_cast(-1); + root.left_ = -1; root.right_ = 1; root.name_ = vector_shape_.vector_id; instr.insert(instr.begin(), root); for (std::size_t i = 1; i < instr.size(); ++i) { - if (instr[i].left_ != static_cast(-1)) instr[i].left_ += 1; - if (instr[i].right_ != static_cast(-1)) instr[i].right_ += 1; + if (instr[i].left_ != -1) instr[i].left_ += 1; + if (instr[i].right_ != -1) instr[i].right_ += 1; } ct::vec_impl::vec_instr_queue_t& queue = CT_ACCESS_SINGLETON(ct::vec_impl::vec_instr_queue); @@ -804,7 +831,6 @@ namespace ct { } // Helper functions - public: const ct::vec_impl::vec_shape_t vector_shape() const { return vector_shape_; @@ -893,7 +919,6 @@ namespace ct { return fval.get(); } - private: std::vector operator()() const { ct::vec_impl::vec_node new_node{node_}; @@ -902,24 +927,14 @@ namespace ct { return std::vector{new_node}; } + ~vector() { + ct::vec_impl::vec_node delNode(vector_shape_.vector_id, ct::util::Operation::dealloc, size_); + ct::vec_impl::vec_instr_queue_t& queue = CT_ACCESS_SINGLETON(ct::vec_impl::vec_instr_queue); + queue.insert(delNode, vector_shape_.shape_id); + } + private: std::size_t size_; ct::vec_impl::vec_shape_t vector_shape_; ct::vec_impl::vec_node node_; }; - - namespace traits { - template - struct is_vec_type_impl - { - constexpr static bool value = false; - }; - - template <> - struct is_vec_type_impl - { - constexpr static bool value = true; - }; - - } // namespace traits - } // namespace ct diff --git a/charmtyles/util/AST.hpp b/charmtyles/util/AST.hpp index e0ac85a..fcac349 100644 --- a/charmtyles/util/AST.hpp +++ b/charmtyles/util/AST.hpp @@ -37,9 +37,6 @@ namespace ct { //Broadcast broadcast = 19, - // Blas - axpy = 20, - // Logical logical_and = 21, logical_or = 22, @@ -57,7 +54,11 @@ namespace ct { unary_expr = 30, // Binary operations binary_expr = 40, - custom_expr = 50 + custom_expr = 50, + // handled separately as dot / mat_mul + matmul = 60, + // deletion + dealloc = 70 }; inline bool is_init_type(ct::util::Operation op) @@ -129,11 +130,120 @@ namespace ct { ckout << " - "; parse_ast(instr, instr[index].right_); return; + case Operation::multiply: + parse_ast(instr, instr[index].left_); + ckout << " * "; + parse_ast(instr, instr[index].right_); + return; + case Operation::divide: + parse_ast(instr, instr[index].left_); + ckout << " / "; + parse_ast(instr, instr[index].right_); + return; + case Operation::lesser: + parse_ast(instr, instr[index].left_); + ckout << " < "; + parse_ast(instr, instr[index].right_); + return; + case Operation::greater: + parse_ast(instr, instr[index].left_); + ckout << " > "; + parse_ast(instr, instr[index].right_); + return; + case Operation::leq: + parse_ast(instr, instr[index].left_); + ckout << " <= "; + parse_ast(instr, instr[index].right_); + return; + case Operation::geq: + parse_ast(instr, instr[index].left_); + ckout << " >= "; + parse_ast(instr, instr[index].right_); + return; + case Operation::eq: + parse_ast(instr, instr[index].left_); + ckout << " == "; + parse_ast(instr, instr[index].right_); + return; + case Operation::neq: + parse_ast(instr, instr[index].left_); + ckout << " != "; + parse_ast(instr, instr[index].right_); + return; + case Operation::logical_and: + parse_ast(instr, instr[index].left_); + ckout << " & "; + parse_ast(instr, instr[index].right_); + return; + case Operation::logical_or: + parse_ast(instr, instr[index].left_); + ckout << " | "; + parse_ast(instr, instr[index].right_); + return; + case Operation::logical_not: + ckout << "!"; + parse_ast(instr, instr[index].left_); + return; + case Operation::broadcast: + ckout << "SCALAR(" << instr[index].value_ << ")"; + return; + case Operation::unary_expr: + ckout << instr[index].unary_expr_->get_name().c_str() << "("; + parse_ast(instr, instr[index].left_); + ckout << ")"; + return; + case Operation::binary_expr: + ckout << instr[index].binary_expr_->get_name().c_str() << "("; + parse_ast(instr, instr[index].left_); + ckout << ", "; + parse_ast(instr, instr[index].right_); + ckout << ")"; + return; + case Operation::dealloc: + ckout << "delete " << instr[index].name_; + return; + case Operation::where: + parse_ast(instr, instr[index].ter_); + ckout << " ? "; + parse_ast(instr, instr[index].left_); + ckout << " : "; + parse_ast(instr, instr[index].right_); + return; default: - CmiAbort("Operation not implemented"); + CmiAbort("Operation %i not implemented", short(instr[index].operation_)); } } + using kernelInfo = std::tuple, std::vector>, std::vector>; + + template + std::vector> carveRegion(const std::vector>& instructions, std::size_t regionIndx) { + std::vector> region; + + while (regionIndx < instructions.size()) { + auto op = instructions[regionIndx][0].operation_; + bool isSpecialOperation = + (op == Operation::init_random || + op == Operation::init_value || + op == Operation::init_generate || + op == Operation::dealloc || + op == Operation::copy || + op == Operation::custom_expr || + (op == Operation::inplace_add && + instructions[regionIndx][0].copy_id_ != -1) || + (op == Operation::inplace_sub && + instructions[regionIndx][0].copy_id_ != -1) || + (op == Operation::inplace_divide && + instructions[regionIndx][0].copy_id_ != -1)); + + if (isSpecialOperation) break; + region.push_back(instructions[regionIndx]); + if (!instructions[regionIndx][0].multiLineFuse) break; + ++regionIndx; + } + + return std::move(region); + } } // namespace util namespace vec_impl { @@ -157,6 +267,9 @@ namespace ct { std::size_t right_ = -1; std::size_t ter_ = -1; + ct::util::kernelInfo kernel; + bool multiLineFuse = false; + // Only called when initializing through expression vec_node() = default; vec_node(vec_node const& other) = default; @@ -168,6 +281,12 @@ namespace ct { { } + explicit vec_node(ct::util::Operation op, std::vector size) + : operation_(op) + , vec_len_(size[0]) + { + } + explicit vec_node( std::size_t name, ct::util::Operation op, std::size_t size) : name_(name) @@ -186,6 +305,16 @@ namespace ct { { } + explicit vec_node(std::size_t name, ct::util::Operation op, + std::shared_ptr unary_expr, + std::vector size) + : name_(name) + , operation_(op) + , unary_expr_(unary_expr) + , vec_len_(size[0]) + { + } + explicit vec_node(std::size_t name, ct::util::Operation op, std::shared_ptr binary_expr, std::size_t vec_len) @@ -196,6 +325,16 @@ namespace ct { { } + explicit vec_node(std::size_t name, ct::util::Operation op, + std::shared_ptr binary_expr, + std::vector size) + : name_(name) + , operation_(op) + , binary_expr_(binary_expr) + , vec_len_(size[0]) + { + } + explicit vec_node(std::size_t name, ct::util::Operation op, std::shared_ptr custom_expr, std::size_t vec_len) @@ -206,6 +345,16 @@ namespace ct { { } + explicit vec_node(std::size_t name, ct::util::Operation op, + std::shared_ptr custom_expr, + std::vector size) + : name_(name) + , operation_(op) + , custom_expr_(custom_expr) + , vec_len_(size[0]) + { + } + explicit vec_node( std::size_t name, ct::util::Operation op, vec_node const& other) : name_(name) @@ -217,6 +366,15 @@ namespace ct { { } + explicit vec_node(std::size_t name, ct::util::Operation op, + double value, std::vector size) + : name_(name) + , operation_(op) + , value_(value) + , vec_len_(size[0]) + { + } + explicit vec_node(std::size_t name, ct::util::Operation op, double value, std::size_t size) : name_(name) @@ -250,6 +408,8 @@ namespace ct { p | left_; p | right_; p | ter_; + p | kernel; + p | multiLineFuse; } }; @@ -277,6 +437,9 @@ namespace ct { std::size_t right_ = -1; std::size_t ter_ = -1; + ct::util::kernelInfo kernel; + bool multiLineFuse = false; + // Only called when initializing through expression mat_node() = default; @@ -288,6 +451,14 @@ namespace ct { { } + explicit mat_node( + ct::util::Operation op, std::vector size) + : operation_(op) + , mat_row_len_(size[0]) + , mat_col_len_(size[1]) + { + } + explicit mat_node(std::size_t matrix_id, ct::util::Operation op, std::size_t rows, std::size_t cols) : name_(matrix_id) @@ -308,6 +479,17 @@ namespace ct { { } + explicit mat_node(std::size_t matrix_id, ct::util::Operation op, + std::shared_ptr unary_expr, + std::vector size) + : name_(matrix_id) + , operation_(op) + , unary_expr_(unary_expr) + , mat_row_len_(size[0]) + , mat_col_len_(size[1]) + { + } + explicit mat_node(std::size_t matrix_id, ct::util::Operation op, std::shared_ptr binary_expr, std::size_t rows, std::size_t cols) @@ -319,6 +501,17 @@ namespace ct { { } + explicit mat_node(std::size_t matrix_id, ct::util::Operation op, + std::shared_ptr binary_expr, + std::vector size) + : name_(matrix_id) + , operation_(op) + , binary_expr_(binary_expr) + , mat_row_len_(size[0]) + , mat_col_len_(size[1]) + { + } + explicit mat_node(std::size_t matrix_id, ct::util::Operation op, std::shared_ptr custom_expr, std::size_t rows, std::size_t cols) @@ -330,6 +523,17 @@ namespace ct { { } + explicit mat_node(std::size_t matrix_id, ct::util::Operation op, + std::shared_ptr custom_expr, + std::vector size) + : name_(matrix_id) + , operation_(op) + , custom_expr_(custom_expr) + , mat_row_len_(size[0]) + , mat_col_len_(size[1]) + { + } + explicit mat_node(std::size_t matrix_id, ct::util::Operation op, double value, std::size_t rows, std::size_t cols) : name_(matrix_id) @@ -340,6 +544,16 @@ namespace ct { { } + explicit mat_node(std::size_t matrix_id, ct::util::Operation op, + double value, std::vector size) + : name_(matrix_id) + , operation_(op) + , value_(value) + , mat_row_len_(size[0]) + , mat_col_len_(size[1]) + { + } + explicit mat_node(std::size_t matrix_id, ct::util::Operation op, mat_node const& other) : name_(matrix_id) @@ -369,6 +583,8 @@ namespace ct { p | left_; p | right_; p | ter_; + p | kernel; + p | multiLineFuse; } }; diff --git a/charmtyles/util/generator.hpp b/charmtyles/util/generator.hpp index 8ce7ce2..67c1df6 100644 --- a/charmtyles/util/generator.hpp +++ b/charmtyles/util/generator.hpp @@ -1,7 +1,7 @@ #pragma once #include "charm++.h" -#include "matrix_view.hpp" +#include #include namespace ct { @@ -150,18 +150,22 @@ namespace ct { { PUP::able::pup(p); } - - // Default Operator overload for vectors - virtual double operator()(std::size_t index, double value) + virtual std::string get_name() + { + return ""; + } + virtual std::string get_vec_signature() { - return -1.0; + return ""; } - // Default Operator overload for matrices - virtual double operator()( - std::size_t row_id, std::size_t col_id, double value) + virtual std::string get_mat_signature() + { + return ""; + } + virtual std::vector get_extra_params() { - return -1.0; + return {}; } }; @@ -182,17 +186,22 @@ namespace ct { { PUP::able::pup(p); } - - virtual double operator()( - std::size_t index, double left_val, double right_val) + virtual std::string get_name() + { + return ""; + } + virtual std::string get_vec_signature() { - return -1.0; + return ""; } - virtual double operator()(std::size_t row_id, std::size_t col_id, - double left_val, double right_val) + virtual std::string get_mat_signature() + { + return ""; + } + virtual std::vector get_extra_params() { - return -1.0; + return {}; } }; @@ -221,8 +230,10 @@ namespace ct { } virtual void operator()(std::size_t rows, std::size_t cols, - ct::util::matrix_view& lhs, ct::util::matrix_view& rhs) + std::vector>& lhs, + std::vector>& rhs) { + // Default implementation: copy rhs to lhs lhs = rhs; } }; diff --git a/charmtyles/util/matrix_view.hpp b/charmtyles/util/matrix_view.hpp deleted file mode 100644 index c30d88a..0000000 --- a/charmtyles/util/matrix_view.hpp +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once - -#include -#include - -#include "charm++.h" - -namespace ct { namespace util { - - class matrix_view - { - public: - matrix_view() = default; - - matrix_view(matrix_view const& other) = default; - matrix_view(matrix_view&& other) = default; - matrix_view& operator=(matrix_view const& other) = default; - matrix_view& operator=(matrix_view&& other) = default; - - explicit matrix_view(std::size_t rows, std::size_t cols) - : rows_(rows) - , cols_(cols) - , mat_(rows * cols) - { - } - - explicit matrix_view(std::size_t rows, std::size_t cols, double value) - : rows_(rows) - , cols_(cols) - , mat_(rows * cols, value) - { - } - - double& operator()(std::size_t row, std::size_t col) - { - return mat_[row * cols_ + col]; - } - - const double& operator()(std::size_t row, std::size_t col) const - { - return mat_[row * cols_ + col]; - } - - std::size_t rows() const - { - return rows_; - } - - std::size_t cols() const - { - return cols_; - } - - double* data() - { - return mat_.data(); - } - - const double* data() const - { - return mat_.data(); - } - - void pup(PUP::er& p) - { - p | rows_; - p | cols_; - p | mat_; - } - - private: - std::size_t rows_; - std::size_t cols_; - std::vector mat_; - }; -}} // namespace ct::util diff --git a/config.cmake b/config.cmake new file mode 100644 index 0000000..d296c70 --- /dev/null +++ b/config.cmake @@ -0,0 +1,35 @@ +if(DEFINED ENV{CHARM_DIR}) + set(CHARM_DIR "$ENV{CHARM_DIR}") +else() + set(CHARM_DIR "/home/shogo/master/Kale/charm/netlrts-linux-x86_64") +endif() + +if(DEFINED ENV{BASE_DIR}) + set(BASE_DIR "$ENV{BASE_DIR}") +else() + get_filename_component(BASE_DIR "${CMAKE_CURRENT_LIST_DIR}" ABSOLUTE) +endif() + +if(DEFINED ENV{EIGEN_DIR}) + set(EIGEN_DIR "$ENV{EIGEN_DIR}") +else() + set(EIGEN_DIR "/usr/include/eigen3") +endif() + +# set(CUDA_DIR "/path/to/CUDA/directory") + +if(DEFINED ENV{KOKKOS_DIR}) + set(KOKKOS_DIR "$ENV{KOKKOS_DIR}") + set(KOKKOS_KERNELS_DIR "$ENV{KOKKOS_KERNELS_DIR}") +else() + set(KOKKOS_DIR "${BASE_DIR}/kokkos/install") + set(KOKKOS_KERNELS_DIR "${BASE_DIR}/kokkos-kernels/install") +endif() +set(KOKKOS_KERNELS_DIR "${BASE_DIR}/kokkos-kernels/install") + +set(CHARMC "${CHARM_DIR}/bin/charmc") +set(CPU_OPTS "-c++-option -std=c++20 -O3 -march=native -DNDEBUG") +set(GPU_OPTS "-std=c++20 -O3 -march=native -DNDEBUG") +set(GPU_LINK_OPTS -O3 -language charm++ -L${KOKKOS_DIR}/lib64 -L/u/ajain18/kokkos_kernels_install/lib64 -lkokkoscore -lkokkoscontainers -lkokkoskernels -L${CUDA_DIR} -lcuda -lcudart -lcusparse -lcublas) +set(LD_OPTS "") +set(INCS "-I${BASE_DIR}") diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..9a9bbf6 --- /dev/null +++ b/setup.sh @@ -0,0 +1,40 @@ +if [ -d "./kokkos/install" ]; then + echo "Kokkos Found at ${PWD}/kokkos/install" +else + export KOKKOS_VERSION=4.7.01 # Replace with the actual version + export KOKKOS_DOWNLOAD_URL=https://github.com/kokkos/kokkos/releases/download/${KOKKOS_VERSION} + curl -sLO ${KOKKOS_DOWNLOAD_URL}/kokkos-${KOKKOS_VERSION}.tar.gz + tar -xzvf kokkos-${KOKKOS_VERSION}.tar.gz + rm kokkos-${KOKKOS_VERSION}.tar.gz + mv kokkos-${KOKKOS_VERSION} kokkos + cd kokkos + mkdir build + cd build + cmake -DBUILD_SHARED_LIBS=ON .. + make -j${nproc} + cd .. + mkdir install + cmake --install build --prefix install + cd .. +fi + +if [ -d "./kokkos-kernels/install" ]; then + echo "Kokkos Kernels Found at ${PWD}/kokkos-kernels/install" +else + git clone https://github.com/kokkos/kokkos-kernels.git + export KOKKOS_KERNELS_VERSION=4.7.01 # Replace with the actual version + export KOKKOS_DOWNLOAD_URL=https://github.com/kokkos/kokkos-kernels/releases/download/${KOKKOS_VERSION} + curl -sLO ${KOKKOS_DOWNLOAD_URL}/kokkos-kernels-${KOKKOS_VERSION}.tar.gz + tar -xzvf kokkos-kernels-${KOKKOS_VERSION}.tar.gz + rm kokkos-kernels-${KOKKOS_VERSION}.tar.gz + mv kokkos-kernels-${KOKKOS_VERSION} kokkos-kernels + cd kokkos-kernels + mkdir build + cd build + cmake .. -DCMAKE_CXX_COMPILER=g++ -DCMAKE_INSTALL_PREFIX=${PWD}/../install -DKokkos_ROOT=${PWD}/../../kokkos/install -DBUILD_SHARED_LIBS=ON + make -j${nproc} + cd .. + mkdir install + cmake --install build --prefix install + cd .. +fi \ No newline at end of file diff --git a/setup_gpu.sh b/setup_gpu.sh new file mode 100644 index 0000000..acc5ab2 --- /dev/null +++ b/setup_gpu.sh @@ -0,0 +1,50 @@ +if [ -d "./kokkos/install" ]; then + echo "Kokkos Found at ${PWD}/kokkos/install" +else + export KOKKOS_VERSION=4.7.01 # Replace with the actual version + export KOKKOS_DOWNLOAD_URL=https://github.com/kokkos/kokkos/releases/download/${KOKKOS_VERSION} + curl -sLO ${KOKKOS_DOWNLOAD_URL}/kokkos-${KOKKOS_VERSION}.tar.gz + tar -xzvf kokkos-${KOKKOS_VERSION}.tar.gz + rm kokkos-${KOKKOS_VERSION}.tar.gz + mv kokkos-${KOKKOS_VERSION} kokkos + cd kokkos + rm -rf build + mkdir build + cd build + + # ensure that you have cmake/3.27.9 cuda/12.4.0 and eigen[for later] loaded + + ## for delta please run these before running the setup script + # module load cuda/12.4.0 + # module load eigen + # module load cmake/3.27.9 + + ## The best practice is to let cmake autodetect the architecture, please run on a GPU syster or add a srun + srun cmake -DBUILD_SHARED_LIBS=ON .. -DKokkos_ENABLE_CUDA=ON + make -j${nproc} + cd .. + mkdir install + cmake --install build --prefix install + cd .. +fi + +if [ -d "./kokkos-kernels/install" ]; then + echo "Kokkos Kernels Found at ${PWD}/kokkos_kernels/install" +else + git clone https://github.com/kokkos/kokkos-kernels.git + export KOKKOS_KERNELS_VERSION=4.7.01 # Replace with the actual version + export KOKKOS_DOWNLOAD_URL=https://github.com/kokkos/kokkos-kernels/releases/download/${KOKKOS_VERSION} + curl -sLO ${KOKKOS_DOWNLOAD_URL}/kokkos-kernels-${KOKKOS_VERSION}.tar.gz + tar -xzvf kokkos-kernels-${KOKKOS_VERSION}.tar.gz + rm kokkos-kernels-${KOKKOS_VERSION}.tar.gz + mv kokkos-kernels-${KOKKOS_VERSION} kokkos-kernels + cd kokkos-kernels + mkdir build + cd build + cmake .. -DCMAKE_CXX_COMPILER=g++ -DCMAKE_INSTALL_PREFIX=${PWD}/../install -DKokkos_ROOT=${PWD}/../../kokkos/install -DBUILD_SHARED_LIBS=ON + make -j${nproc} + cd .. + mkdir install + cmake --install build --prefix install + cd .. +fi diff --git a/tests/binary/.gitignore b/tests/binary/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/tests/binary/.gitignore @@ -0,0 +1 @@ +build diff --git a/tests/binary/CMakeLists.txt b/tests/binary/CMakeLists.txt new file mode 100644 index 0000000..c9e7bd6 --- /dev/null +++ b/tests/binary/CMakeLists.txt @@ -0,0 +1,54 @@ +cmake_minimum_required(VERSION 3.16) +project(charmTyles) + +include(${CMAKE_SOURCE_DIR}/../../config.cmake) + +set(Kokkos_ROOT ${KOKKOS_DIR}) +find_package(Kokkos 4.5 REQUIRED CONFIG) + +set(KokkosKernels_DIR ${KOKKOS_KERNELS_DIR}/lib/cmake/KokkosKernels) +find_package(KokkosKernels REQUIRED) + +if(Charm_ENABLE_GPU) + message(STATUS "Building for a GPU backend") + add_definitions(-DGPU_BACKEND) + add_definitions(-DCUDA_DIR=\"${CUDA_DIR}\") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GPU_OPTS} ${LD_OPTS}") +else() + message(STATUS "Building for a CPU backend") + set(CMAKE_CXX_COMPILER "${CHARMC}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CPU_OPTS} ${LD_OPTS}") +endif() + +add_definitions(-DKOKKOS_DIR=\"${KOKKOS_DIR}\") + +add_custom_command( + OUTPUT ${BASE_DIR}/charmtyles/backend/libcharmtyles.decl.h + COMMAND ${CMAKE_COMMAND} -E chdir ${BASE_DIR}/charmtyles/backend + ${CHARMC} ${BASE_DIR}/charmtyles/backend/charmtyles.ci + DEPENDS ${BASE_DIR}/charmtyles/backend/charmtyles.ci + COMMENT "Processing charmtyles ci files" +) + +add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/base.decl.h + COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_SOURCE_DIR} + ${CHARMC} ${CMAKE_SOURCE_DIR}/base.ci + DEPENDS ${CMAKE_SOURCE_DIR}/base.ci + COMMENT "Processing base ci files" +) + +if(Charm_ENABLE_GPU) + add_library(binary_include OBJECT binary_include.cpp ${BASE_DIR}/charmtyles/backend/libcharmtyles.decl.h ${CMAKE_SOURCE_DIR}/base.decl.h) + target_include_directories(binary_include PRIVATE ${BASE_DIR} ${BASE_DIR}/charmtyles/backend ${EIGEN_DIR}/include ${CHARM_DIR}/include) + target_link_libraries(binary_include Kokkos::kokkos Kokkos::kokkoskernels) + + add_custom_command(result ALL + COMMAND ${CHARMC} ${GPU_LINK_OPTS} $:binary_include> -o ${CMAKE_BINARY_DIR}/binary_include.out + DEPENDS binary_include + COMMENT "Linking charm build against kokkos and cuda") +else() + add_executable(binary_include.out binary_include.cpp ${BASE_DIR}/charmtyles/backend/libcharmtyles.decl.h ${CMAKE_SOURCE_DIR}/base.decl.h) + target_include_directories(binary_include.out PRIVATE ${BASE_DIR} ${BASE_DIR}/charmtyles/backend ${EIGEN_DIR}) + target_link_libraries(binary_include.out Kokkos::kokkos Kokkos::kokkoskernels) +endif() diff --git a/tests/binary/binary_include.cpp b/tests/binary/binary_include.cpp index 8aeb4a8..2f8546e 100644 --- a/tests/binary/binary_include.cpp +++ b/tests/binary/binary_include.cpp @@ -9,10 +9,6 @@ class Main : public CBase_Main public: Main(CkArgMsg* msg) { - int num_pes = 6; - if (msg->argc > 1) - num_pes = atoi(msg->argv[1]); - ct::init(); thisProxy.benchmark(); } @@ -26,14 +22,19 @@ class Main : public CBase_Main ct::vector neg_result = ct::unary_expr(vec1, ct::unary_ops::negate()); ct::scalar neg_sum = ct::sum(neg_result); double neg_val = neg_sum.get(); - ckout << " Negate [3,3,3,3,3] -> sum = " << neg_val << " (expected: -15)" << endl; - + ckout << "Negate [3,3,3,3,3] -> sum = " << neg_val << " (expected: -15)" << endl; + ct::vector vec_neg(4, -2.5); // [-2.5, -2.5, -2.5, -2.5] ct::vector abs_result = ct::unary_expr(vec_neg, ct::unary_ops::abs()); ct::scalar abs_sum = ct::sum(abs_result); double abs_val = abs_sum.get(); ckout << "sum = " << abs_val << " (expected: 10)" << endl; - + + ct::vector vec_scale(4, 2.5); // [2.5, 2.5, 2.5, 2.5] + ct::vector scale_result = ct::unary_expr(vec_scale, ct::unary_ops::scale(2.0)); + ct::scalar scale_sum = ct::sum(scale_result); + double scalar_result = scale_sum.get(); + ckout << "sum = " << scalar_result << " (expected: 20)" << endl; ct::vector vec3(5, 1.0); // [1, 1, 1, 1, 1] ct::vector vec4(5, 2.0); // [2, 2, 2, 2, 2] @@ -43,10 +44,8 @@ class Main : public CBase_Main ct::scalar add_sum = ct::sum(add_result); double add_val = add_sum.get(); ckout << "sum = " << add_val << " (expected: 15)" << endl; - - - - + + ct::finalize(); CkExit(); } }; diff --git a/tests/comprehensive/CMakeLists.txt b/tests/comprehensive/CMakeLists.txt new file mode 100644 index 0000000..c5cac8c --- /dev/null +++ b/tests/comprehensive/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 3.16) +project(charmtyles_comprehensive_tests) + +include(${CMAKE_SOURCE_DIR}/../../config.cmake) + +set(Kokkos_ROOT ${KOKKOS_DIR}) +find_package(Kokkos 4.5 REQUIRED CONFIG) + +if(Charm_ENABLE_GPU) + message(STATUS "Building for a GPU backend") + add_definitions(-DGPU_BACKEND) + add_definitions(-DCUDA_DIR=\"${CUDA_DIR}\") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GPU_OPTS} ${LD_OPTS}") +else() + message(STATUS "Building for a CPU backend") + set(CMAKE_CXX_COMPILER "${CHARMC}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CPU_OPTS} ${LD_OPTS}") +endif() + +add_definitions(-DKOKKOS_DIR=\"${KOKKOS_DIR}\" ) + +add_custom_command( + OUTPUT ${BASE_DIR}/charmtyles/backend/libcharmtyles.decl.h + COMMAND ${CMAKE_COMMAND} -E chdir ${BASE_DIR}/charmtyles/backend + ${CHARMC} ${BASE_DIR}/charmtyles/backend/charmtyles.ci + DEPENDS ${BASE_DIR}/charmtyles/backend/charmtyles.ci + COMMENT "Processing charmtyles ci files" +) + +add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/base.decl.h + COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_SOURCE_DIR} + ${CHARMC} ${CMAKE_SOURCE_DIR}/base.ci + DEPENDS ${CMAKE_SOURCE_DIR}/base.ci + COMMENT "Processing base ci files" +) + +if(Charm_ENABLE_GPU) + add_library(comprehensive_tests OBJECT comprehensive.cpp ${BASE_DIR}/charmtyles/backend/libcharmtyles.decl.h ${CMAKE_SOURCE_DIR}/base.decl.h) + target_include_directories(comprehensive_tests PRIVATE ${BASE_DIR} ${BASE_DIR}/charmtyles/backend ${EIGEN_DIR}/include ${CHARM_DIR}/include) + target_link_libraries(comprehensive_tests Kokkos::kokkos) + + add_custom_command( + OUTPUT "${CMAKE_BINARY_DIR}/comprehensive_tests.out" + COMMAND ${CHARMC} ${GPU_LINK_OPTS} $ -o ${CMAKE_BINARY_DIR}/comprehensive_tests.out + DEPENDS comprehensive_tests + COMMENT "Linking charm build against kokkos and cuda" + ) + + add_custom_target(result ALL + DEPENDS "${CMAKE_BINARY_DIR}/comprehensive_tests.out" + ) +else() + add_executable(comprehensive_tests.out comprehensive.cpp ${BASE_DIR}/charmtyles/backend/libcharmtyles.decl.h ${CMAKE_SOURCE_DIR}/base.decl.h) + target_include_directories(comprehensive_tests.out PRIVATE ${BASE_DIR} ${BASE_DIR}/charmtyles/backend ${EIGEN_DIR}) + target_link_libraries(comprehensive_tests.out Kokkos::kokkos) +endif() diff --git a/tests/comprehensive/Makefile b/tests/comprehensive/Makefile new file mode 100644 index 0000000..ac6f033 --- /dev/null +++ b/tests/comprehensive/Makefile @@ -0,0 +1,17 @@ +include ../../Makefile.common + +TEST_DIR=$(BASE_DIR)/../tests +LIBS_DIR=$(BASE_DIR) + +all: comprehensive_tests + +.PHONY: clean base + +base: base.ci + $(CHARMC) -E base.ci + +comprehensive_tests: comprehensive.cpp base + $(CHARMC) $< -L$(LIBS_DIR)/charmtyles -lcharmtyles -I$(BASE_DIR) -I$(BASE_DIR)/charmtyles/backend -o $@.out $(OPTS) + +clean: + rm *.decl.h *.def.h *.out charmrun 2>/dev/null || true diff --git a/tests/comprehensive/base.ci b/tests/comprehensive/base.ci new file mode 100644 index 0000000..8fc43a7 --- /dev/null +++ b/tests/comprehensive/base.ci @@ -0,0 +1,10 @@ +mainmodule base +{ + extern module libcharmtyles; + + mainchare Main + { + entry Main(CkArgMsg*); + entry [threaded] void run(); + }; +} diff --git a/tests/comprehensive/comprehensive.cpp b/tests/comprehensive/comprehensive.cpp new file mode 100644 index 0000000..8bdf8ba --- /dev/null +++ b/tests/comprehensive/comprehensive.cpp @@ -0,0 +1,240 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include "base.decl.h" + +namespace { + +constexpr double kTolerance = 1e-10; + +void fail(const std::string& test_name, const std::string& reason) +{ + ckout << "[FAIL] " << test_name.c_str() << ": " << reason.c_str() << endl; + CkAbort("Comprehensive test suite failure"); +} + +void assert_vector_equals(const std::vector& actual, + const std::vector& expected, const std::string& test_name) +{ + if (actual.size() != expected.size()) + { + fail(test_name, + "Size mismatch. Expected " + std::to_string(expected.size()) + + " got " + std::to_string(actual.size())); + } + + for (std::size_t i = 0; i < actual.size(); ++i) + { + if (std::abs(actual[i] - expected[i]) > kTolerance) + { + fail(test_name, + "Value mismatch at index " + std::to_string(i) + ". Expected " + + std::to_string(expected[i]) + " got " + + std::to_string(actual[i])); + } + } + + ckout << "[PASS] " << test_name.c_str() << endl; +} + +void assert_matrix_equals(const std::vector>& actual, + const std::vector>& expected, + const std::string& test_name) +{ + if (actual.size() != expected.size()) + { + fail(test_name, + "Row mismatch. Expected " + std::to_string(expected.size()) + + " got " + std::to_string(actual.size())); + } + + for (std::size_t row = 0; row < actual.size(); ++row) + { + if (actual[row].size() != expected[row].size()) + { + fail(test_name, + "Column mismatch in row " + std::to_string(row) + ". Expected " + + std::to_string(expected[row].size()) + " got " + + std::to_string(actual[row].size())); + } + + for (std::size_t col = 0; col < actual[row].size(); ++col) + { + if (std::abs(actual[row][col] - expected[row][col]) > kTolerance) + { + fail(test_name, + "Value mismatch at (" + std::to_string(row) + ", " + + std::to_string(col) + "). Expected " + + std::to_string(expected[row][col]) + " got " + + std::to_string(actual[row][col])); + } + } + } + + ckout << "[PASS] " << test_name.c_str() << endl; +} + +} // namespace + +class Main : public CBase_Main +{ +public: + explicit Main(CkArgMsg* msg) + { + int num_pes = 4; + if (msg->argc > 1) + num_pes = atoi(msg->argv[1]); + + ckout << "[INFO] Initializing Charmtyles comprehensive test suite on " + << num_pes << " PEs" << endl; + ct::init(); + thisProxy.run(); + } + + void run() + { + test_vector_addition(); + test_vector_division(); + test_matrix_addition(); + test_matrix_division(); + test_vector_vector_dot(); + test_matrix_vector_dot(); + + ckout << "[SUCCESS] Comprehensive Charmtyles tests passed" << endl; + CkExit(); + } + +private: + static std::vector fill_vector(double value, std::size_t size) + { + return std::vector(size, value); + } + + static std::vector> fill_matrix( + double value, std::size_t rows, std::size_t cols) + { + return std::vector>( + rows, std::vector(cols, value)); + } + + void test_vector_addition() + { + constexpr std::size_t size = 8; + const std::string test_name = "Vector addition"; + + ct::vector lhs{size, 1.25}; + ct::vector rhs{size, 2.75}; + ct::vector result = lhs + rhs; + ct::sync(); + + assert_vector_equals( + result.get(), fill_vector(4.0, size), test_name); + } + + void test_vector_division() + { + constexpr std::size_t size = 6; + const std::string test_name = "Vector division"; + + ct::vector lhs{size, 6.0}; + ct::vector rhs{size, -2.0}; + ct::vector result = lhs / rhs; + ct::sync(); + + assert_vector_equals( + result.get(), fill_vector(-3.0, size), test_name); + } + + void test_matrix_addition() + { + constexpr std::size_t rows = 4; + constexpr std::size_t cols = 5; + const std::string test_name = "Matrix addition"; + + ct::matrix lhs{rows, cols, 1.0}; + ct::matrix rhs{rows, cols, 2.0}; + ct::matrix result = lhs + rhs; + ct::sync(); + + assert_matrix_equals( + result.get(), fill_matrix(3.0, rows, cols), test_name); + } + + void test_matrix_division() + { + const std::string test_name = "Matrix division"; + + constexpr std::size_t rows = 3; + constexpr std::size_t cols = 2; + + ct::matrix lhs{rows, cols, 12.0}; + ct::matrix rhs{rows, cols, -4.0}; + ct::matrix result = lhs / rhs; + ct::sync(); + + assert_matrix_equals( + result.get(), fill_matrix(-3.0, rows, cols), test_name); + } + + void test_vector_vector_dot() + { + const std::string test_name = "Vector dot product"; + + const std::vector lhs_vals{1.0, 2.0, 3.0, 4.0}; + const std::vector rhs_vals{5.0, 6.0, 7.0, 8.0}; + + ct::vector lhs = ct::from_vector(lhs_vals); + ct::vector rhs = ct::from_vector(rhs_vals); + ct::scalar result = ct::dot(lhs, rhs); + ct::sync(); + + const double expected = + std::inner_product(lhs_vals.begin(), lhs_vals.end(), + rhs_vals.begin(), 0.0); + + double actual = result.get(); + if (std::abs(actual - expected) > kTolerance) + { + fail(test_name, + "Value mismatch. Expected " + std::to_string(expected) + + " got " + std::to_string(actual)); + } + + ckout << "[PASS] " << test_name.c_str() << endl; + } + + void test_matrix_vector_dot() + { + const std::string test_name = "Matrix-vector dot product"; + + const std::vector> mat_vals{ + {2.0, 0.0, 1.0}, + {-1.0, 3.0, 2.0}, + {4.0, -2.0, 0.5}}; + const std::vector vec_vals{4.0, -2.0, 1.0}; + + ct::matrix mat = ct::from_matrix(mat_vals); + ct::vector vec = ct::from_vector(vec_vals); + + ct::vector result = ct::dot(mat, vec); + ct::sync(); + + std::vector expected; + expected.reserve(mat_vals.size()); + for (const auto& row : mat_vals) + { + expected.push_back(std::inner_product( + row.begin(), row.end(), vec_vals.begin(), 0.0)); + } + + assert_vector_equals(result.get(), expected, test_name); + } +}; + +#include "base.def.h" diff --git a/tests/matrix/.gitignore b/tests/matrix/.gitignore new file mode 100644 index 0000000..c795b05 --- /dev/null +++ b/tests/matrix/.gitignore @@ -0,0 +1 @@ +build \ No newline at end of file diff --git a/tests/matrix/CMakeLists.txt b/tests/matrix/CMakeLists.txt new file mode 100644 index 0000000..86a4b9b --- /dev/null +++ b/tests/matrix/CMakeLists.txt @@ -0,0 +1,51 @@ +cmake_minimum_required(VERSION 3.16) +project(charmTyles) + +include(${CMAKE_SOURCE_DIR}/../../config.cmake) + +set(Kokkos_ROOT ${KOKKOS_DIR}) +find_package(Kokkos 4.5 REQUIRED CONFIG) + +if(Charm_ENABLE_GPU) + message(STATUS "Building for a GPU backend") + add_definitions(-DGPU_BACKEND) + add_definitions(-DCUDA_DIR=\"${CUDA_DIR}\") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GPU_OPTS} ${LD_OPTS}") +else() + message(STATUS "Building for a CPU backend") + set(CMAKE_CXX_COMPILER "${CHARMC}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CPU_OPTS} ${LD_OPTS}") +endif() + +add_definitions(-DKOKKOS_DIR=\"${KOKKOS_DIR}\") + +add_custom_command( + OUTPUT ${BASE_DIR}/charmtyles/backend/libcharmtyles.decl.h + COMMAND ${CMAKE_COMMAND} -E chdir ${BASE_DIR}/charmtyles/backend + ${CHARMC} ${BASE_DIR}/charmtyles/backend/charmtyles.ci + DEPENDS ${BASE_DIR}/charmtyles/backend/charmtyles.ci + COMMENT "Processing charmtyles ci files" +) + +add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/base.decl.h + COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_SOURCE_DIR} + ${CHARMC} ${CMAKE_SOURCE_DIR}/base.ci + DEPENDS ${CMAKE_SOURCE_DIR}/base.ci + COMMENT "Processing base ci files" +) + +if(Charm_ENABLE_GPU) + add_library(matrix OBJECT matrix.cpp ${BASE_DIR}/charmtyles/backend/libcharmtyles.decl.h ${CMAKE_SOURCE_DIR}/base.decl.h) + target_include_directories(matrix PRIVATE ${BASE_DIR} ${BASE_DIR}/charmtyles/backend ${EIGEN_DIR}/include ${CHARM_DIR}/include) + target_link_libraries(matrix Kokkos::kokkos) + + add_custom_command(result ALL + COMMAND ${CHARMC} ${GPU_LINK_OPTS} $:matrix> -o ${CMAKE_BINARY_DIR}/matrix.out + DEPENDS matrix + COMMENT "Linking charm build against kokkos and cuda") +else() + add_executable(matrix.out matrix.cpp ${BASE_DIR}/charmtyles/backend/libcharmtyles.decl.h ${CMAKE_SOURCE_DIR}/base.decl.h) + target_include_directories(matrix.out PRIVATE ${BASE_DIR} ${BASE_DIR}/charmtyles/backend ${EIGEN_DIR}) + target_link_libraries(matrix.out Kokkos::kokkos) +endif() diff --git a/tests/matrix/matrix.cpp b/tests/matrix/matrix.cpp index 9d514e0..0d04005 100644 --- a/tests/matrix/matrix.cpp +++ b/tests/matrix/matrix.cpp @@ -26,105 +26,209 @@ class Main : public CBase_Main constexpr std::size_t mat_row_3 = 1 << 11; constexpr std::size_t mat_col_3 = 1 << 12; + auto verify_mat = [&](const std::vector>& mdata, + std::size_t rows, std::size_t cols, + double expected, const char* name) { + const double eps = 1e-12; // tolerance for floating comparisons + if (mdata.size() != rows) { + ckout << "Verification failed for " << name << ": row count " + << mdata.size() << " != " << rows << endl; + CkAbort("Test failed"); + } + for (std::size_t i = 0; i < rows; ++i) { + if (mdata[i].size() != cols) { + ckout << "Verification failed for " << name << ": row " << i + << " col count " << mdata[i].size() << " != " << cols << endl; + CkAbort("Test failed"); + } + for (std::size_t j = 0; j < cols; ++j) { + if (std::abs(mdata[i][j] - expected) > eps) { + ckout << "Verification failed for " << name << " at (" + << i << "," << j << "): expected " << expected + << " got " << mdata[i][j] << endl; + CkAbort("Test failed"); + } + } + } + }; + double start = CkWallTimer(); - ct::matrix mat1{mat_row_1, mat_col_1}; + ct::matrix mat1{mat_row_1, mat_col_1, 1}; ct::matrix mat2{mat_row_1, mat_col_1, 1.5}; ct::matrix mat3{mat_row_1, mat_col_1, .5}; - ct::matrix mat4 = mat1 + mat2 - mat3; + ct::matrix mat4 = mat1 + mat2 - mat3; // should be 2.0 - ct::matrix mat11{mat_row_2, mat_col_2}; + ct::matrix mat11{mat_row_2, mat_col_2, 1}; ct::matrix mat12{mat_row_2, mat_col_2, 1.5}; ct::matrix mat13{mat_row_2, mat_col_2, .5}; - ct::matrix mat14 = mat11 + mat12 - mat13; + ct::matrix mat14 = mat11 + mat12 - mat13; // should be 2.0 - ct::matrix mat111{mat_row_3, mat_col_3}; + ct::matrix mat111{mat_row_3, mat_col_3, 1}; ct::matrix mat112{mat_row_3, mat_col_3, 1.5}; ct::matrix mat113{mat_row_3, mat_col_3, .5}; - ct::matrix mat114 = mat111 + mat112 - mat113; - // ct::mat_impl::mat_instr_queue_t& queue = - // CT_ACCESS_SINGLETON(ct::mat_impl::mat_instr_queue); - // queue.print_instructions(); + ct::matrix mat114 = mat111 + mat112 - mat113; // should be 2.0 ct::sync(); double end = CkWallTimer(); - ckout << "Execution Time (Phase 1): " << end - start << endl; + ckout << "Running Correctness checks for (Phase 1)" << endl; + + // --- Verification after Phase 1 --- + { + auto mat1_data = mat1.get(); + auto mat2_data = mat2.get(); + auto mat3_data = mat3.get(); + auto mat4_data = mat4.get(); + + auto mat11_data = mat11.get(); + auto mat12_data = mat12.get(); + auto mat13_data = mat13.get(); + auto mat14_data = mat14.get(); + + auto mat111_data = mat111.get(); + auto mat112_data = mat112.get(); + auto mat113_data = mat113.get(); + auto mat114_data = mat114.get(); + + // Verify values for Phase 1 matrices + verify_mat(mat1_data, mat_row_1, mat_col_1, 1.0, "mat1"); + verify_mat(mat2_data, mat_row_1, mat_col_1, 1.5, "mat2"); + verify_mat(mat3_data, mat_row_1, mat_col_1, 0.5, "mat3"); + verify_mat(mat4_data, mat_row_1, mat_col_1, 2.0, "mat4"); // 1 + 1.5 - 0.5 + + verify_mat(mat11_data, mat_row_2, mat_col_2, 1.0, "mat11"); + verify_mat(mat12_data, mat_row_2, mat_col_2, 1.5, "mat12"); + verify_mat(mat13_data, mat_row_2, mat_col_2, 0.5, "mat13"); + verify_mat(mat14_data, mat_row_2, mat_col_2, 2.0, "mat14"); // 1 + 1.5 - 0.5 + + verify_mat(mat111_data, mat_row_3, mat_col_3, 1.0, "mat111"); + verify_mat(mat112_data, mat_row_3, mat_col_3, 1.5, "mat112"); + verify_mat(mat113_data, mat_row_3, mat_col_3, 0.5, "mat113"); + verify_mat(mat114_data, mat_row_3, mat_col_3, 2.0, "mat114"); // 1 + 1.5 - 0.5 + } + + ckout << "[SUCCESS] Correctness checks passed for (Phase 1)" << endl; start = CkWallTimer(); - mat4 = mat1 - mat3 + mat4; - mat14 = mat11 - mat13 + mat14; - mat114 = mat111 - mat113 + mat114; + mat4 = mat1 - mat3 + mat4; // 1 - 0.5 + 2.0 = 2.5 + mat14 = mat11 - mat13 + mat14; // 2.5 + mat114 = mat111 - mat113 + mat114; // 2.5 // in-place operation - ct::matrix mat115 = mat112 -= mat113; - mat115 += mat111 += mat112; + ct::matrix mat115 = mat112 -= mat113; // mat112: 1.5 - 0.5 = 1.0, mat115 = 1.0 + mat115 += mat111 += mat112; // mat111: 1.0 + 1.0 = 2.0, mat115: 1.0 + 2.0 = 3.0 ct::sync(); - end = CkWallTimer(); + end = CkWallTimer(); ckout << "Execution Time (Phase 2): " << end - start << endl; + ckout << "Running Correctness checks for (Phase 2)" << endl; - // copy operator - mat4 = mat1; - // copy constructor - ct::matrix mat5 = mat4; + // --- Verification after Phase 2 --- + { + auto mat4_data = mat4.get(); + auto mat14_data = mat14.get(); + auto mat114_data = mat114.get(); - ct::sync(); + auto mat111_data = mat111.get(); + auto mat112_data = mat112.get(); + auto mat113_data = mat113.get(); + auto mat115_data = mat115.get(); + + // mat4/mat14/mat114 expected 2.5 after mat - mat + prev + verify_mat(mat4_data, mat_row_1, mat_col_1, 2.5, "mat4"); + verify_mat(mat14_data, mat_row_2, mat_col_2, 2.5, "mat14"); + verify_mat(mat114_data, mat_row_3, mat_col_3, 2.5, "mat114"); + + // In-place results + verify_mat(mat112_data, mat_row_3, mat_col_3, 1.0, "mat112"); // became 1.0 + verify_mat(mat111_data, mat_row_3, mat_col_3, 2.0, "mat111"); // became 2.0 after += + verify_mat(mat113_data, mat_row_3, mat_col_3, 0.5, "mat113"); // unchanged + verify_mat(mat115_data, mat_row_3, mat_col_3, 3.0, "mat115"); // final value + } + + ckout << "[SUCCESS] Correctness checks passed for (Phase 2)" << endl; start = CkWallTimer(); - ct::matrix x{1 << 13, 1 << 13, 1.0}; - ct::vector y{1 << 13, 2.0}; - ct::vector x_dot_y = ct::dot(x, y); + // copy operator + mat4 = mat1; // mat4 -> 1.0 + // copy constructor + ct::matrix mat5 = mat4; // mat5 -> 1.0 + ct::sync(); end = CkWallTimer(); + ckout << "Execution Time (Phase 3): " << end - start << endl; - ckout << "Execution Time (mat-vec dot product): " << end - start - << endl; + ckout << "Running Correctness checks for (Phase 3)" << endl; - start = CkWallTimer(); + // --- Verification after Phase 3 --- + { + auto mat4_data = mat4.get(); + auto mat5_data = mat5.get(); + // mat4 and mat5 must equal mat1 (1.0) + verify_mat(mat4_data, mat_row_1, mat_col_1, 1.0, "mat4 (after copy)"); + verify_mat(mat5_data, mat_row_1, mat_col_1, 1.0, "mat5 (copy constructor)"); + } - ct::scalar scal1 = ct::dot(x_dot_y, x_dot_y); - double underlying_val = scal1.get(); - ckout << "[Result] Dot-product over resultant vector: " - << underlying_val << endl; + ckout << "[SUCCESS] Correctness checks passed for (Phase 3)" << endl; - Eigen::MatrixXd eX = Eigen::MatrixXd::Constant(1 << 11, 1 << 12, 1.); - Eigen::VectorXd ey = Eigen::VectorXd::Constant(1 << 12, 2.); - Eigen::VectorXd ex_y = eX * ey; + // start = CkWallTimer(); - double eres = ex_y.dot(ex_y); - ckout << "[Result: Eigen] Dot-product over resultant vector: " << eres - << endl; + // ct::matrix x{1 << 13, 1 << 13, 1.0}; + // ct::vector y{1 << 13, 2.0}; + // ct::vector x_dot_y = ct::dot(x, y); + // ct::sync(); - end = CkWallTimer(); - ckout << "Execution Time (vec-vec dot product): " << end - start - << endl; + // end = CkWallTimer(); - ckout << "[Result] MatMul over 2 matrices: " << eres << endl; - start = CkWallTimer(); + // ckout << "Execution Time (mat-vec dot product): " << end - start + // << endl; - ct::matrix m1{1 << 10, 1 << 10, 0}; - ct::matrix m2{1 << 10, 1 << 10, 0}; - ct::matrix m3 = m1 * m2; - ct::sync(m1.matrix_shape()); + // start = CkWallTimer(); - end = CkWallTimer(); - ckout << "Execution Time (mat-mul): " << end - start << endl; + // ct::scalar scal1 = ct::dot(x_dot_y, x_dot_y); + // double underlying_val = scal1.get(); + // ckout << "[Result] Dot-product over resultant vector: " + // << underlying_val << endl; + + // Eigen::MatrixXd eX = Eigen::MatrixXd::Constant(1 << 11, 1 << 12, 1.); + // Eigen::VectorXd ey = Eigen::VectorXd::Constant(1 << 12, 2.); + // Eigen::VectorXd ex_y = eX * ey; + + // double eres = ex_y.dot(ex_y); + // ckout << "[Result: Eigen] Dot-product over resultant vector: " << eres + // << endl; + + // end = CkWallTimer(); + // ckout << "Execution Time (vec-vec dot product): " << end - start + // << endl; + + // ckout << "[Result] MatMul over 2 matrices: " << eres << endl; + // start = CkWallTimer(); + + // ct::matrix m1{1 << 10, 1 << 10, 0}; + // ct::matrix m2{1 << 10, 1 << 10, 0}; + // ct::matrix m3 = m1 * m2; + // ct::sync(m1.matrix_shape()); + + // end = CkWallTimer(); + // ckout << "Execution Time (mat-mul): " << end - start << endl; - ct::vector v1{1 << 10, 0}; - ct::vector vres = ct::dot(m3, v1); - ct::scalar sval = ct::dot(vres, vres); - double uval = sval.get(); + // ct::vector v1{1 << 10, 0}; + // ct::vector vres = ct::dot(m3, v1); + // ct::scalar sval = ct::dot(vres, vres); + // double uval = sval.get(); - ckout << "[Result] Mat-mul sum: " << uval << endl; + // ckout << "[Result] Mat-mul sum: " << uval << endl; + ct::finalize(); CkExit(); } }; diff --git a/tests/performance/logistic.cpp b/tests/performance/logistic.cpp index 6602af0..f6b5d81 100644 --- a/tests/performance/logistic.cpp +++ b/tests/performance/logistic.cpp @@ -55,6 +55,7 @@ class logistic_regression ct::vector error = y_train - predictions; ct::vector gradient = ct::dot(X_train, error); + // TODO: fix with the changed axpy api? weight_vector_ = ct::axpy(learning_rate_, gradient, weight_vector_); for (std::size_t iters = 1; iters != iterations_; ++iters) diff --git a/tests/vector/.gitignore b/tests/vector/.gitignore new file mode 100644 index 0000000..c795b05 --- /dev/null +++ b/tests/vector/.gitignore @@ -0,0 +1 @@ +build \ No newline at end of file diff --git a/tests/vector/CMakeLists.txt b/tests/vector/CMakeLists.txt new file mode 100644 index 0000000..6976885 --- /dev/null +++ b/tests/vector/CMakeLists.txt @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 3.16) +project(charmTyles) + +include(${CMAKE_SOURCE_DIR}/../../config.cmake) + +set(Kokkos_ROOT ${KOKKOS_DIR}) +find_package(Kokkos 4.5 REQUIRED CONFIG) + +set(KokkosKernels_DIR ${KOKKOS_KERNELS_DIR}/lib/cmake/KokkosKernels) +find_package(KokkosKernels REQUIRED) + +if(Charm_ENABLE_GPU) + message(STATUS "Building for a GPU backend") + add_definitions(-DGPU_BACKEND) + add_definitions(-DCUDA_DIR=\"${CUDA_DIR}\") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GPU_OPTS} ${LD_OPTS}") +else() + message(STATUS "Building for a CPU backend") + set(CMAKE_CXX_COMPILER "${CHARMC}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CPU_OPTS} ${LD_OPTS}") +endif() + +add_definitions(-DKOKKOS_DIR=\"${KOKKOS_DIR}\") + +add_custom_command( + OUTPUT ${BASE_DIR}/charmtyles/backend/libcharmtyles.decl.h + COMMAND ${CMAKE_COMMAND} -E chdir ${BASE_DIR}/charmtyles/backend + ${CHARMC} ${BASE_DIR}/charmtyles/backend/charmtyles.ci + DEPENDS ${BASE_DIR}/charmtyles/backend/charmtyles.ci + COMMENT "Processing charmtyles ci files" +) + +add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/base.decl.h + COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_SOURCE_DIR} + ${CHARMC} ${CMAKE_SOURCE_DIR}/base.ci + DEPENDS ${CMAKE_SOURCE_DIR}/base.ci + COMMENT "Processing base ci files" +) + +if(Charm_ENABLE_GPU) + add_library(vector OBJECT vector.cpp ${BASE_DIR}/charmtyles/backend/libcharmtyles.decl.h ${CMAKE_SOURCE_DIR}/base.decl.h) + target_include_directories(vector PRIVATE ${BASE_DIR} ${BASE_DIR}/charmtyles/backend ${EIGEN_DIR}/include ${CHARM_DIR}/include) + target_link_libraries(vector Kokkos::kokkos Kokkos::kokkoskernels) + + add_custom_command( + OUTPUT "${CMAKE_BINARY_DIR}/vector.out" + COMMAND ${CHARMC} ${GPU_LINK_OPTS} $ -o ${CMAKE_BINARY_DIR}/vector.out + DEPENDS vector + COMMENT "Linking charm build against kokkos and cuda" + ) + + add_custom_target(result ALL + DEPENDS "${CMAKE_BINARY_DIR}/vector.out" + ) +else() + add_executable(vector.out vector.cpp ${BASE_DIR}/charmtyles/backend/libcharmtyles.decl.h ${CMAKE_SOURCE_DIR}/base.decl.h) + target_include_directories(vector.out PRIVATE ${BASE_DIR} ${BASE_DIR}/charmtyles/backend ${EIGEN_DIR}) + target_link_libraries(vector.out Kokkos::kokkos Kokkos::kokkoskernels) +endif() diff --git a/tests/vector/Makefile b/tests/vector/Makefile index 13a1e67..e2f20f1 100644 --- a/tests/vector/Makefile +++ b/tests/vector/Makefile @@ -11,7 +11,7 @@ base: base.ci $(CHARMC) -E base.ci vector: vector.cpp base - $(CHARMC) $< -L$(LIBS_DIR)/charmtyles -lcharmtyles -I$(BASE_DIR) -I$(BASE_DIR)/charmtyles/backend -o $@.out $(OPTS) + $(CHARMC) $< -I$(BASE_DIR) -I$(BASE_DIR)/charmtyles/backend -o $@.out $(OPTS) clean: rm *.decl.h *.def.h *.out charmrun diff --git a/tests/vector/vector.cpp b/tests/vector/vector.cpp index 1221026..86e80a9 100644 --- a/tests/vector/vector.cpp +++ b/tests/vector/vector.cpp @@ -18,80 +18,243 @@ class Main : public CBase_Main void benchmark() { - constexpr std::size_t vec_size_1 = 1 << 20; - constexpr std::size_t vec_size_2 = 1 << 26; - constexpr std::size_t vec_size_3 = 1 << 22; - - double start = CkWallTimer(); - - ct::vector vec1{vec_size_1}; + constexpr std::size_t vec_size_1 = 1 << 24; + constexpr std::size_t vec_size_2 = 1 << 24; + constexpr std::size_t vec_size_3 = 1 << 24; + ct::vector vec1{vec_size_1, .5}; ct::vector vec2{vec_size_1, 1.5}; ct::vector vec3{vec_size_1, .5}; - - ct::vector vec4 = vec1 + vec2 - vec3; - - ct::vector vec11{vec_size_2}; + ct::vector vec11{vec_size_2, 0.0}; ct::vector vec12{vec_size_2, 1.5}; ct::vector vec13{vec_size_2, .5}; - - ct::vector vec14 = vec11 + vec12 - vec13; - - ct::vector vec111{vec_size_3}; + ct::vector vec111{vec_size_3, 0.0}; ct::vector vec112{vec_size_3, 1.5}; ct::vector vec113{vec_size_3, .5}; + ct::vector vec4 = vec1 + vec2; + ct::vector vec14 = vec11 + vec12 - vec13; ct::vector vec114 = vec111 + vec112 - vec113; - - // ct::vec_impl::vec_instr_queue_t& queue = - // CT_ACCESS_SINGLETON(ct::vec_impl::vec_instr_queue); - // queue.print_instructions(); - ct::sync(); + double start = CkWallTimer(); + for (int i = 0; i < 100; i++) + { + vec4 = vec1 + vec2; + vec14 = vec11 + vec12 - vec13; + vec114 = vec111 + vec112 - vec113; + } + ct::sync(); double end = CkWallTimer(); ckout << "Execution Time (Phase 1): " << end - start << endl; - start = CkWallTimer(); - vec4 = vec1 - vec3 + vec4; - vec14 = vec11 - vec13 + vec14; - vec114 = vec111 - vec113 + vec114; + ckout << "Running correctness checks for phase 1" << endl; + // Retrieve values for all vectors once + auto vec1_data = vec1.get(); + auto vec2_data = vec2.get(); + auto vec3_data = vec3.get(); + auto vec4_data = vec4.get(); - // in-place operation - ct::vector vec115 = vec112 -= vec113; - vec115 += vec111 += vec112; + auto vec11_data = vec11.get(); + auto vec12_data = vec12.get(); + auto vec13_data = vec13.get(); + auto vec14_data = vec14.get(); - ct::sync(); - end = CkWallTimer(); + auto vec111_data = vec111.get(); + auto vec112_data = vec112.get(); + auto vec113_data = vec113.get(); + auto vec114_data = vec114.get(); - ckout << "Execution Time (Phase 2): " << end - start << endl; + // Verify values for all vectors + if (!(vec1_data.size() == vec_size_1 && + std::all_of(vec1_data.begin(), vec1_data.end(), + [](double v) { return v == 0.5; }))) + { + ckout << "Verification failed for vec1_data" << endl; + CkAbort("Test failed"); + } + if (!(vec2_data.size() == vec_size_1 && + std::all_of(vec2_data.begin(), vec2_data.end(), + [](double v) { return v == 1.5; }))) + { + ckout << "Verification failed for vec2_data" << endl; + CkAbort("Test failed"); + } + if (!(vec3_data.size() == vec_size_1 && + std::all_of(vec3_data.begin(), vec3_data.end(), + [](double v) { return v == 0.5; }))) + { + ckout << "Verification failed for vec3_data" << endl; + CkAbort("Test failed"); + } + if (!(vec4_data.size() == vec_size_1 && + std::all_of(vec4_data.begin(), vec4_data.end(), + [](double v) { return v == 2.0; }))) + { + ckout << "Verification failed for vec4_data" << endl; + CkAbort("Test failed"); + } - // copy operator - vec4 = vec1; - // copy constructor - ct::vector vec5 = vec4; + if (!(vec11_data.size() == vec_size_2 && + std::all_of(vec11_data.begin(), vec11_data.end(), + [](double v) { return v == 0.0; }))) + { + ckout << "Verification failed for vec11_data" << endl; + CkAbort("Test failed"); + } + if (!(vec12_data.size() == vec_size_2 && + std::all_of(vec12_data.begin(), vec12_data.end(), + [](double v) { return v == 1.5; }))) + { + ckout << "Verification failed for vec12_data" << endl; + CkAbort("Test failed"); + } + if (!(vec13_data.size() == vec_size_2 && + std::all_of(vec13_data.begin(), vec13_data.end(), + [](double v) { return v == 0.5; }))) + { + ckout << "Verification failed for vec13_data" << endl; + CkAbort("Test failed"); + } + if (!(vec14_data.size() == vec_size_2 && + std::all_of(vec14_data.begin(), vec14_data.end(), + [](double v) { return v == 1.0; }))) + { + ckout << "Verification failed for vec14_data" << endl; + CkAbort("Test failed"); + } - ct::sync(); + if (!(vec111_data.size() == vec_size_3 && + std::all_of(vec111_data.begin(), vec111_data.end(), + [](double v) { return v == 0.0; }))) + { + ckout << "Verification failed for vec111_data" << endl; + CkAbort("Test failed"); + } + if (!(vec112_data.size() == vec_size_3 && + std::all_of(vec112_data.begin(), vec112_data.end(), + [](double v) { return v == 1.5; }))) + { + ckout << "Verification failed for vec112_data" << endl; + CkAbort("Test failed"); + } + if (!(vec113_data.size() == vec_size_3 && + std::all_of(vec113_data.begin(), vec113_data.end(), + [](double v) { return v == 0.5; }))) + { + ckout << "Verification failed for vec113_data" << endl; + CkAbort("Test failed"); + } + if (!(vec114_data.size() == vec_size_3 && + std::all_of(vec114_data.begin(), vec114_data.end(), + [](double v) { return v == 1.0; }))) + { + ckout << "Verification failed for vec114_data" << endl; + CkAbort("Test failed"); + } - ct::vector x{1 << 21, 1.0}; - ct::vector y{1 << 21, 2.0}; - ct::scalar scal1 = ct::dot(x, y); - double underlying_val = scal1.get(); + ckout << "[SUCCESS] All Phase 1 Tests passed" << endl; - ckout << "Result of Vector dot product: " << underlying_val << endl; + // ct::scalar halo{42.0}; + // ct::scalar illo{27.0}; + // ct::scalar reso = halo + illo; + // ct::sync(); + // double reso_h = reso.get(); + // ckout << "RESO> " << reso_h << endl; - // Test our new from_vector functionality - std::vector test_data = {1.1, 2.2, 3.3, 4.4, 5.5}; - ct::vector custom_vec = ct::from_vector(test_data); - ct::sync(); - - std::vector result = custom_vec.get(); - ckout << "Custom vector elements: "; - for (const auto& val : result) { - ckout << val << " "; - } - ckout << endl; + // start = CkWallTimer(); + // vec4 = vec1 - vec3 + vec4; + // vec14 = vec11 - vec13 + vec14; + // vec114 = vec111 - vec113 + vec114; + + // // in-place operation + // ct::vector vec115 = vec112 -= vec113; + // vec115 += vec111 += vec112; + + // ct::sync(); + // end = CkWallTimer(); + + // ckout << "Execution Time (Phase 2): " << end - start << endl; + + // ckout << "Running correctness checks for phase 2" << endl; + + // // Retrieve values after operations + // vec4_data = vec4.get(); + // vec14_data = vec14.get(); + // vec114_data = vec114.get(); + // auto vec115_data = vec115.get(); + + // // Verify values after operations + // if (!(vec4_data.size() == vec_size_1 && std::all_of(vec4_data.begin(), vec4_data.end(), [](double v) { return v == 2.0; }))) { + // ckout << "Verification failed for vec4_data after operations" << endl; + // CkAbort("Test failed"); + // } + // if (!(vec14_data.size() == vec_size_2 && std::all_of(vec14_data.begin(), vec14_data.end(), [](double v) { return v == 0.5; }))) { + // ckout << "Verification failed for vec14_data after operations" << endl; + // CkAbort("Test failed"); + // } + // if (!(vec114_data.size() == vec_size_3 && std::all_of(vec114_data.begin(), vec114_data.end(), [](double v) { return v == 0.5; }))) { + // ckout << "Verification failed for vec114_data after operations" << endl; + // CkAbort("Test failed"); + // } + // if (!(vec115_data.size() == vec_size_3 && std::all_of(vec115_data.begin(), vec115_data.end(), [](double v) { return v == 2.0; }))) { + // ckout << "Verification failed for vec115_data after operations" << endl; + // CkAbort("Test failed"); + // } + + // ckout << "[SUCCESS] All Phase 2 Tests passed" << endl; + + // start = CkWallTimer(); + + // // copy operator + // vec4 = vec1; + // // copy constructor + // ct::vector vec5 = vec4; + + // ct::sync(); + + // end = CkWallTimer(); + + // ckout << "Execution Time (Phase 3): " << end - start << endl; + + // ckout << "Running correctness checks for phase 3" << endl; + + // // Retrieve copied values + // vec4_data = vec4.get(); + // auto vec5_data = vec5.get(); + + // // Verify copied values + // if (!(vec4_data.size() == vec_size_1 && std::all_of(vec4_data.begin(), vec4_data.end(), [](double v) { return v == 0.5; }))) { + // ckout << "Verification failed for vec4_data after copy" << endl; + // CkAbort("Test failed"); + // } + // if (!(vec5_data.size() == vec_size_1 && std::all_of(vec5_data.begin(), vec5_data.end(), [](double v) { return v == 0.5; }))) { + // ckout << "Verification failed for vec5_data after copy" << endl; + // CkAbort("Test failed"); + // } + + // ckout << "[SUCCESS] All Phase 3 Tests passed" << endl; + + // ct::vector x{1 << 21, 1.0}; + // ct::vector y{1 << 21, 2.0}; + // ct::scalar scal1 = ct::dot(x, y); + // double underlying_val = scal1.get(); + + // ckout << "Result of Vector dot product: " << underlying_val << endl; + + // // Test our new from_vector functionality + // std::vector test_data = {1.1, 2.2, 3.3, 4.4, 5.5}; + // ct::vector custom_vec = ct::from_vector(test_data); + // ct::sync(); + + // std::vector result = custom_vec.get(); + // ckout << "Custom vector elements: "; + // for (const auto& val : result) { + // ckout << val << " "; + // } + // ckout << endl; + ct::finalize(); CkExit(); } };