Commit 79982799 authored by Alejandro Homs Puron's avatar Alejandro Homs Puron
Browse files

Numa: add NumaNodeMask helper class, used by NumaAllocator

parent 9cd3720b
Pipeline #50794 passed with stages
in 27 minutes and 59 seconds
......@@ -149,15 +149,51 @@ protected:
#endif //__unix
#ifdef LIMA_USE_NUMA
class LIMACORE_API NumaAllocator : public MMapAllocator
// Structure needed to bind memory to one or more CPU sockets
class NumaNodeMask
{
public:
static constexpr int MaxNbCPUs = 128;
typedef std::bitset<MaxNbCPUs> Mask;
typedef std::bitset<MaxNbCPUs> CPUMask;
typedef std::vector<unsigned long> ItemArray;
static constexpr int ItemBits = sizeof(ItemArray::value_type) * 8;
NumaNodeMask();
NumaNodeMask(const ItemArray& array);
NumaNodeMask(const NumaNodeMask& o);
NumaNodeMask(NumaNodeMask&& o);
NumaNodeMask& operator =(const ItemArray& array);
NumaNodeMask& operator =(const NumaNodeMask& o);
NumaNodeMask& operator =(NumaNodeMask&& o);
static int getMaxNodes();
static int getNbItems();
static NumaNodeMask fromCPUMask(const CPUMask& cpu_mask);
void bind(void *ptr, size_t size);
const ItemArray& getArray() const { return m_array; }
private:
const ItemArray& checkArray(const ItemArray& array);
ItemArray m_array;
};
NumaAllocator(const Mask& cpu_mask) : m_cpu_mask(cpu_mask) {}
std::ostream& operator <<(std::ostream& os, const NumaNodeMask& mask);
const Mask &getCPUAffinityMask()
class LIMACORE_API NumaAllocator : public MMapAllocator
{
public:
static constexpr int MaxNbCPUs = NumaNodeMask::MaxNbCPUs;
typedef NumaNodeMask::CPUMask CPUMask;
NumaAllocator(const CPUMask& cpu_mask) : m_cpu_mask(cpu_mask) {}
const CPUMask &getCPUAffinityMask()
{ return m_cpu_mask; }
// Allocate a buffer and sets the NUMA memory policy with mbind
......@@ -165,13 +201,7 @@ public:
override;
private:
// Given a cpu_mask, returns the memory node mask
// used by alloc to bind memory with the proper socket
void getNUMANodeMask(const Mask &cpu_mask,
unsigned long& node_mask,
int& max_node);
Mask m_cpu_mask; //<! if NUMA is used, keep the cpu_mask for later use
CPUMask m_cpu_mask; //<! if NUMA is used, keep cpu_mask for later use
};
#endif
......
......@@ -23,6 +23,7 @@
#include <cstdlib>
#include <sstream>
#include <iomanip>
#ifdef __unix
#include <sys/sysinfo.h>
#ifdef LIMA_USE_NUMA
......@@ -301,37 +302,107 @@ void MemBuffer::deepCopy(const MemBuffer& buffer)
#ifdef LIMA_USE_NUMA
Allocator::DataPtr NumaAllocator::alloc(void* &ptr, size_t& size,
size_t alignment)
int NumaNodeMask::getMaxNodes()
{
DataPtr alloc_data = MMapAllocator::alloc(ptr, size, alignment);
static int max_nb_nodes = numa_max_node() + 1;
return max_nb_nodes;
}
if (m_cpu_mask.none())
return alloc_data;
int NumaNodeMask::getNbItems() { return (getMaxNodes() - 1) / ItemBits + 1; }
unsigned long node_mask;
int max_node;
getNUMANodeMask(m_cpu_mask, node_mask, max_node);
if (mbind(ptr, size, MPOL_BIND, &node_mask, max_node, 0) != 0)
throw LIMA_COM_EXC(Error, "Error in mbind: ")
<< strerror(errno);
inline
const NumaNodeMask::ItemArray& NumaNodeMask::checkArray(const ItemArray& array)
{
if (array.size() != getNbItems())
throw LIMA_COM_EXC(Error, "NumaNodeMask array has bad size");
return array;
}
return alloc_data;
NumaNodeMask::NumaNodeMask() : m_array(getNbItems(), 0) {}
NumaNodeMask::NumaNodeMask(const ItemArray& array) : m_array(checkArray(array))
{}
NumaNodeMask::NumaNodeMask(const NumaNodeMask& o) : m_array(o.m_array) {}
NumaNodeMask::NumaNodeMask(NumaNodeMask&& o) : m_array(std::move(o.m_array)) {}
NumaNodeMask& NumaNodeMask::operator =(const ItemArray& array)
{
m_array = checkArray(array);
return *this;
}
NumaNodeMask& NumaNodeMask::operator =(const NumaNodeMask& o)
{
m_array = o.m_array;
return *this;
}
void NumaAllocator::getNUMANodeMask(const Mask &cpu_mask,
unsigned long& node_mask,
int& max_node)
NumaNodeMask& NumaNodeMask::operator =(NumaNodeMask&& o)
{
int nb_nodes = numa_max_node() + 1;
max_node = nb_nodes + 1;
m_array = std::move(o.m_array);
return *this;
}
NumaNodeMask NumaNodeMask::fromCPUMask(const CPUMask& cpu_mask)
{
typedef std::list<std::pair<CPUMask, NumaNodeMask>> NumaNodeList;
static NumaNodeList cpu_numa_node_list;
NumaNodeList::iterator it, end = cpu_numa_node_list.end();
for (it = cpu_numa_node_list.begin(); it != end; ++it)
if (it->first == cpu_mask)
return it->second;;
NumaNodeMask numa_node_mask;
ItemArray& node_mask = numa_node_mask.m_array;
node_mask = 0;
for (unsigned int i = 0; i < MaxNbCPUs; ++i) {
if (cpu_mask.test(i)) {
unsigned int n = numa_node_of_cpu(i);
node_mask |= 1L << n;
if (n >= getMaxNodes())
throw LIMA_COM_EXC(Error, "Numa node too high");
node_mask[n / ItemBits] |= 1L << (n % ItemBits);
}
}
cpu_numa_node_list.emplace_back(std::make_pair(cpu_mask, node_mask));
return numa_node_mask;
}
void NumaNodeMask::bind(void *ptr, size_t size)
{
int max_node = getMaxNodes() + 1; // Linux kernel decrements max_node(?)
if (mbind(ptr, size, MPOL_BIND, &m_array[0], max_node, 0) != 0)
throw LIMA_COM_EXC(Error, "Error in mbind: ")
<< strerror(errno);
}
std::ostream& lima::operator <<(std::ostream& os, const NumaNodeMask& mask)
{
os << "[" << mask.getMaxNodes() << "-bit]" << hex << setfill('0');
bool first = true;
int missaligned_bits = mask.getMaxNodes() % mask.ItemBits;
int first_bits = missaligned_bits ? missaligned_bits : mask.ItemBits;
const NumaNodeMask::ItemArray& array = mask.getArray();
NumaNodeMask::ItemArray::const_reverse_iterator it, end = array.rend();
for (it = array.rbegin(); it != end; ++it, first = false) {
int word_bits = first ? first_bits : mask.ItemBits;
os << (!first ? "," : "") << setw(word_bits / 4) << *it;
}
return os << setfill(' ') << dec;
}
Allocator::DataPtr NumaAllocator::alloc(void* &ptr, size_t& size,
size_t alignment)
{
DataPtr alloc_data = MMapAllocator::alloc(ptr, size, alignment);
if (m_cpu_mask.none())
return alloc_data;
NumaNodeMask node_mask = NumaNodeMask::fromCPUMask(m_cpu_mask);
node_mask.bind(ptr, size);
return alloc_data;
}
#endif //LIMA_USE_NUMA
......@@ -111,12 +111,12 @@ class LIMACORE_API NumaSoftBufferAllocMgr : public SoftBufferAllocMgr
public:
static constexpr int MaxNbCPUs = NumaAllocator::MaxNbCPUs;
typedef NumaAllocator::Mask Mask;
typedef NumaAllocator::CPUMask CPUMask;
NumaSoftBufferAllocMgr();
virtual ~NumaSoftBufferAllocMgr();
void setCPUAffinityMask(const Mask& mask);
void setCPUAffinityMask(const CPUMask& mask);
protected:
NumaAllocator *m_numa_allocator;
......@@ -386,7 +386,7 @@ protected:
class LIMACORE_API NumaSoftBufferCtrlObj : public SoftBufferCtrlObj
{
public:
typedef NumaSoftBufferAllocMgr::Mask Mask;
typedef NumaSoftBufferAllocMgr::CPUMask CPUMask;
NumaSoftBufferCtrlObj()
: SoftBufferCtrlObj(new NumaSoftBufferAllocMgr())
......@@ -394,7 +394,7 @@ public:
virtual ~NumaSoftBufferCtrlObj() = default;
void setCPUAffinityMask(Mask mask)
void setCPUAffinityMask(CPUMask mask)
{
NumaSoftBufferAllocMgr *mgr;
mgr = static_cast<NumaSoftBufferAllocMgr *>(m_buffer_alloc_mgr.getPtr());
......
......@@ -183,17 +183,17 @@ NumaSoftBufferAllocMgr::~NumaSoftBufferAllocMgr()
setAllocator(Allocator::defaultAllocator());
}
void NumaSoftBufferAllocMgr::setCPUAffinityMask(const Mask& mask)
void NumaSoftBufferAllocMgr::setCPUAffinityMask(const CPUMask& mask)
{
DEB_MEMBER_FUNCT();
if (DEB_CHECK_ANY(DebTypeParam)) {
typedef unsigned long ULong;
constexpr Mask ULongMask(std::numeric_limits<ULong>::max());
constexpr CPUMask ULongMask(std::numeric_limits<ULong>::max());
std::ostringstream os;
typedef unsigned long ULong;
constexpr int NbULongBits = sizeof(ULong) * 8;
for (int i = 0; i < MaxNbCPUs / NbULongBits; ++i) {
Mask m = (mask >> (i * NbULongBits)) & ULongMask;
CPUMask m = (mask >> (i * NbULongBits)) & ULongMask;
ULong val = m.to_ulong();
os << std::hex << val;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment