Files
lammps/lib/kokkos/containers/src/Kokkos_Vector.hpp
2022-07-01 13:17:50 -06:00

337 lines
10 KiB
C++

/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) National Technology & Engineering
// Solutions of Sandia, LLC (NTESS).
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#ifndef KOKKOS_VECTOR_HPP
#define KOKKOS_VECTOR_HPP
#include <Kokkos_Core_fwd.hpp>
#include <Kokkos_DualView.hpp>
/* Drop in replacement for std::vector based on Kokkos::DualView
* Most functions only work on the host (it will not compile if called from
* device kernel)
*
*/
namespace Kokkos {
template <class Scalar, class Arg1Type = void>
class vector : public DualView<Scalar*, LayoutLeft, Arg1Type> {
public:
using value_type = Scalar;
using pointer = Scalar*;
using const_pointer = const Scalar*;
using reference = Scalar&;
using const_reference = const Scalar&;
using iterator = Scalar*;
using const_iterator = const Scalar*;
using size_type = size_t;
private:
size_t _size;
float _extra_storage;
using DV = DualView<Scalar*, LayoutLeft, Arg1Type>;
public:
#ifdef KOKKOS_ENABLE_CUDA_UVM
KOKKOS_INLINE_FUNCTION reference operator()(int i) const {
return DV::h_view(i);
};
KOKKOS_INLINE_FUNCTION reference operator[](int i) const {
return DV::h_view(i);
};
#else
inline reference operator()(int i) const { return DV::h_view(i); };
inline reference operator[](int i) const { return DV::h_view(i); };
#endif
/* Member functions which behave like std::vector functions */
vector() : DV() {
_size = 0;
_extra_storage = 1.1;
}
vector(int n, Scalar val = Scalar())
: DualView<Scalar*, LayoutLeft, Arg1Type>("Vector", size_t(n * (1.1))) {
_size = n;
_extra_storage = 1.1;
DV::modified_flags(0) = 1;
assign(n, val);
}
void resize(size_t n) {
if (n >= span()) DV::resize(size_t(n * _extra_storage));
_size = n;
}
void resize(size_t n, const Scalar& val) { assign(n, val); }
void assign(size_t n, const Scalar& val) {
/* Resize if necessary (behavior of std:vector) */
if (n > span()) DV::resize(size_t(n * _extra_storage));
_size = n;
/* Assign value either on host or on device */
if (DV::template need_sync<typename DV::t_dev::device_type>()) {
set_functor_host f(DV::h_view, val);
parallel_for("Kokkos::vector::assign", n, f);
typename DV::t_host::execution_space().fence(
"Kokkos::vector::assign: fence after assigning values");
DV::template modify<typename DV::t_host::device_type>();
} else {
set_functor f(DV::d_view, val);
parallel_for("Kokkos::vector::assign", n, f);
typename DV::t_dev::execution_space().fence(
"Kokkos::vector::assign: fence after assigning values");
DV::template modify<typename DV::t_dev::device_type>();
}
}
void reserve(size_t n) { DV::resize(size_t(n * _extra_storage)); }
void push_back(Scalar val) {
DV::template sync<typename DV::t_host::device_type>();
DV::template modify<typename DV::t_host::device_type>();
if (_size == span()) {
size_t new_size = _size * _extra_storage;
if (new_size == _size) new_size++;
DV::resize(new_size);
}
DV::h_view(_size) = val;
_size++;
}
void pop_back() { _size--; }
void clear() { _size = 0; }
iterator insert(iterator it, const value_type& val) {
return insert(it, 1, val);
}
iterator insert(iterator it, size_type count, const value_type& val) {
if ((size() == 0) && (it == begin())) {
resize(count, val);
DV::sync_host();
return begin();
}
DV::sync_host();
DV::modify_host();
if (std::less<>()(it, begin()) || std::less<>()(end(), it))
Kokkos::abort("Kokkos::vector::insert : invalid insert iterator");
if (count == 0) return it;
ptrdiff_t start = std::distance(begin(), it);
auto org_size = size();
resize(size() + count);
std::copy_backward(begin() + start, begin() + org_size,
begin() + org_size + count);
std::fill_n(begin() + start, count, val);
return begin() + start;
}
private:
template <class T>
struct impl_is_input_iterator
: /* TODO replace this */ std::integral_constant<
bool, !std::is_convertible<T, size_type>::value> {};
public:
// TODO: can use detection idiom to generate better error message here later
template <typename InputIterator>
typename std::enable_if<impl_is_input_iterator<InputIterator>::value,
iterator>::type
insert(iterator it, InputIterator b, InputIterator e) {
ptrdiff_t count = std::distance(b, e);
DV::sync_host();
DV::modify_host();
if (std::less<>()(it, begin()) || std::less<>()(end(), it))
Kokkos::abort("Kokkos::vector::insert : invalid insert iterator");
ptrdiff_t start = std::distance(begin(), it);
auto org_size = size();
// Note: resize(...) invalidates it; use begin() + start instead
resize(size() + count);
std::copy_backward(begin() + start, begin() + org_size,
begin() + org_size + count);
std::copy(b, e, begin() + start);
return begin() + start;
}
KOKKOS_INLINE_FUNCTION constexpr bool is_allocated() const {
return DV::is_allocated();
}
size_type size() const { return _size; }
size_type max_size() const { return 2000000000; }
size_type span() const { return DV::span(); }
bool empty() const { return _size == 0; }
pointer data() const { return DV::h_view.data(); }
iterator begin() const { return DV::h_view.data(); }
iterator end() const {
return _size > 0 ? DV::h_view.data() + _size : DV::h_view.data();
}
reference front() { return DV::h_view(0); }
reference back() { return DV::h_view(_size - 1); }
const_reference front() const { return DV::h_view(0); }
const_reference back() const { return DV::h_view(_size - 1); }
/* std::algorithms which work originally with iterators, here they are
* implemented as member functions */
size_t lower_bound(const size_t& start, const size_t& theEnd,
const Scalar& comp_val) const {
int lower = start; // FIXME (mfh 24 Apr 2014) narrowing conversion
int upper =
_size > theEnd
? theEnd
: _size - 1; // FIXME (mfh 24 Apr 2014) narrowing conversion
if (upper <= lower) {
return theEnd;
}
Scalar lower_val = DV::h_view(lower);
Scalar upper_val = DV::h_view(upper);
size_t idx = (upper + lower) / 2;
Scalar val = DV::h_view(idx);
if (val > upper_val) return upper;
if (val < lower_val) return start;
while (upper > lower) {
if (comp_val > val) {
lower = ++idx;
} else {
upper = idx;
}
idx = (upper + lower) / 2;
val = DV::h_view(idx);
}
return idx;
}
bool is_sorted() {
for (int i = 0; i < _size - 1; i++) {
if (DV::h_view(i) > DV::h_view(i + 1)) return false;
}
return true;
}
iterator find(Scalar val) const {
if (_size == 0) return end();
int upper, lower, current;
current = _size / 2;
upper = _size - 1;
lower = 0;
if ((val < DV::h_view(0)) || (val > DV::h_view(_size - 1))) return end();
while (upper > lower) {
if (val > DV::h_view(current))
lower = current + 1;
else
upper = current;
current = (upper + lower) / 2;
}
if (val == DV::h_view(current))
return &DV::h_view(current);
else
return end();
}
/* Additional functions for data management */
void device_to_host() { deep_copy(DV::h_view, DV::d_view); }
void host_to_device() const { deep_copy(DV::d_view, DV::h_view); }
void on_host() { DV::template modify<typename DV::t_host::device_type>(); }
void on_device() { DV::template modify<typename DV::t_dev::device_type>(); }
void set_overallocation(float extra) { _extra_storage = 1.0 + extra; }
public:
struct set_functor {
using execution_space = typename DV::t_dev::execution_space;
typename DV::t_dev _data;
Scalar _val;
set_functor(typename DV::t_dev data, Scalar val) : _data(data), _val(val) {}
KOKKOS_INLINE_FUNCTION
void operator()(const int& i) const { _data(i) = _val; }
};
struct set_functor_host {
using execution_space = typename DV::t_host::execution_space;
typename DV::t_host _data;
Scalar _val;
set_functor_host(typename DV::t_host data, Scalar val)
: _data(data), _val(val) {}
KOKKOS_INLINE_FUNCTION
void operator()(const int& i) const { _data(i) = _val; }
};
};
} // namespace Kokkos
#endif