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

Use a SmallVector<T> as parts container #508

Open
wants to merge 2 commits into
base: dev
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
2 changes: 2 additions & 0 deletions fairmq/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ if(BUILD_FAIRMQ)
ProgOptionsFwd.h
Properties.h
PropertyOutput.h
SmallVector.h
Socket.h
StateMachine.h
States.h
Expand Down Expand Up @@ -125,6 +126,7 @@ if(BUILD_FAIRMQ)
PluginServices.cxx
ProgOptions.cxx
Properties.cxx
SmallVector.cxx
StateMachine.cxx
States.cxx
SuboptParser.cxx
Expand Down
4 changes: 2 additions & 2 deletions fairmq/Channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ class Channel
}

void CheckSendCompatibility(Parts& parts) { CheckSendCompatibility(parts.fParts); }
void CheckSendCompatibility(std::vector<MessagePtr>& msgVec)
void CheckSendCompatibility(Parts::container & msgVec)
{
for (auto& msg : msgVec) {
if (fTransportType != msg->GetType()) {
Expand Down Expand Up @@ -468,7 +468,7 @@ class Channel
}

void CheckReceiveCompatibility(Parts& parts) { CheckReceiveCompatibility(parts.fParts); }
void CheckReceiveCompatibility(std::vector<MessagePtr>& msgVec)
void CheckReceiveCompatibility(Parts::container& msgVec)
{
for (auto& msg : msgVec) {
if (fTransportType != msg->GetType()) {
Expand Down
13 changes: 7 additions & 6 deletions fairmq/Parts.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <algorithm> // std::move
#include <fairmq/Message.h> // fair::mq::MessagePtr
#include <fairmq/SmallVector.h>
#include <iterator> // std::back_inserter
#include <utility> // std::move, std::forward
#include <vector> // std::vector
Expand All @@ -21,7 +22,7 @@ namespace fair::mq {
/// Message, used for sending multi-part messages
struct Parts
{
using container = std::vector<MessagePtr>;
using container = fair::llvm_copy::SmallVector<MessagePtr, 8>;
using size_type = container::size_type;
using reference = container::reference;
using const_reference = container::const_reference;
Expand Down Expand Up @@ -71,9 +72,9 @@ struct Parts
// const_reference operator[](size_type index) const { return fParts[index]; }

[[deprecated("Redundant, dereference at call site e.g. '*(parts.At(index))' instead.")]]
Message& AtRef(size_type index) { return *(fParts.at(index)); }
reference At(size_type index) { return fParts.at(index); }
const_reference At(size_type index) const { return fParts.at(index); }
Message& AtRef(size_type index) { return *(fParts[index]); }
reference At(size_type index) { return fParts[index]; }
const_reference At(size_type index) const { return fParts[index]; }

size_type Size() const noexcept { return fParts.size(); }
bool Empty() const noexcept { return fParts.empty(); }
Expand All @@ -82,10 +83,10 @@ struct Parts
// range access
iterator begin() noexcept { return fParts.begin(); }
const_iterator begin() const noexcept { return fParts.begin(); }
const_iterator cbegin() const noexcept { return fParts.cbegin(); }
const_iterator cbegin() const noexcept { return fParts.begin(); }
iterator end() noexcept { return fParts.end(); }
const_iterator end() const noexcept { return fParts.end(); }
const_iterator cend() const noexcept { return fParts.cend(); }
const_iterator cend() const noexcept { return fParts.end(); }

container fParts{};
};
Expand Down
120 changes: 120 additions & 0 deletions fairmq/SmallVector.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
//===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the SmallVector class.
//
//===----------------------------------------------------------------------===//

#include <SmallVector.h>
//#include "llvm/Support/MemAlloc.h"
#include <cstdint>
using namespace fair::llvm_copy;

// Check that no bytes are wasted and everything is well-aligned.
namespace {
struct Struct16B {
alignas(16) void *X;
};
struct Struct32B {
alignas(32) void *X;
};
}
static_assert(sizeof(SmallVector<void *, 0>) ==
sizeof(unsigned) * 2 + sizeof(void *),
"wasted space in SmallVector size 0");
static_assert(alignof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
"wrong alignment for 16-byte aligned T");
static_assert(alignof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
"wrong alignment for 32-byte aligned T");
static_assert(sizeof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
"missing padding for 16-byte aligned T");
static_assert(sizeof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
"missing padding for 32-byte aligned T");
static_assert(sizeof(SmallVector<void *, 1>) ==
sizeof(unsigned) * 2 + sizeof(void *) * 2,
"wasted space in SmallVector size 1");

static_assert(sizeof(SmallVector<char, 0>) ==
sizeof(void *) * 2 + sizeof(void *),
"1 byte elements have word-sized type for size and capacity");

// Note: Moving this function into the header may cause performance regression.
template <class Size_T>
static size_t getNewCapacity(size_t MinSize, size_t , size_t OldCapacity) {
constexpr size_t MaxSize = std::numeric_limits<Size_T>::max();

// In theory 2*capacity can overflow if the capacity is 64 bit, but the
// original capacity would never be large enough for this to be a problem.
size_t NewCapacity = 2 * OldCapacity + 1; // Always grow.
return std::clamp(NewCapacity, MinSize, MaxSize);
}

template <class Size_T>
void *SmallVectorBase<Size_T>::replaceAllocation(void *NewElts, size_t TSize,
size_t NewCapacity,
size_t VSize) {
void *NewEltsReplace = malloc(NewCapacity * TSize);
if (VSize)
memcpy(NewEltsReplace, NewElts, VSize * TSize);
free(NewElts);
return NewEltsReplace;
}

// Note: Moving this function into the header may cause performance regression.
template <class Size_T>
void *SmallVectorBase<Size_T>::mallocForGrow(void *FirstEl, size_t MinSize,
size_t TSize,
size_t &NewCapacity) {
NewCapacity = getNewCapacity<Size_T>(MinSize, TSize, this->capacity());
// Even if capacity is not 0 now, if the vector was originally created with
// capacity 0, it's possible for the malloc to return FirstEl.
void *NewElts = malloc(NewCapacity * TSize);
if (NewElts == FirstEl)
NewElts = replaceAllocation(NewElts, TSize, NewCapacity);
return NewElts;
}

// Note: Moving this function into the header may cause performance regression.
template <class Size_T>
void SmallVectorBase<Size_T>::grow_pod(void *FirstEl, size_t MinSize,
size_t TSize) {
size_t NewCapacity = getNewCapacity<Size_T>(MinSize, TSize, this->capacity());
void *NewElts;
if (BeginX == FirstEl) {
NewElts = malloc(NewCapacity * TSize);
if (NewElts == FirstEl)
NewElts = replaceAllocation(NewElts, TSize, NewCapacity);

// Copy the elements over. No need to run dtors on PODs.
memcpy(NewElts, this->BeginX, size() * TSize);
} else {
// If this wasn't grown from the inline copy, grow the allocated space.
NewElts = realloc(this->BeginX, NewCapacity * TSize);
if (NewElts == FirstEl)
NewElts = replaceAllocation(NewElts, TSize, NewCapacity, size());
}

this->set_allocation_range(NewElts, NewCapacity);
}

template class fair::llvm_copy::SmallVectorBase<uint32_t>;

// Disable the uint64_t instantiation for 32-bit builds.
// Both uint32_t and uint64_t instantiations are needed for 64-bit builds.
// This instantiation will never be used in 32-bit builds, and will cause
// warnings when sizeof(Size_T) > sizeof(size_t).
#if SIZE_MAX > UINT32_MAX
template class fair::llvm_copy::SmallVectorBase<uint64_t>;

// Assertions to ensure this #if stays in sync with SmallVectorSizeType.
static_assert(sizeof(SmallVectorSizeType<char>) == sizeof(uint64_t),
"Expected SmallVectorBase<uint64_t> variant to be in use.");
#else
static_assert(sizeof(SmallVectorSizeType<char>) == sizeof(uint32_t),
"Expected SmallVectorBase<uint32_t> variant to be in use.");
#endif
Loading