Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEA] Add support for bitmap_view & the API of bitmap_to_csr #2109

Merged
merged 30 commits into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
165b278
[FEA] Add support for bitmap_view & the API of `bitmap_to_csr`
rhdong Jan 21, 2024
62d9e34
Merge branch 'branch-24.02' into rhdong/bitmap
rhdong Jan 23, 2024
7dea38d
fix doc build CI error 35fe8a
rhdong Jan 23, 2024
1b6e784
Merge branch 'rhdong/bitmap' of https://github.com/rhdong/raft into r…
rhdong Jan 23, 2024
67f0650
try to fix the CI failure
rhdong Jan 24, 2024
1e5294c
Merge branch 'branch-24.02' into rhdong/bitmap
rhdong Jan 24, 2024
70cce47
Merge branch 'branch-24.04' into rhdong/bitmap
rhdong Jan 25, 2024
f8960d9
Merge branch 'branch-24.04' into rhdong/bitmap
rhdong Feb 23, 2024
20f76af
fix a ut& benchmark error
rhdong Feb 21, 2024
7dc7cf8
Improve performance & eliminate the temp buffer.
rhdong Feb 23, 2024
cab8691
fix : compatible with devices with compute capability < 8.0
rhdong Feb 24, 2024
3edeafd
Merge remote-tracking branch 'origin/branch-24.04' into rhdong/bitmap…
rhdong Mar 5, 2024
f015ed5
Optimize based on review comments
rhdong Mar 5, 2024
308eb8b
Ensure the `bitmap_t` to be {uint64_t, uint32_t}
rhdong Mar 5, 2024
0d5ec74
Merge remote-tracking branch 'origin/branch-24.04' into rhdong/bitmap…
rhdong Mar 6, 2024
5cf5a8b
Merge remote-tracking branch 'origin/branch-24.04' into rhdong/bitmap…
rhdong Mar 6, 2024
42d5355
Optimize based on review comments-3rd round
rhdong Mar 7, 2024
1aff844
[Fix] `std::vector` compilation error of in the `nvtx.hpp`
rhdong Mar 6, 2024
59533e0
Remove `#undef NDEBUG`
rhdong Mar 7, 2024
311f2d1
Merge branch 'branch-24.04' into rhdong/bitmap
rhdong Mar 7, 2024
7d960bd
Optimize based on review comments-4rd round
rhdong Mar 8, 2024
8a3b759
Merge branch 'branch-24.04' into rhdong/bitmap
rhdong Mar 11, 2024
7dea754
Merge branch 'branch-24.04' into rhdong/bitmap
rhdong Mar 11, 2024
08397c6
API changes to Owning/perserving
rhdong Mar 14, 2024
b2ad06e
d1
rhdong Mar 15, 2024
09e64ab
Add the UT cases for owning scenario
rhdong Mar 15, 2024
53202c6
Merge branch 'branch-24.04' into rhdong/bitmap
rhdong Mar 15, 2024
8838a36
fix benchmark compile error
rhdong Mar 16, 2024
1c91c74
Merge branch 'branch-24.04' into rhdong/bitmap
rhdong Mar 19, 2024
01dd903
Merge branch 'branch-24.04' into rhdong/bitmap
rhdong Mar 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion cpp/bench/prims/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,14 @@ if(BUILD_PRIMS_BENCH)
bench/prims/random/rng.cu bench/prims/main.cpp
)

ConfigureBench(NAME SPARSE_BENCH PATH bench/prims/sparse/convert_csr.cu bench/prims/main.cpp)
ConfigureBench(
NAME
SPARSE_BENCH
PATH
bench/prims/sparse/bitmap_to_csr.cu
bench/prims/sparse/convert_csr.cu
bench/prims/main.cpp
)

ConfigureBench(
NAME
Expand Down
156 changes: 156 additions & 0 deletions cpp/bench/prims/sparse/bitmap_to_csr.cu
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* Copyright (c) 2024, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <common/benchmark.hpp>

#include <raft/core/device_resources.hpp>
#include <raft/core/resource/cuda_stream.hpp>
#include <raft/core/resources.hpp>
#include <raft/sparse/convert/csr.cuh>
#include <raft/util/itertools.hpp>

#include <rmm/device_uvector.hpp>

#include <sstream>
#include <vector>

namespace raft::bench::sparse {

template <typename index_t>
struct bench_param {
index_t n_rows;
index_t n_cols;
float sparsity;
};

template <typename index_t>
inline auto operator<<(std::ostream& os, const bench_param<index_t>& params) -> std::ostream&
{
os << " rows*cols=" << params.n_rows << "*" << params.n_cols << "\tsparsity=" << params.sparsity;
return os;
}

template <typename bitmap_t, typename index_t, typename value_t = float>
struct BitmapToCsrBench : public fixture {
BitmapToCsrBench(const bench_param<index_t>& p)
: fixture(true),
params(p),
handle(stream),
bitmap_d(0, stream),
nnz(0),
indptr_d(0, stream),
indices_d(0, stream),
values_d(0, stream)
{
index_t element = raft::ceildiv(params.n_rows * params.n_cols, index_t(sizeof(bitmap_t) * 8));
std::vector<bitmap_t> bitmap_h(element);
nnz = create_sparse_matrix(params.n_rows, params.n_cols, params.sparsity, bitmap_h);

bitmap_d.resize(bitmap_h.size(), stream);
indptr_d.resize(params.n_rows + 1, stream);
indices_d.resize(nnz, stream);
values_d.resize(nnz, stream);

update_device(bitmap_d.data(), bitmap_h.data(), bitmap_h.size(), stream);

resource::sync_stream(handle);
}

index_t create_sparse_matrix(index_t m, index_t n, float sparsity, std::vector<bitmap_t>& bitmap)
{
index_t total = static_cast<index_t>(m * n);
index_t num_ones = static_cast<index_t>((total * 1.0f) * sparsity);
index_t res = num_ones;

for (auto& item : bitmap) {
item = static_cast<bitmap_t>(0);
}

std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<index_t> dis(0, total - 1);

while (num_ones > 0) {
index_t index = dis(gen);

bitmap_t& element = bitmap[index / (8 * sizeof(bitmap_t))];
index_t bit_position = index % (8 * sizeof(bitmap_t));

if (((element >> bit_position) & 1) == 0) {
element |= (static_cast<index_t>(1) << bit_position);
num_ones--;
}
}
return res;
}

void run_benchmark(::benchmark::State& state) override
{
std::ostringstream label_stream;
label_stream << params;
state.SetLabel(label_stream.str());

auto bitmap =
raft::core::bitmap_view<bitmap_t, index_t>(bitmap_d.data(), params.n_rows, params.n_cols);

auto csr_view = raft::make_device_compressed_structure_view<index_t, index_t, index_t>(
indptr_d.data(), indices_d.data(), params.n_rows, params.n_cols, nnz);
auto csr = raft::make_device_csr_matrix_view<value_t, index_t>(values_d.data(), csr_view);

raft::sparse::convert::bitmap_to_csr<bitmap_t, index_t>(handle, bitmap, csr);

resource::sync_stream(handle);
loop_on_state(state, [this, &bitmap, &csr]() {
raft::sparse::convert::bitmap_to_csr<bitmap_t, index_t>(handle, bitmap, csr);
});
}

protected:
const raft::device_resources handle;

bench_param<index_t> params;

rmm::device_uvector<bitmap_t> bitmap_d;
rmm::device_uvector<index_t> indptr_d;
rmm::device_uvector<index_t> indices_d;
rmm::device_uvector<value_t> values_d;

index_t nnz;
}; // struct BitmapToCsrBench

template <typename index_t>
const std::vector<bench_param<index_t>> getInputs()
{
std::vector<bench_param<index_t>> param_vec;
struct TestParams {
index_t m;
index_t n;
float sparsity;
};

const std::vector<TestParams> params_group = raft::util::itertools::product<TestParams>(
{index_t(10), index_t(1024)}, {index_t(1024 * 1024)}, {0.01f, 0.1f, 0.2f, 0.5f});

param_vec.reserve(params_group.size());
for (TestParams params : params_group) {
param_vec.push_back(bench_param<index_t>({params.m, params.n, params.sparsity}));
}
return param_vec;
}

RAFT_BENCH_REGISTER((BitmapToCsrBench<uint32_t, int, float>), "", getInputs<int>());
RAFT_BENCH_REGISTER((BitmapToCsrBench<uint64_t, int, double>), "", getInputs<int>());

} // namespace raft::bench::sparse
127 changes: 127 additions & 0 deletions cpp/include/raft/core/bitmap.cuh
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* Copyright (c) 2024, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <raft/core/bitset.cuh>
#include <raft/core/detail/mdspan_util.cuh>
#include <raft/core/device_container_policy.hpp>
#include <raft/core/device_mdarray.hpp>
#include <raft/core/resources.hpp>

namespace raft::core {
/**
* @defgroup bitmap Bitmap
* @{
*/
/**
* @brief View of a RAFT Bitmap.
*
* This lightweight structure which represents and manipulates a two-dimensional bitmap matrix view
* with row major order. This class provides functionality for handling a matrix where each element
* is represented as a bit in a bitmap.
*
* @tparam bitmap_t Underlying type of the bitmap array. Default is uint32_t.
* @tparam index_t Indexing type used. Default is uint32_t.
*/
template <typename bitmap_t = uint32_t, typename index_t = uint32_t>
struct bitmap_view : public bitset_view<bitmap_t, index_t> {
static_assert((std::is_same<bitmap_t, uint32_t>::value ||
std::is_same<bitmap_t, uint64_t>::value),
"The bitmap_t must be uint32_t or uint64_t.");
/**
* @brief Create a bitmap view from a device raw pointer.
*
* @param bitmap_ptr Device raw pointer
* @param rows Number of row in the matrix.
* @param cols Number of col in the matrix.
*/
_RAFT_HOST_DEVICE bitmap_view(bitmap_t* bitmap_ptr, index_t rows, index_t cols)
: bitset_view<bitmap_t, index_t>(bitmap_ptr, rows * cols), rows_(rows), cols_(cols)
{
}

/**
* @brief Create a bitmap view from a device vector view of the bitset.
*
* @param bitmap_span Device vector view of the bitmap
* @param rows Number of row in the matrix.
* @param cols Number of col in the matrix.
*/
_RAFT_HOST_DEVICE bitmap_view(raft::device_vector_view<bitmap_t, index_t> bitmap_span,
index_t rows,
index_t cols)
: bitset_view<bitmap_t, index_t>(bitmap_span, rows * cols), rows_(rows), cols_(cols)
{
}

private:
// Hide the constructors of bitset_view.
_RAFT_HOST_DEVICE bitmap_view(bitmap_t* bitmap_ptr, index_t bitmap_len)
: bitset_view<bitmap_t, index_t>(bitmap_ptr, bitmap_len)
{
}

_RAFT_HOST_DEVICE bitmap_view(raft::device_vector_view<bitmap_t, index_t> bitmap_span,
index_t bitmap_len)
: bitset_view<bitmap_t, index_t>(bitmap_span, bitmap_len)
{
}

public:
/**
* @brief Device function to test if a given row and col are set in the bitmap.
*
* @param row Row index of the bit to test
* @param col Col index of the bit to test
* @return bool True if index has not been unset in the bitset
*/
inline _RAFT_DEVICE auto test(const index_t row, const index_t col) const -> bool
{
return test(row * cols_ + col);
}

/**
* @brief Device function to set a given row and col to set_value in the bitset.
*
* @param row Row index of the bit to set
* @param col Col index of the bit to set
* @param new_value Value to set the bit to (true or false)
*/
inline _RAFT_DEVICE void set(const index_t row, const index_t col, bool new_value) const
{
set(row * cols_ + col, &new_value);
}

/**
* @brief Get the total number of rows
* @return index_t The total number of rows
*/
inline _RAFT_HOST_DEVICE index_t get_n_rows() const { return rows_; }

/**
* @brief Get the total number of columns
* @return index_t The total number of columns
*/
inline _RAFT_HOST_DEVICE index_t get_n_cols() const { return cols_; }

private:
index_t rows_;
index_t cols_;
};

/** @} */
} // end namespace raft::core
1 change: 1 addition & 0 deletions cpp/include/raft/core/detail/nvtx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <string>
#include <type_traits>
#include <unordered_map>
#include <vector>

namespace raft::common::nvtx::detail {

Expand Down
27 changes: 26 additions & 1 deletion cpp/include/raft/sparse/convert/csr.cuh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2023, NVIDIA CORPORATION.
* Copyright (c) 2019-2024, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,7 +18,10 @@

#pragma once

#include <raft/core/bitmap.cuh>
#include <raft/core/device_csr_matrix.hpp>
#include <raft/sparse/convert/detail/adj_to_csr.cuh>
#include <raft/sparse/convert/detail/bitmap_to_csr.cuh>
#include <raft/sparse/convert/detail/csr.cuh>
#include <raft/sparse/csr.hpp>

Expand Down Expand Up @@ -102,6 +105,28 @@ void adj_to_csr(raft::resources const& handle,
detail::adj_to_csr(handle, adj, row_ind, num_rows, num_cols, tmp, out_col_ind);
}

/**
* @brief Converts a bitmap matrix into unsorted CSR format matrix.
*
* @tparam bitmap_t Underlying type of the bitmap.
* @tparam index_t Indexing type used.
* @tparam csr_matrix_t Reference Type of CSR Matrix, raft::device_csr_matrix
*
* @param[in] handle RAFT handle
* @param[in] bitmap input raft::bitmap_view
Copy link
Member

Choose a reason for hiding this comment

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

In and out are already specified on the param so we shouldn't need to duplicate those in the description. Can you please expand the descriptions, though? Instead of just "handle" and "raft::bitmap_view", it would be helpful to explain their purpose.

Also, please don't include "reference type" in the description. The caller doesn't have to care that it's a reference type. That's automatic when they pass in the argument.

Copy link
Member

@cjnolet cjnolet Mar 14, 2024

Choose a reason for hiding this comment

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

I think we should still be accepting device_structure_owning_csr_matrix here unless we intend to explicitly support both. If a user passes in a structure-preserving csr matrix, they will end up getting an error when you try to initialize the sparsity.

EDIT: Nevermind. I see where you are supporting both below.

Copy link
Member Author

Choose a reason for hiding this comment

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

Make sense.

* @param[out] csr output raft::device_csr_matrix
*/
template <typename bitmap_t,
typename index_t,
typename csr_matrix_t,
typename = std::enable_if_t<raft::is_device_csr_matrix_v<csr_matrix_t>>>
void bitmap_to_csr(raft::resources const& handle,
raft::core::bitmap_view<bitmap_t, index_t> bitmap,
csr_matrix_t& csr)
{
detail::bitmap_to_csr(handle, bitmap, csr);
}

}; // end NAMESPACE convert
}; // end NAMESPACE sparse
}; // end NAMESPACE raft
Expand Down
Loading
Loading