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

Feature/eckit sparsematrix allocators reorganization, new in-place allocator #148

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions src/eckit/linalg/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ list( APPEND eckit_la_srcs
Triplet.h
Vector.cc
Vector.h
allocator/BufferAllocator.cc
allocator/BufferAllocator.h
allocator/InPlaceAllocator.cc
allocator/InPlaceAllocator.h
allocator/StandardAllocator.cc
allocator/StandardAllocator.h
dense/LinearAlgebraGeneric.cc
dense/LinearAlgebraGeneric.h
sparse/LinearAlgebraGeneric.cc
Expand Down
75 changes: 9 additions & 66 deletions src/eckit/linalg/SparseMatrix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
#include "eckit/exception/Exceptions.h"
#include "eckit/io/AutoCloser.h"
#include "eckit/io/MemoryHandle.h"
#include "eckit/log/Bytes.h"
#include "eckit/linalg/allocator/BufferAllocator.h"
#include "eckit/linalg/allocator/StandardAllocator.h"
#include "eckit/log/Log.h"
#include "eckit/memory/MemoryBuffer.h"
#include "eckit/serialisation/FileStream.h"
Expand All @@ -37,64 +38,6 @@ static_assert(sizeof(Index) == sizeof(SparseMatrix::UIndex), "sizeof(sizeof(Inde
static constexpr bool littleEndian = eckit_LITTLE_ENDIAN != 0;


//----------------------------------------------------------------------------------------------------------------------

namespace detail {

class StandardAllocator : public SparseMatrix::Allocator {
public:
StandardAllocator() : membuff_(0) {}

SparseMatrix::Layout allocate(SparseMatrix::Shape& shape) override {
if (shape.allocSize() > membuff_.size()) {
membuff_.resize(shape.allocSize());
}

SparseMatrix::Layout p;

char* addr = membuff_;

p.data_ = reinterpret_cast<Scalar*>(addr);
p.outer_ = reinterpret_cast<SparseMatrix::UIndex*>(addr + shape.sizeofData());
p.inner_ = reinterpret_cast<Index*>(addr + shape.sizeofData() + shape.sizeofOuter());

return p;
}

void deallocate(SparseMatrix::Layout p, SparseMatrix::Shape) override {}
bool inSharedMemory() const override { return false; }
void print(std::ostream& out) const override {
out << "StandardAllocator[" << Bytes{static_cast<double>(membuff_.size())} << "]";
}

MemoryBuffer membuff_;
};


class BufferAllocator : public SparseMatrix::Allocator {
public:
BufferAllocator(const MemoryBuffer& buffer) : buffer_(buffer, buffer.size()) {}

SparseMatrix::Layout allocate(SparseMatrix::Shape& shape) override {
SparseMatrix::Layout layout;

SparseMatrix::load(buffer_.data(), buffer_.size(), layout, shape);

return layout;
}

void deallocate(SparseMatrix::Layout, SparseMatrix::Shape) override {}
bool inSharedMemory() const override { return false; }
void print(std::ostream& out) const override {
out << "BufferAllocator[" << Bytes{static_cast<double>(buffer_.size())} << "]";
}

MemoryBuffer buffer_;
};


} // namespace detail

//----------------------------------------------------------------------------------------------------------------------

void SparseMatrix::Shape::print(std::ostream& os) const {
Expand All @@ -105,19 +48,19 @@ void SparseMatrix::Shape::print(std::ostream& os) const {
}


SparseMatrix::SparseMatrix(Allocator* alloc) : owner_(alloc != nullptr ? alloc : new detail::StandardAllocator) {
SparseMatrix::SparseMatrix(Allocator* alloc) : owner_(alloc != nullptr ? alloc : new allocator::StandardAllocator) {
spm_ = owner_->allocate(shape_);
}


SparseMatrix::SparseMatrix(Size rows, Size cols, Allocator* alloc) :
owner_(alloc != nullptr ? alloc : new detail::StandardAllocator) {
owner_(alloc != nullptr ? alloc : new allocator::StandardAllocator) {
reserve(rows, cols, 1);
}


SparseMatrix::SparseMatrix(Size rows, Size cols, const std::vector<Triplet>& triplets) :
owner_(new detail::StandardAllocator) {
owner_(new allocator::StandardAllocator) {

// Count number of non-zeros, allocate memory 1 triplet per non-zero
Size nnz = std::count_if(triplets.begin(), triplets.end(), [](const auto& tri) { return tri.nonZero(); });
Expand Down Expand Up @@ -163,17 +106,17 @@ SparseMatrix::SparseMatrix(Size rows, Size cols, const std::vector<Triplet>& tri
}


SparseMatrix::SparseMatrix(Stream& s) : owner_(new detail::StandardAllocator) {
SparseMatrix::SparseMatrix(Stream& s) : owner_(new allocator::StandardAllocator) {
decode(s);
}


SparseMatrix::SparseMatrix(const MemoryBuffer& buffer) : owner_(new detail::BufferAllocator(buffer)) {
SparseMatrix::SparseMatrix(const MemoryBuffer& buffer) : owner_(new allocator::BufferAllocator(buffer)) {
spm_ = owner_->allocate(shape_);
}


SparseMatrix::SparseMatrix(const SparseMatrix& other) : owner_(new detail::StandardAllocator) {
SparseMatrix::SparseMatrix(const SparseMatrix& other) : owner_(new allocator::StandardAllocator) {
if (!other.empty()) { // in case we copy an other that was constructed empty

reserve(other.rows(), other.cols(), other.nonZeros());
Expand Down Expand Up @@ -539,7 +482,7 @@ void SparseMatrix::decode(Stream& s) {

reset();

owner_ = std::make_unique<detail::StandardAllocator>();
owner_ = std::make_unique<allocator::StandardAllocator>();

reserve(rows, cols, nnz);

Expand Down
45 changes: 45 additions & 0 deletions src/eckit/linalg/allocator/BufferAllocator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* (C) Copyright 1996- ECMWF.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
* In applying this licence, ECMWF does not waive the privileges and immunities
* granted to it by virtue of its status as an intergovernmental organisation
* nor does it submit to any jurisdiction.
*/


#include "eckit/linalg/allocator/BufferAllocator.h"

#include <ostream>

#include "eckit/log/Bytes.h"


namespace eckit::linalg::allocator {


BufferAllocator::BufferAllocator(const MemoryBuffer& buffer) : buffer_(buffer, buffer.size()) {}


SparseMatrix::Layout BufferAllocator::allocate(SparseMatrix::Shape& shape) {
SparseMatrix::Layout layout;
SparseMatrix::load(buffer_.data(), buffer_.size(), layout, shape);
return layout;
}


void BufferAllocator::deallocate(SparseMatrix::Layout, SparseMatrix::Shape) {}


bool BufferAllocator::inSharedMemory() const {
return false;
}


void BufferAllocator::print(std::ostream& out) const {
out << "BufferAllocator[" << Bytes{static_cast<double>(buffer_.size())} << "]";
}


} // namespace eckit::linalg::allocator
36 changes: 36 additions & 0 deletions src/eckit/linalg/allocator/BufferAllocator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* (C) Copyright 1996- ECMWF.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
* In applying this licence, ECMWF does not waive the privileges and immunities
* granted to it by virtue of its status as an intergovernmental organisation
* nor does it submit to any jurisdiction.
*/


#pragma once

#include "eckit/linalg/SparseMatrix.h"

#include "eckit/memory/MemoryBuffer.h"


namespace eckit::linalg::allocator {


class BufferAllocator : public SparseMatrix::Allocator {
public:
BufferAllocator(const MemoryBuffer&);

SparseMatrix::Layout allocate(SparseMatrix::Shape&) override;

void deallocate(SparseMatrix::Layout, SparseMatrix::Shape) override;
bool inSharedMemory() const override;
void print(std::ostream&) const override;

MemoryBuffer buffer_;
};


} // namespace eckit::linalg::allocator
57 changes: 57 additions & 0 deletions src/eckit/linalg/allocator/InPlaceAllocator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* (C) Copyright 2024- ECMWF.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
* In applying this licence, ECMWF does not waive the privileges and immunities
* granted to it by virtue of its status as an intergovernmental organisation
* nor does it submit to any jurisdiction.
*/


#include "eckit/linalg/allocator/InPlaceAllocator.h"

#include <ostream>

#include "eckit/exception/Exceptions.h"


namespace eckit::linalg::allocator {


InPlaceAllocator::InPlaceAllocator(Size Nr, Size Nc, Size nnz, Index* ia, Index* ja, Scalar* a) :
Nr_(Nr), Nc_(Nc), nnz_(nnz), ia_(ia), ja_(ja), a_(a) {
ASSERT(ia_ != nullptr);
ASSERT(ja_ != nullptr);
ASSERT(a_ != nullptr);
}


SparseMatrix::Layout InPlaceAllocator::InPlaceAllocator::allocate(SparseMatrix::Shape& shape) {
shape.size_ = nnz_;
shape.rows_ = Nr_;
shape.cols_ = Nc_;

SparseMatrix::Layout layout;
layout.outer_ = reinterpret_cast<decltype(SparseMatrix::Layout::outer_)>(ia_);
Copy link
Member

Choose a reason for hiding this comment

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

I believe a reinterpret_cast or const_cast or any other casting should not be necessary.

layout.inner_ = ja_;
layout.data_ = a_;

return layout;
}


void InPlaceAllocator::deallocate(SparseMatrix::Layout, SparseMatrix::Shape) {}


bool InPlaceAllocator::inSharedMemory() const {
return false;
}


void InPlaceAllocator::print(std::ostream& out) const {
out << "InPlaceAllocator[Nr=" << Nr_ << ",Nc=" << Nc_ << ",nnz=" << nnz_ << "]";
}


} // namespace eckit::linalg::allocator
44 changes: 44 additions & 0 deletions src/eckit/linalg/allocator/InPlaceAllocator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* (C) Copyright 2024- ECMWF.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
* In applying this licence, ECMWF does not waive the privileges and immunities
* granted to it by virtue of its status as an intergovernmental organisation
* nor does it submit to any jurisdiction.
*/


#pragma once

#include "eckit/linalg/SparseMatrix.h"


namespace eckit::linalg::allocator {


/**
* @brief In-place allocator for sparse matrices, directly mapping supporting arrays including from another
* SparseMatrix. It is able to provide a "view".
*/
class InPlaceAllocator : public SparseMatrix::Allocator {
public:
InPlaceAllocator(Size Nr, Size Nc, Size nnz, Index* ia, Index* ja, Scalar* a);

SparseMatrix::Layout allocate(SparseMatrix::Shape&) override;

void deallocate(SparseMatrix::Layout, SparseMatrix::Shape) override;
bool inSharedMemory() const override;
void print(std::ostream&) const override;

private:
const Size Nr_;
const Size Nc_;
const Size nnz_;
Index* ia_; // NOTE: not owned
Index* ja_; // NOTE: not owned
Scalar* a_; // NOTE: not owned
};


} // namespace eckit::linalg::allocator
56 changes: 56 additions & 0 deletions src/eckit/linalg/allocator/StandardAllocator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@

/*
* (C) Copyright 1996- ECMWF.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
* In applying this licence, ECMWF does not waive the privileges and immunities
* granted to it by virtue of its status as an intergovernmental organisation
* nor does it submit to any jurisdiction.
*/


#include "eckit/linalg/allocator/StandardAllocator.h"

#include <ostream>

#include "eckit/log/Bytes.h"


namespace eckit::linalg::allocator {


StandardAllocator::StandardAllocator() : buffer_(0) {}


SparseMatrix::Layout StandardAllocator::allocate(SparseMatrix::Shape& shape) {
if (shape.allocSize() > buffer_.size()) {
buffer_.resize(shape.allocSize());
}

SparseMatrix::Layout layout;

char* addr = buffer_;

layout.data_ = reinterpret_cast<Scalar*>(addr);
layout.outer_ = reinterpret_cast<SparseMatrix::UIndex*>(addr + shape.sizeofData());
layout.inner_ = reinterpret_cast<Index*>(addr + shape.sizeofData() + shape.sizeofOuter());

return layout;
}


void StandardAllocator::deallocate(SparseMatrix::Layout p, SparseMatrix::Shape) {}


bool StandardAllocator::inSharedMemory() const {
return false;
}


void StandardAllocator::print(std::ostream& out) const {
out << "StandardAllocator[" << Bytes{static_cast<double>(buffer_.size())} << "]";
}


} // namespace eckit::linalg::allocator
Loading
Loading