mirror of
https://github.com/mmueller41/genode.git
synced 2026-01-21 12:32:56 +01:00
Started porting newest version of MxTasking.
This commit is contained in:
21
repos/ealanos/include/ealanos/util/ecpp/LICENSE
Normal file
21
repos/ealanos/include/ealanos/util/ecpp/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Jan Macheta
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
960
repos/ealanos/include/ealanos/util/ecpp/static_vector.h
Normal file
960
repos/ealanos/include/ealanos/util/ecpp/static_vector.h
Normal file
@@ -0,0 +1,960 @@
|
||||
#ifndef STATIC_VECTOR_HPP_
|
||||
#define STATIC_VECTOR_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <compare>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef __cpp_exceptions
|
||||
#include <exception>
|
||||
#define ECPP_STATIC_VECTOR_THROW(x) throw(x)
|
||||
#else
|
||||
#define ECPP_STATIC_VECTOR_THROW(x) std::abort();
|
||||
#endif
|
||||
|
||||
namespace ecpp
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Implementation of standard vector with statically allocated pool
|
||||
* The container uses underlying array to allocate required capacity.
|
||||
* For detailed documentation see https://en.cppreference.com/w/cpp/container/vector
|
||||
* The documentation below highlights only the differences.
|
||||
*/
|
||||
template <typename T, std::size_t N> class static_vector
|
||||
{
|
||||
public:
|
||||
|
||||
using value_type = T; ///< The type of the elements
|
||||
using storage_container_type =
|
||||
std::array<std::aligned_storage_t<sizeof(T), alignof(T)>,
|
||||
N>; ///< Type of underlying continuous static storage
|
||||
using size_type = typename storage_container_type::size_type; ///< Unsigned integer type
|
||||
///< (usually std::size_t)
|
||||
|
||||
using pointer = T *; ///< Pointer to element type
|
||||
using const_pointer = T const *; ///< Const pointer to element type
|
||||
|
||||
using reference = T &; ///< Reference to element type
|
||||
using const_reference = T const &; ///< Const reference to element type
|
||||
|
||||
using iterator = pointer; ///< Iterator to value_type type that meets
|
||||
///< LegacyRandomAccessIterator requirements
|
||||
using const_iterator = const_pointer; ///< Iterator to const value_type type that meets
|
||||
///< LegacyRandomAccessIterator requirements
|
||||
|
||||
using reverse_iterator = std::reverse_iterator<iterator>; ///< Reverse iterator type
|
||||
using const_reverse_iterator =
|
||||
std::reverse_iterator<const_iterator>; ///< Reverse const iterator type
|
||||
|
||||
using difference_type = decltype(std::distance(
|
||||
std::declval<iterator>(),
|
||||
std::declval<iterator>())); ///< Signed integer type (usually std::ptrdiff_t)
|
||||
|
||||
private:
|
||||
|
||||
storage_container_type container; ///< element storage
|
||||
size_type currentSize{0}; ///< current element count
|
||||
|
||||
public:
|
||||
|
||||
/// Default constructor. Constructs an empty container with a default-constructed
|
||||
/// allocator
|
||||
constexpr static_vector() noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Constructs the container with count copies of elements with value value
|
||||
* @param[in] count the size of the container
|
||||
* @param[in] value the value to initialize elements of the container with
|
||||
* @note The method will throw LengthError if count > max_size()
|
||||
*/
|
||||
constexpr static_vector(size_type count, const_reference value) : currentSize(count)
|
||||
{
|
||||
if (count > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
}
|
||||
std::uninitialized_fill_n(begin(), count, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs the container with count default-inserted instances of T. No copies
|
||||
* are made
|
||||
* @param[in] count the size of the container
|
||||
* @note The method will throw LengthError if count > max_size()
|
||||
*/
|
||||
constexpr explicit static_vector(size_type count)
|
||||
requires(std::is_default_constructible_v<T>)
|
||||
: currentSize(count)
|
||||
{
|
||||
if (count > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
}
|
||||
std::uninitialized_default_construct_n(begin(), count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs the container with the contents of the range [first, last)
|
||||
* @param[in] first start of the range to copy the elements from
|
||||
* @param[in] last end of the range to copy the elements from
|
||||
* @note The method will throw LengthError if std::distance(first, last) is negative or,
|
||||
* greater than max_size()
|
||||
*/
|
||||
template <class InputIt> constexpr static_vector(InputIt first, InputIt last)
|
||||
{
|
||||
auto dist = std::distance(first, last);
|
||||
auto count = size_type(dist);
|
||||
if (dist < 0 || count > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
}
|
||||
currentSize = count;
|
||||
std::uninitialized_copy(first, last, begin());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor. Constructs the container with the copy of the contents of
|
||||
* other
|
||||
* @param[in] other another container to be used as source to initialize the elements of
|
||||
* the container with
|
||||
*/
|
||||
constexpr static_vector(static_vector const &other) : currentSize(other.currentSize)
|
||||
{
|
||||
std::uninitialized_copy(other.begin(), other.end(), begin());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move constructor. Constructs the container with the contents of other using
|
||||
* move semantics. After the move, other is guaranteed to be empty()
|
||||
* @param[in] other another container to be used as source to initialize the elements of
|
||||
* the container with
|
||||
*/
|
||||
constexpr static_vector(static_vector &&other) noexcept
|
||||
requires(std::movable<T>)
|
||||
: currentSize(std::move(other.currentSize))
|
||||
{
|
||||
std::uninitialized_move(other.begin(), other.end(), begin());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs the container with the contents of the initializer list init
|
||||
* @param[in] init initializer list to initialize the elements of the container with
|
||||
* @note The method will throw LengthError if init.size() > max_size()
|
||||
*/
|
||||
constexpr static_vector(std::initializer_list<value_type> init)
|
||||
: static_vector(init.begin(), init.end())
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destructs the vector. The destructors of the elements are called and the used
|
||||
* storage is deallocated.
|
||||
* @note if the elements are pointers, the pointed-to objects are not destroyed.
|
||||
*/
|
||||
constexpr ~static_vector() noexcept
|
||||
{
|
||||
if constexpr (!std::is_trivially_destructible_v<value_type>) { clear(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator. Replaces the contents with a copy of the contents of
|
||||
* other
|
||||
* @param[in] other another container to use as data source
|
||||
* @return *this
|
||||
*/
|
||||
constexpr static_vector &operator=(static_vector const &other)
|
||||
{
|
||||
if (&other != this) {
|
||||
if (!empty()) { clear(); }
|
||||
currentSize = other.currentSize;
|
||||
std::uninitialized_copy(other.begin(), other.end(), begin());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator. Replaces the contents with those of other using move
|
||||
* semantics (i.e. the data in other is moved from other into this container). other is
|
||||
* in a valid but unspecified state afterwards
|
||||
* @param[in] other another container to use as data source
|
||||
* @return *this
|
||||
*/
|
||||
constexpr static_vector &operator=(static_vector &&other)
|
||||
{
|
||||
if (&other != this) {
|
||||
if (!empty()) { clear(); }
|
||||
currentSize = std::move(other.currentSize);
|
||||
std::uninitialized_move(other.begin(), other.end(), begin());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replaces the contents with those identified by initializer list ilist
|
||||
* @param[in] ilist initializer list to use as data source
|
||||
* @return *this
|
||||
* @note The method will throw LengthError if ilist.size() > max_size()
|
||||
*/
|
||||
constexpr static_vector &operator=(std::initializer_list<value_type> ilist)
|
||||
{
|
||||
if (!empty()) { clear(); }
|
||||
if (ilist.size() > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
}
|
||||
currentSize = ilist.size();
|
||||
std::uninitialized_copy(ilist.begin(), ilist.end(), begin());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replaces the contents with count copies of value value
|
||||
* @param[in] count the new size of the container
|
||||
* @param[in] value the value to initialize elements of the container with
|
||||
* @note The method will throw LengthError if count > max_size()
|
||||
*/
|
||||
constexpr void assign(size_type count, T const &value)
|
||||
{
|
||||
if (!empty()) { clear(); }
|
||||
if (count > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
}
|
||||
std::uninitialized_fill_n(begin(), count, value);
|
||||
currentSize = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replaces the contents with copies of those in the range [first, last)
|
||||
* @param[in] first start of the range to copy the elements from
|
||||
* @param[in] last end of the range to copy the elements from
|
||||
* @note The behavior is undefined if either argument is an iterator into *this.
|
||||
* @note The method will throw LengthError if std::distance(first, last) is negative or,
|
||||
* greater than max_size()
|
||||
*/
|
||||
template <class InputIt> constexpr void assign(InputIt first, InputIt last)
|
||||
{
|
||||
if (!empty()) { clear(); }
|
||||
|
||||
auto dist = std::distance(first, last);
|
||||
auto count = size_type(dist);
|
||||
if (dist < 0 || count > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
}
|
||||
currentSize = count;
|
||||
std::uninitialized_copy(first, last, begin());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replaces the contents with the elements from the initializer list ilist
|
||||
* @param[in] ilist initializer list to copy the values from
|
||||
* @note The method will throw LengthError if ilist.size() > max_size()
|
||||
*/
|
||||
constexpr void assign(std::initializer_list<T> ilist)
|
||||
{
|
||||
assign(ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the element at specified location pos, with bounds
|
||||
* checking.
|
||||
* @param[in] pos position of the element to return
|
||||
* @return Reference to the requested element
|
||||
* @note If pos is not within the range of the container, an OutOfRangeError is thrown.
|
||||
*/
|
||||
constexpr reference at(size_type pos)
|
||||
{
|
||||
if (pos >= size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(std::out_of_range("Index out of bounds"));
|
||||
}
|
||||
return (*this)[pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the element at specified location pos, with bounds
|
||||
* checking.
|
||||
* @param[in] pos position of the element to return
|
||||
* @return Reference to the requested element
|
||||
* @note If pos is not within the range of the container, an OutOfRangeError is thrown.
|
||||
*/
|
||||
constexpr const_reference at(size_type pos) const
|
||||
{
|
||||
if (pos >= size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(std::out_of_range("Index out of bounds"));
|
||||
}
|
||||
return (*this)[pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the element at specified location pos. No bounds
|
||||
* checking is performed
|
||||
* @param[in] pos position of the element to return
|
||||
* @return Reference to the requested element
|
||||
* @note Accessing a nonexistent element through this operator is undefined behavior
|
||||
*/
|
||||
constexpr reference operator[](size_type pos) noexcept { return *(begin() + pos); }
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the element at specified location pos. No bounds
|
||||
* checking is performed
|
||||
* @param[in] pos position of the element to return
|
||||
* @return Reference to the requested element
|
||||
* @note Accessing a nonexistent element through this operator is undefined behavior
|
||||
*/
|
||||
constexpr const_reference operator[](size_type pos) const noexcept
|
||||
{
|
||||
return *(begin() + pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the first element in the container
|
||||
* @return Reference to the first element
|
||||
* @note Calling front on an empty container is undefined
|
||||
*/
|
||||
constexpr reference front() noexcept { return *begin(); }
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the first element in the container
|
||||
* @return Reference to the first element
|
||||
* @note Calling front on an empty container is undefined
|
||||
*/
|
||||
constexpr const_reference front() const noexcept { return *begin(); }
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the last element in the container
|
||||
* @return Reference to the last element
|
||||
* @note Calling back on an empty container is undefined
|
||||
*/
|
||||
constexpr reference back() noexcept { return *(end() - 1); }
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the last element in the container
|
||||
* @return Reference to the last element
|
||||
* @note Calling back on an empty container is undefined
|
||||
*/
|
||||
constexpr const_reference back() const noexcept { return *(end() - 1); }
|
||||
|
||||
/**
|
||||
* @brief Returns pointer to the underlying array serving as element storage
|
||||
* @return Pointer to the underlying element storage. For non-empty containers, the
|
||||
* returned pointer compares equal to the address of the first element
|
||||
* @note The pointer is such that range [data(); data() + size()) is always a valid
|
||||
* range, even if the container is empty (data() is not dereferenceable in that case)
|
||||
*/
|
||||
constexpr pointer data() noexcept
|
||||
{
|
||||
return std::launder(reinterpret_cast<pointer>(container.begin()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns pointer to the underlying array serving as element storage
|
||||
* @return Pointer to the underlying element storage. For non-empty containers, the
|
||||
* returned pointer compares equal to the address of the first element
|
||||
* @note The pointer is such that range [data(); data() + size()) is always a valid
|
||||
* range, even if the container is empty (data() is not dereferenceable in that case)
|
||||
*/
|
||||
constexpr const_pointer data() const noexcept
|
||||
{
|
||||
return std::launder(reinterpret_cast<const_pointer>(container.begin()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the first element of the vector.
|
||||
* If the vector is empty, the returned iterator will be equal to end()
|
||||
* @return Iterator to the first element
|
||||
*/
|
||||
constexpr iterator begin() noexcept { return data(); }
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the first element of the vector.
|
||||
* If the vector is empty, the returned iterator will be equal to end()
|
||||
* @return Iterator to the first element
|
||||
*/
|
||||
constexpr const_iterator begin() const noexcept { return data(); }
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the first element of the vector.
|
||||
* If the vector is empty, the returned iterator will be equal to end()
|
||||
* @return Iterator to the first element
|
||||
*/
|
||||
constexpr const_iterator cbegin() const noexcept { return data(); }
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the element following the last element of the vector
|
||||
* @return Iterator to the element following the last element
|
||||
* @note This element acts as a placeholder; attempting to access it results in
|
||||
* undefined behavior.
|
||||
*/
|
||||
constexpr iterator end() noexcept { return begin() + currentSize; }
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the element following the last element of the vector
|
||||
* @return Iterator to the element following the last element
|
||||
* @note This element acts as a placeholder; attempting to access it results in
|
||||
* undefined behavior.
|
||||
*/
|
||||
constexpr const_iterator end() const noexcept { return begin() + currentSize; }
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the element following the last element of the vector
|
||||
* @return Iterator to the element following the last element
|
||||
* @note This element acts as a placeholder; attempting to access it results in
|
||||
* undefined behavior.
|
||||
*/
|
||||
constexpr const_iterator cend() const noexcept { return begin() + currentSize; }
|
||||
|
||||
/**
|
||||
* @brief Returns a reverse iterator to the first element of the reversed vector.
|
||||
* It corresponds to the last element of the non-reversed vector. If the vector is
|
||||
* empty, the returned iterator is equal to rend().
|
||||
* @return Reverse iterator to the first element
|
||||
*/
|
||||
constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
|
||||
|
||||
/**
|
||||
* @brief Returns a reverse iterator to the first element of the reversed vector.
|
||||
* It corresponds to the last element of the non-reversed vector. If the vector is
|
||||
* empty, the returned iterator is equal to rend().
|
||||
* @return Reverse iterator to the first element
|
||||
*/
|
||||
constexpr const_reverse_iterator rbegin() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reverse iterator to the first element of the reversed vector.
|
||||
* It corresponds to the last element of the non-reversed vector. If the vector is
|
||||
* empty, the returned iterator is equal to rend().
|
||||
* @return Reverse iterator to the first element
|
||||
*/
|
||||
constexpr const_reverse_iterator crbegin() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(cend());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reverse iterator to the element following the last element of the
|
||||
* reversed vector. It corresponds to the element preceding the first element of the
|
||||
* non-reversed vector
|
||||
* @return Reverse iterator to the element following the last element
|
||||
* @note This element acts as a placeholder, attempting to access it results in
|
||||
* undefined behavior
|
||||
*/
|
||||
constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
|
||||
|
||||
/**
|
||||
* @brief Returns a reverse iterator to the element following the last element of the
|
||||
* reversed vector. It corresponds to the element preceding the first element of the
|
||||
* non-reversed vector
|
||||
* @return Reverse iterator to the element following the last element
|
||||
* @note This element acts as a placeholder, attempting to access it results in
|
||||
* undefined behavior
|
||||
*/
|
||||
constexpr const_reverse_iterator rend() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reverse iterator to the element following the last element of the
|
||||
* reversed vector. It corresponds to the element preceding the first element of the
|
||||
* non-reversed vector
|
||||
* @return Reverse iterator to the element following the last element
|
||||
* @note This element acts as a placeholder, attempting to access it results in
|
||||
* undefined behavior
|
||||
*/
|
||||
constexpr const_reverse_iterator crend() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the container has no elements, i.e. whether begin() == end()
|
||||
* @return true if the container is empty, false otherwise
|
||||
*/
|
||||
constexpr bool empty() const noexcept { return 0 == size(); }
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in the container, i.e. std::distance(begin(),
|
||||
* end())
|
||||
* @return The number of elements in the container
|
||||
*/
|
||||
constexpr size_type size() const noexcept { return currentSize; }
|
||||
|
||||
/**
|
||||
* @brief Returns the maximum number of elements the container is able to hold due to
|
||||
* system or library implementation limitations i.e. N
|
||||
* @return Maximum number of elements
|
||||
*/
|
||||
constexpr size_type max_size() const noexcept { return container.max_size(); }
|
||||
|
||||
/**
|
||||
* @brief Increase the capacity of the vector to a value that's greater or equal to
|
||||
* new_cap. Because the static_vector uses static storage, when new_cap <= max_size()
|
||||
* the method does nothing.
|
||||
* @param[in] new_cap new capacity of the vector
|
||||
* @note For compatibility purposes, The method throws LengthError when new_cap >
|
||||
* max_size
|
||||
*/
|
||||
constexpr void reserve(size_type new_cap)
|
||||
{
|
||||
if (new_cap > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(std::length_error("Reserve exceeds max_size"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements that the container has currently allocated
|
||||
* space for
|
||||
* @return Capacity of the currently allocated storage
|
||||
*/
|
||||
constexpr size_type capacity() const noexcept { return max_size(); }
|
||||
|
||||
/**
|
||||
* @brief Requests the removal of unused capacity.
|
||||
* Because the static_vector uses static storage this method does nothing
|
||||
*/
|
||||
constexpr void shrink_to_fit() noexcept
|
||||
{ /* Do nothing, as the underlying storage cannot be shrinked */ }
|
||||
|
||||
/**
|
||||
* @brief Erases all elements from the container. After this call, size() returns zero.
|
||||
* Invalidates any references, pointers, or iterators referring to contained elements.
|
||||
* Any past-the-end iterators are also invalidated. Leaves the capacity() of the vector
|
||||
* unchanged
|
||||
*/
|
||||
constexpr void clear() noexcept
|
||||
{
|
||||
std::for_each(begin(), end(), [](reference x) { std::destroy_at(&x); });
|
||||
currentSize = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts value before pos
|
||||
* @param[in] pos iterator before which the content will be inserted. pos may be the
|
||||
* end() iterator
|
||||
* @param[in] value element value to insert
|
||||
* @return Iterator pointing to the inserted value
|
||||
* @note The method will throw LengthError if size() == max_size()
|
||||
*/
|
||||
constexpr iterator insert(const_iterator pos, T const &value)
|
||||
{
|
||||
if (size() + 1 > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
}
|
||||
auto position = begin() + std::distance(cbegin(), pos);
|
||||
// Move last element right by one (end() + 1 will become new end(), so uninitialized
|
||||
// memory need to be initialized)
|
||||
if (position != end()) {
|
||||
std::uninitialized_move(end() - 1, end(), end());
|
||||
// Move [pos, end() -1) to [pos + 1, end())
|
||||
std::move_backward(position, end() - 1, end());
|
||||
}
|
||||
std::construct_at(position, value);
|
||||
++currentSize;
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts value before pos
|
||||
* @param[in] pos iterator before which the content will be inserted. pos may be the
|
||||
* end() iterator
|
||||
* @param[in] value element value to insert
|
||||
* @return Iterator pointing to the inserted value
|
||||
* @note The method will throw LengthError if size() == max_size()
|
||||
*/
|
||||
constexpr iterator insert(const_iterator pos, T &&value)
|
||||
{
|
||||
if (size() + 1 > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
}
|
||||
auto position = begin() + std::distance(cbegin(), pos);
|
||||
// Move last element right by one (end() + 1 will become new end(), so uninitialized
|
||||
// memory need to be initialized)
|
||||
if (position != end()) {
|
||||
std::uninitialized_move(end() - 1, end(), end());
|
||||
// Move [pos, end() -1) to [pos + 1, end())
|
||||
std::move_backward(position, end() - 1, end());
|
||||
}
|
||||
std::construct_at(position, std::move(value));
|
||||
++currentSize;
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts count copies of the value before pos
|
||||
* @param[in] pos iterator before which the content will be inserted. pos may be the
|
||||
* end() iterator
|
||||
* @param[in] count number of copies to be inserted
|
||||
* @param[in] value element value to insert
|
||||
* @return Iterator pointing to the first element inserted, or pos if count==0
|
||||
* @note The method will throw LengthError if size() + count > max_size()
|
||||
*/
|
||||
constexpr iterator insert(const_iterator pos, size_type count, T const &value)
|
||||
{
|
||||
if (size() + count > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
}
|
||||
auto position = begin() + std::distance(cbegin(), pos);
|
||||
if (count > 0) {
|
||||
if (position != end()) {
|
||||
auto existingElementsToMove = std::distance(
|
||||
position, end()); // Negative distance in this context is UB (position
|
||||
// must be in range [begin(), end()])
|
||||
auto toCopyAtTheEnd = (count >= existingElementsToMove)
|
||||
? (count - existingElementsToMove)
|
||||
: 0;
|
||||
auto toMoveAssign = (count >= existingElementsToMove)
|
||||
? 0
|
||||
: (existingElementsToMove - count);
|
||||
|
||||
// uninitialized_copy last toCopyAtTheEnd elements of input range at the
|
||||
// end(), as they don't overlap with existing data
|
||||
auto lastElem = std::uninitialized_fill_n(end(), toCopyAtTheEnd, value);
|
||||
|
||||
// Move data from [pos end()) after last element of the vector. If size of
|
||||
// the input range is smaller than number of elements to move
|
||||
std::uninitialized_move(position + toMoveAssign, end(), lastElem);
|
||||
|
||||
std::move_backward(position, position + toMoveAssign, end());
|
||||
|
||||
std::fill(position, position + count - toCopyAtTheEnd, value);
|
||||
|
||||
} else {
|
||||
std::uninitialized_fill_n(position, count, value);
|
||||
}
|
||||
currentSize += count;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts elements from range [first, last) before pos
|
||||
* @param[in] pos iterator before which the content will be inserted. pos may be the
|
||||
* end() iterator
|
||||
* @param[in] first start of the range of elements to insert, can't be iterators into
|
||||
* container for which insert is called
|
||||
* @param[in] last end of the range of elements to insert, can't be iterators into
|
||||
* container for which insert is called
|
||||
* @return Iterator pointing to the first element inserted, or pos if first==last
|
||||
* @note The method will throw LengthError if size() + count > max_size()
|
||||
*/
|
||||
template <class InputIt>
|
||||
constexpr iterator insert(const_iterator pos, InputIt first, InputIt last)
|
||||
{
|
||||
auto dist = std::distance(first, last);
|
||||
auto count = size_type(dist);
|
||||
if (dist < 0 || (size() + count > max_size())) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
}
|
||||
auto position = begin() + std::distance(cbegin(), pos);
|
||||
if (position != end()) {
|
||||
auto existingElementsToMove = std::distance(
|
||||
position, end()); // Negative distance in this context is UB (position must
|
||||
// be in range [begin(), end()])
|
||||
auto toCopyAtTheEnd =
|
||||
(dist >= existingElementsToMove) ? (dist - existingElementsToMove) : 0;
|
||||
auto toMoveAssign =
|
||||
(dist >= existingElementsToMove) ? 0 : (existingElementsToMove - dist);
|
||||
|
||||
// uninitialized_copy last toCopyAtTheEnd elements of input range at the end(),
|
||||
// as they don't overlap with existing data
|
||||
auto lastElem = std::uninitialized_copy(last - toCopyAtTheEnd, last, end());
|
||||
|
||||
// Move data from [pos end()) after last element of the vector. If size of the
|
||||
// input range is smaller than number of elements to move
|
||||
//
|
||||
std::uninitialized_move(position + toMoveAssign, end(), lastElem);
|
||||
|
||||
std::move_backward(position, position + toMoveAssign, end());
|
||||
|
||||
std::copy(first, last - toCopyAtTheEnd, position);
|
||||
} else {
|
||||
std::uninitialized_copy(first, last, end());
|
||||
}
|
||||
currentSize += count;
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts elements from initializer list ilist before pos
|
||||
* @param[in] pos iterator before which the content will be inserted. pos may be the
|
||||
* end() iterator
|
||||
* @param[in] ilist initializer list to insert the values from
|
||||
* @return Iterator pointing to the first element inserted, or pos if ilist is empty
|
||||
* @note The method will throw LengthError if size() + ilist.size() > max_size()
|
||||
*/
|
||||
constexpr iterator insert(const_iterator pos, std::initializer_list<T> ilist)
|
||||
{
|
||||
return insert(pos, ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts a new element into the container directly before pos
|
||||
* @param pos iterator before which the new element will be constructed
|
||||
* @param args arguments to forward to the constructor of the element
|
||||
* @return Iterator pointing to the emplaced element
|
||||
* @note The method will throw LengthError if size() == max_size()
|
||||
*/
|
||||
template <class... Args> constexpr iterator emplace(const_iterator pos, Args &&...args)
|
||||
{
|
||||
if (size() + 1 > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
}
|
||||
auto const position = begin() + std::distance(cbegin(), pos);
|
||||
// Move last element right by one (end() + 1 will become new end(), so uninitialized
|
||||
// memory need to be initialized)
|
||||
if (position != end()) {
|
||||
std::uninitialized_move(end() - 1, end(), end());
|
||||
// Move [pos, end() -1) to [pos + 1, end())
|
||||
std::move_backward(position, end() - 1, end());
|
||||
} else {
|
||||
std::construct_at(position, std::forward<Args>(args)...);
|
||||
}
|
||||
++currentSize;
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the element at pos
|
||||
* @param[in] pos to the element to remove
|
||||
* @return Iterator following the last removed element
|
||||
* @note If pos refers to the last element, then the end() iterator is returned
|
||||
*/
|
||||
constexpr iterator erase(const_iterator pos)
|
||||
{
|
||||
auto index = std::distance(cbegin(), pos);
|
||||
std::move(begin() + index + 1, end(), begin() + index);
|
||||
// Elements were moved left, now destroy the last element
|
||||
currentSize--;
|
||||
// Now, end() points to previous last element
|
||||
std::destroy_at(end());
|
||||
return begin() + index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the elements in the range [first, last)
|
||||
* @param[in] first start of range of elements to remove
|
||||
* @param[in] last end of range of elements to remove
|
||||
* @return Iterator following the last removed element
|
||||
* @note If last==end() prior to removal, then the updated end() iterator is returned.
|
||||
* @note If [first, last) is an empty range, then last is returned
|
||||
*/
|
||||
constexpr iterator erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
auto last_ = begin() + std::distance(cbegin(), last);
|
||||
if (first >= last) return last_;
|
||||
auto first_ = begin() + std::distance(cbegin(), first);
|
||||
|
||||
auto toErase = std::distance(first, last); // Guaranteed to be > 0
|
||||
auto lastValid = std::move(first_ + toErase, end(), first_);
|
||||
std::for_each(lastValid, end(), [](reference x) { std::destroy_at(&x); });
|
||||
|
||||
currentSize -= size_type(toErase);
|
||||
return first_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Appends the given element value to the end of the container. The new element
|
||||
* is initialized as a copy of value
|
||||
* @param[in] value the value of the element to append
|
||||
* @note The method will throw LengthError if size() == max_size()
|
||||
*/
|
||||
constexpr void push_back(T const &value)
|
||||
{
|
||||
if (size() + 1 > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
}
|
||||
std::construct_at(end(), value);
|
||||
++currentSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Appends the given element value to the end of the container; value is moved
|
||||
* into the new element
|
||||
* @param[in] value the value of the element to append
|
||||
* @note The method will throw LengthError if size() == max_size()
|
||||
*/
|
||||
constexpr void push_back(T &&value)
|
||||
{
|
||||
if (size() + 1 > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
}
|
||||
std::construct_at(end(), std::move(value));
|
||||
++currentSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Appends a new element to the end of the container. The element is constructed
|
||||
* in-place.
|
||||
* @param[in] args arguments to forward to the constructor of the element
|
||||
* @return A reference to the inserted element
|
||||
* @note The method will throw LengthError if size() == max_size()
|
||||
*/
|
||||
template <class... Args> constexpr reference emplace_back(Args &&...args)
|
||||
{
|
||||
if (size() + 1 > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
}
|
||||
auto const position = end();
|
||||
std::construct_at(position, std::forward<Args>(args)...);
|
||||
++currentSize;
|
||||
return *position;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the last element of the container
|
||||
* Iterators and references to the last element, as well as the end() iterator, are
|
||||
* invalidated
|
||||
* @note Calling pop_back on an empty container results in undefined behavior.
|
||||
*/
|
||||
constexpr void pop_back()
|
||||
{
|
||||
currentSize--;
|
||||
std::destroy_at(end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resizes the container to contain count elements
|
||||
* If the current size is greater than count, the container is reduced to its first
|
||||
* count elements. If the current size is less than count, additional default-inserted
|
||||
* elements are appended
|
||||
* @param[in] count new size of the container
|
||||
* @note The method will throw LengthError if count > max_size()
|
||||
*/
|
||||
constexpr void resize(size_type count)
|
||||
{
|
||||
if (count < size()) {
|
||||
erase(begin() + count, end());
|
||||
} else if (count > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
} else {
|
||||
auto toAdd = count - size();
|
||||
for (size_type i = 0; i != toAdd; ++i) { emplace_back(); }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resizes the container to contain count elements
|
||||
* If the current size is greater than count, the container is reduced to its first
|
||||
* count elements. If the current size is less than count, additional copies of value
|
||||
* are appended.
|
||||
* @param[in] count new size of the container
|
||||
* @param[in] value the value to initialize the new elements with
|
||||
* @note The method will throw LengthError if count > max_size()
|
||||
*/
|
||||
constexpr void resize(size_type count, value_type const &value)
|
||||
{
|
||||
if (count < size()) {
|
||||
erase(begin() + count, end());
|
||||
} else if (count > max_size()) {
|
||||
ECPP_STATIC_VECTOR_THROW(
|
||||
std::length_error("Insertion would exceed static_vector capacity"));
|
||||
} else {
|
||||
auto toAdd = count - size();
|
||||
for (size_type i = 0; i != toAdd; ++i) { push_back(value); }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exchanges the contents of the container with those of other. Swaps content of
|
||||
* underlying storage. All iterators and references are invalidated
|
||||
* @param[in] other reference to static_vector instance to swap with
|
||||
*/
|
||||
constexpr void swap(static_vector &other) noexcept
|
||||
{
|
||||
container.swap(other.container);
|
||||
std::swap(currentSize, other.currentSize);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Checks if the contents of lhs and rhs are equal, that is, they have the same number of
|
||||
* elements and each element in lhs compares equal with the element in rhs at the same position
|
||||
* @param[in] lhs first of vectors whose contents to compare
|
||||
* @param[in] rhs second of vectors whose contents to compare
|
||||
* @return true if the contents of the vectors are equal, false otherwise
|
||||
*/
|
||||
template <class T, std::size_t N>
|
||||
constexpr bool operator==(static_vector<T, N> const &lhs, static_vector<T, N> const &rhs)
|
||||
{
|
||||
return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares the contents of lhs and rhs lexicographically.
|
||||
* The comparison is performed as if by calling std::lexicographical_compare_three_way on two
|
||||
* vectors with a function object performing synthesized three-way comparison. The return type
|
||||
* is same as the result type of synthesized three-way comparison
|
||||
* @param[in] lhs first of vectors whose contents to compare
|
||||
* @param[in] rhs second of vectors whose contents to compare
|
||||
* @return The relative order of the first pair of non-equivalent elements in lhs and rhs if
|
||||
* there are such elements, lhs.size() <=> rhs.size() otherwise
|
||||
*/
|
||||
template <class T, std::size_t N>
|
||||
constexpr auto operator<=>(static_vector<T, N> const &lhs, static_vector<T, N> const &rhs)
|
||||
{
|
||||
return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(),
|
||||
rhs.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Specializes the std::swap algorithm for static_vector.
|
||||
* Swaps the contents of lhs and rhs. Calls lhs.swap(rhs).
|
||||
* @param[in,out] lhs container whose contents to swap
|
||||
* @param[in,out] rhs containers whose contents to swap
|
||||
*/
|
||||
template <typename T, std::size_t N>
|
||||
constexpr void swap(static_vector<T, N> &lhs, static_vector<T, N> &rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erases all elements that compare equal to value from the container
|
||||
* @param[in, out] c container from which to erase
|
||||
* @param[in] value value to be removed
|
||||
* @return The number of erased elements
|
||||
*/
|
||||
template <typename T, std::size_t N, typename U>
|
||||
constexpr typename static_vector<T, N>::size_type erase(static_vector<T, N> &c, U const &value)
|
||||
{
|
||||
auto oldSize = c.size();
|
||||
auto end = std::remove(c.begin(), c.end(), value);
|
||||
c.erase(end, c.end());
|
||||
return c.size() - oldSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erases all elements that compare equal to value from the container
|
||||
* @param[in, out] c container from which to erase
|
||||
* @param[in] pred unary predicate which returns true if the element should be erased
|
||||
* @return The number of erased elements
|
||||
*/
|
||||
template <typename T, std::size_t N, typename Pred>
|
||||
constexpr typename static_vector<T, N>::size_type erase_if(static_vector<T, N> &c, Pred pred)
|
||||
{
|
||||
auto oldSize = c.size();
|
||||
auto end = std::remove_if(c.begin(), c.end(), pred);
|
||||
c.erase(end, c.end());
|
||||
return c.size() - oldSize;
|
||||
}
|
||||
} // namespace ecpp
|
||||
|
||||
#endif
|
||||
20842
repos/ealanos/include/ealanos/util/json.hpp
Normal file
20842
repos/ealanos/include/ealanos/util/json.hpp
Normal file
File diff suppressed because it is too large
Load Diff
21
repos/ealanos/include/ealanos/util/tsl/LICENSE
Normal file
21
repos/ealanos/include/ealanos/util/tsl/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Thibaut Goetghebuer-Planchon <tessil@gmx.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
415
repos/ealanos/include/ealanos/util/tsl/robin_growth_policy.h
Normal file
415
repos/ealanos/include/ealanos/util/tsl/robin_growth_policy.h
Normal file
@@ -0,0 +1,415 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2017 Thibaut Goetghebuer-Planchon <tessil@gmx.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef TSL_ROBIN_GROWTH_POLICY_H
|
||||
#define TSL_ROBIN_GROWTH_POLICY_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <ratio>
|
||||
#include <stdexcept>
|
||||
|
||||
// A change of the major version indicates an API and/or ABI break (change of
|
||||
// in-memory layout of the data structure)
|
||||
#define TSL_RH_VERSION_MAJOR 1
|
||||
// A change of the minor version indicates the addition of a feature without
|
||||
// impact on the API/ABI
|
||||
#define TSL_RH_VERSION_MINOR 4
|
||||
// A change of the patch version indicates a bugfix without additional
|
||||
// functionality
|
||||
#define TSL_RH_VERSION_PATCH 0
|
||||
|
||||
#ifdef TSL_DEBUG
|
||||
#define tsl_rh_assert(expr) assert(expr)
|
||||
#else
|
||||
#define tsl_rh_assert(expr) (static_cast<void>(0))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* If exceptions are enabled, throw the exception passed in parameter, otherwise
|
||||
* call std::terminate.
|
||||
*/
|
||||
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || \
|
||||
(defined(_MSC_VER) && defined(_CPPUNWIND))) && \
|
||||
!defined(TSL_NO_EXCEPTIONS)
|
||||
#define TSL_RH_THROW_OR_TERMINATE(ex, msg) throw ex(msg)
|
||||
#else
|
||||
#define TSL_RH_NO_EXCEPTIONS
|
||||
#ifdef TSL_DEBUG
|
||||
#include <iostream>
|
||||
#define TSL_RH_THROW_OR_TERMINATE(ex, msg) \
|
||||
do { \
|
||||
std::cerr << msg << std::endl; \
|
||||
std::terminate(); \
|
||||
} while (0)
|
||||
#else
|
||||
#define TSL_RH_THROW_OR_TERMINATE(ex, msg) std::terminate()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define TSL_RH_LIKELY(exp) (__builtin_expect(!!(exp), true))
|
||||
#else
|
||||
#define TSL_RH_LIKELY(exp) (exp)
|
||||
#endif
|
||||
|
||||
#define TSL_RH_UNUSED(x) static_cast<void>(x)
|
||||
|
||||
namespace tsl {
|
||||
namespace rh {
|
||||
|
||||
/**
|
||||
* Grow the hash table by a factor of GrowthFactor keeping the bucket count to a
|
||||
* power of two. It allows the table to use a mask operation instead of a modulo
|
||||
* operation to map a hash to a bucket.
|
||||
*
|
||||
* GrowthFactor must be a power of two >= 2.
|
||||
*/
|
||||
template <std::size_t GrowthFactor>
|
||||
class power_of_two_growth_policy {
|
||||
public:
|
||||
/**
|
||||
* Called on the hash table creation and on rehash. The number of buckets for
|
||||
* the table is passed in parameter. This number is a minimum, the policy may
|
||||
* update this value with a higher value if needed (but not lower).
|
||||
*
|
||||
* If 0 is given, min_bucket_count_in_out must still be 0 after the policy
|
||||
* creation and bucket_for_hash must always return 0 in this case.
|
||||
*/
|
||||
explicit power_of_two_growth_policy(std::size_t& min_bucket_count_in_out) {
|
||||
if (min_bucket_count_in_out > max_bucket_count()) {
|
||||
TSL_RH_THROW_OR_TERMINATE(std::length_error,
|
||||
"The hash table exceeds its maximum size.");
|
||||
}
|
||||
|
||||
if (min_bucket_count_in_out > 0) {
|
||||
min_bucket_count_in_out =
|
||||
round_up_to_power_of_two(min_bucket_count_in_out);
|
||||
m_mask = min_bucket_count_in_out - 1;
|
||||
} else {
|
||||
m_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bucket [0, bucket_count()) to which the hash belongs.
|
||||
* If bucket_count() is 0, it must always return 0.
|
||||
*/
|
||||
std::size_t bucket_for_hash(std::size_t hash) const noexcept {
|
||||
return hash & m_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of buckets that should be used on next growth.
|
||||
*/
|
||||
std::size_t next_bucket_count() const {
|
||||
if ((m_mask + 1) > max_bucket_count() / GrowthFactor) {
|
||||
TSL_RH_THROW_OR_TERMINATE(std::length_error,
|
||||
"The hash table exceeds its maximum size.");
|
||||
}
|
||||
|
||||
return (m_mask + 1) * GrowthFactor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of buckets supported by the policy.
|
||||
*/
|
||||
std::size_t max_bucket_count() const {
|
||||
// Largest power of two.
|
||||
return (std::numeric_limits<std::size_t>::max() / 2) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the growth policy as if it was created with a bucket count of 0.
|
||||
* After a clear, the policy must always return 0 when bucket_for_hash is
|
||||
* called.
|
||||
*/
|
||||
void clear() noexcept { m_mask = 0; }
|
||||
|
||||
private:
|
||||
static std::size_t round_up_to_power_of_two(std::size_t value) {
|
||||
if (is_power_of_two(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (value == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
--value;
|
||||
for (std::size_t i = 1; i < sizeof(std::size_t) * CHAR_BIT; i *= 2) {
|
||||
value |= value >> i;
|
||||
}
|
||||
|
||||
return value + 1;
|
||||
}
|
||||
|
||||
static constexpr bool is_power_of_two(std::size_t value) {
|
||||
return value != 0 && (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
static_assert(is_power_of_two(GrowthFactor) && GrowthFactor >= 2,
|
||||
"GrowthFactor must be a power of two >= 2.");
|
||||
|
||||
std::size_t m_mask;
|
||||
};
|
||||
|
||||
/**
|
||||
* Grow the hash table by GrowthFactor::num / GrowthFactor::den and use a modulo
|
||||
* to map a hash to a bucket. Slower but it can be useful if you want a slower
|
||||
* growth.
|
||||
*/
|
||||
template <class GrowthFactor = std::ratio<3, 2>>
|
||||
class mod_growth_policy {
|
||||
public:
|
||||
explicit mod_growth_policy(std::size_t& min_bucket_count_in_out) {
|
||||
if (min_bucket_count_in_out > max_bucket_count()) {
|
||||
TSL_RH_THROW_OR_TERMINATE(std::length_error,
|
||||
"The hash table exceeds its maximum size.");
|
||||
}
|
||||
|
||||
if (min_bucket_count_in_out > 0) {
|
||||
m_mod = min_bucket_count_in_out;
|
||||
} else {
|
||||
m_mod = 1;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t bucket_for_hash(std::size_t hash) const noexcept {
|
||||
return hash % m_mod;
|
||||
}
|
||||
|
||||
std::size_t next_bucket_count() const {
|
||||
if (m_mod == max_bucket_count()) {
|
||||
TSL_RH_THROW_OR_TERMINATE(std::length_error,
|
||||
"The hash table exceeds its maximum size.");
|
||||
}
|
||||
|
||||
const double next_bucket_count =
|
||||
std::ceil(double(m_mod) * REHASH_SIZE_MULTIPLICATION_FACTOR);
|
||||
if (!std::isnormal(next_bucket_count)) {
|
||||
TSL_RH_THROW_OR_TERMINATE(std::length_error,
|
||||
"The hash table exceeds its maximum size.");
|
||||
}
|
||||
|
||||
if (next_bucket_count > double(max_bucket_count())) {
|
||||
return max_bucket_count();
|
||||
} else {
|
||||
return std::size_t(next_bucket_count);
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t max_bucket_count() const { return MAX_BUCKET_COUNT; }
|
||||
|
||||
void clear() noexcept { m_mod = 1; }
|
||||
|
||||
private:
|
||||
static constexpr double REHASH_SIZE_MULTIPLICATION_FACTOR =
|
||||
1.0 * GrowthFactor::num / GrowthFactor::den;
|
||||
static const std::size_t MAX_BUCKET_COUNT =
|
||||
std::size_t(double(std::numeric_limits<std::size_t>::max() /
|
||||
REHASH_SIZE_MULTIPLICATION_FACTOR));
|
||||
|
||||
static_assert(REHASH_SIZE_MULTIPLICATION_FACTOR >= 1.1,
|
||||
"Growth factor should be >= 1.1.");
|
||||
|
||||
std::size_t m_mod;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
#if SIZE_MAX >= ULLONG_MAX
|
||||
#define TSL_RH_NB_PRIMES 51
|
||||
#elif SIZE_MAX >= ULONG_MAX
|
||||
#define TSL_RH_NB_PRIMES 40
|
||||
#else
|
||||
#define TSL_RH_NB_PRIMES 23
|
||||
#endif
|
||||
|
||||
inline constexpr std::array<std::size_t, TSL_RH_NB_PRIMES> PRIMES = {{
|
||||
1u,
|
||||
5u,
|
||||
17u,
|
||||
29u,
|
||||
37u,
|
||||
53u,
|
||||
67u,
|
||||
79u,
|
||||
97u,
|
||||
131u,
|
||||
193u,
|
||||
257u,
|
||||
389u,
|
||||
521u,
|
||||
769u,
|
||||
1031u,
|
||||
1543u,
|
||||
2053u,
|
||||
3079u,
|
||||
6151u,
|
||||
12289u,
|
||||
24593u,
|
||||
49157u,
|
||||
#if SIZE_MAX >= ULONG_MAX
|
||||
98317ul,
|
||||
196613ul,
|
||||
393241ul,
|
||||
786433ul,
|
||||
1572869ul,
|
||||
3145739ul,
|
||||
6291469ul,
|
||||
12582917ul,
|
||||
25165843ul,
|
||||
50331653ul,
|
||||
100663319ul,
|
||||
201326611ul,
|
||||
402653189ul,
|
||||
805306457ul,
|
||||
1610612741ul,
|
||||
3221225473ul,
|
||||
4294967291ul,
|
||||
#endif
|
||||
#if SIZE_MAX >= ULLONG_MAX
|
||||
6442450939ull,
|
||||
12884901893ull,
|
||||
25769803751ull,
|
||||
51539607551ull,
|
||||
103079215111ull,
|
||||
206158430209ull,
|
||||
412316860441ull,
|
||||
824633720831ull,
|
||||
1649267441651ull,
|
||||
3298534883309ull,
|
||||
6597069766657ull,
|
||||
#endif
|
||||
}};
|
||||
|
||||
template <unsigned int IPrime>
|
||||
static constexpr std::size_t mod(std::size_t hash) {
|
||||
return hash % PRIMES[IPrime];
|
||||
}
|
||||
|
||||
// MOD_PRIME[iprime](hash) returns hash % PRIMES[iprime]. This table allows for
|
||||
// faster modulo as the compiler can optimize the modulo code better with a
|
||||
// constant known at the compilation.
|
||||
inline constexpr std::array<std::size_t (*)(std::size_t), TSL_RH_NB_PRIMES>
|
||||
MOD_PRIME = {{
|
||||
&mod<0>, &mod<1>, &mod<2>, &mod<3>, &mod<4>, &mod<5>,
|
||||
&mod<6>, &mod<7>, &mod<8>, &mod<9>, &mod<10>, &mod<11>,
|
||||
&mod<12>, &mod<13>, &mod<14>, &mod<15>, &mod<16>, &mod<17>,
|
||||
&mod<18>, &mod<19>, &mod<20>, &mod<21>, &mod<22>,
|
||||
#if SIZE_MAX >= ULONG_MAX
|
||||
&mod<23>, &mod<24>, &mod<25>, &mod<26>, &mod<27>, &mod<28>,
|
||||
&mod<29>, &mod<30>, &mod<31>, &mod<32>, &mod<33>, &mod<34>,
|
||||
&mod<35>, &mod<36>, &mod<37>, &mod<38>, &mod<39>,
|
||||
#endif
|
||||
#if SIZE_MAX >= ULLONG_MAX
|
||||
&mod<40>, &mod<41>, &mod<42>, &mod<43>, &mod<44>, &mod<45>,
|
||||
&mod<46>, &mod<47>, &mod<48>, &mod<49>, &mod<50>,
|
||||
#endif
|
||||
}};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* Grow the hash table by using prime numbers as bucket count. Slower than
|
||||
* tsl::rh::power_of_two_growth_policy in general but will probably distribute
|
||||
* the values around better in the buckets with a poor hash function.
|
||||
*
|
||||
* To allow the compiler to optimize the modulo operation, a lookup table is
|
||||
* used with constant primes numbers.
|
||||
*
|
||||
* With a switch the code would look like:
|
||||
* \code
|
||||
* switch(iprime) { // iprime is the current prime of the hash table
|
||||
* case 0: hash % 5ul;
|
||||
* break;
|
||||
* case 1: hash % 17ul;
|
||||
* break;
|
||||
* case 2: hash % 29ul;
|
||||
* break;
|
||||
* ...
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* Due to the constant variable in the modulo the compiler is able to optimize
|
||||
* the operation by a series of multiplications, substractions and shifts.
|
||||
*
|
||||
* The 'hash % 5' could become something like 'hash - (hash * 0xCCCCCCCD) >> 34)
|
||||
* * 5' in a 64 bits environment.
|
||||
*/
|
||||
class prime_growth_policy {
|
||||
public:
|
||||
explicit prime_growth_policy(std::size_t& min_bucket_count_in_out) {
|
||||
auto it_prime = std::lower_bound(
|
||||
detail::PRIMES.begin(), detail::PRIMES.end(), min_bucket_count_in_out);
|
||||
if (it_prime == detail::PRIMES.end()) {
|
||||
TSL_RH_THROW_OR_TERMINATE(std::length_error,
|
||||
"The hash table exceeds its maximum size.");
|
||||
}
|
||||
|
||||
m_iprime = static_cast<unsigned int>(
|
||||
std::distance(detail::PRIMES.begin(), it_prime));
|
||||
if (min_bucket_count_in_out > 0) {
|
||||
min_bucket_count_in_out = *it_prime;
|
||||
} else {
|
||||
min_bucket_count_in_out = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t bucket_for_hash(std::size_t hash) const noexcept {
|
||||
return detail::MOD_PRIME[m_iprime](hash);
|
||||
}
|
||||
|
||||
std::size_t next_bucket_count() const {
|
||||
if (m_iprime + 1 >= detail::PRIMES.size()) {
|
||||
TSL_RH_THROW_OR_TERMINATE(std::length_error,
|
||||
"The hash table exceeds its maximum size.");
|
||||
}
|
||||
|
||||
return detail::PRIMES[m_iprime + 1];
|
||||
}
|
||||
|
||||
std::size_t max_bucket_count() const { return detail::PRIMES.back(); }
|
||||
|
||||
void clear() noexcept { m_iprime = 0; }
|
||||
|
||||
private:
|
||||
unsigned int m_iprime;
|
||||
|
||||
static_assert(std::numeric_limits<decltype(m_iprime)>::max() >=
|
||||
detail::PRIMES.size(),
|
||||
"The type of m_iprime is not big enough.");
|
||||
};
|
||||
|
||||
} // namespace rh
|
||||
} // namespace tsl
|
||||
|
||||
#endif
|
||||
1589
repos/ealanos/include/ealanos/util/tsl/robin_hash.h
Normal file
1589
repos/ealanos/include/ealanos/util/tsl/robin_hash.h
Normal file
File diff suppressed because it is too large
Load Diff
815
repos/ealanos/include/ealanos/util/tsl/robin_map.h
Normal file
815
repos/ealanos/include/ealanos/util/tsl/robin_map.h
Normal file
@@ -0,0 +1,815 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2017 Thibaut Goetghebuer-Planchon <tessil@gmx.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef TSL_ROBIN_MAP_H
|
||||
#define TSL_ROBIN_MAP_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "robin_hash.h"
|
||||
|
||||
namespace tsl {
|
||||
|
||||
/**
|
||||
* Implementation of a hash map using open-addressing and the robin hood hashing
|
||||
* algorithm with backward shift deletion.
|
||||
*
|
||||
* For operations modifying the hash map (insert, erase, rehash, ...), the
|
||||
* strong exception guarantee is only guaranteed when the expression
|
||||
* `std::is_nothrow_swappable<std::pair<Key, T>>::value &&
|
||||
* std::is_nothrow_move_constructible<std::pair<Key, T>>::value` is true,
|
||||
* otherwise if an exception is thrown during the swap or the move, the hash map
|
||||
* may end up in a undefined state. Per the standard a `Key` or `T` with a
|
||||
* noexcept copy constructor and no move constructor also satisfies the
|
||||
* `std::is_nothrow_move_constructible<std::pair<Key, T>>::value` criterion (and
|
||||
* will thus guarantee the strong exception for the map).
|
||||
*
|
||||
* When `StoreHash` is true, 32 bits of the hash are stored alongside the
|
||||
* values. It can improve the performance during lookups if the `KeyEqual`
|
||||
* function takes time (if it engenders a cache-miss for example) as we then
|
||||
* compare the stored hashes before comparing the keys. When
|
||||
* `tsl::rh::power_of_two_growth_policy` is used as `GrowthPolicy`, it may also
|
||||
* speed-up the rehash process as we can avoid to recalculate the hash. When it
|
||||
* is detected that storing the hash will not incur any memory penalty due to
|
||||
* alignment (i.e. `sizeof(tsl::detail_robin_hash::bucket_entry<ValueType,
|
||||
* true>) == sizeof(tsl::detail_robin_hash::bucket_entry<ValueType, false>)`)
|
||||
* and `tsl::rh::power_of_two_growth_policy` is used, the hash will be stored
|
||||
* even if `StoreHash` is false so that we can speed-up the rehash (but it will
|
||||
* not be used on lookups unless `StoreHash` is true).
|
||||
*
|
||||
* `GrowthPolicy` defines how the map grows and consequently how a hash value is
|
||||
* mapped to a bucket. By default the map uses
|
||||
* `tsl::rh::power_of_two_growth_policy`. This policy keeps the number of
|
||||
* buckets to a power of two and uses a mask to map the hash to a bucket instead
|
||||
* of the slow modulo. Other growth policies are available and you may define
|
||||
* your own growth policy, check `tsl::rh::power_of_two_growth_policy` for the
|
||||
* interface.
|
||||
*
|
||||
* `std::pair<Key, T>` must be swappable.
|
||||
*
|
||||
* `Key` and `T` must be copy and/or move constructible.
|
||||
*
|
||||
* If the destructor of `Key` or `T` throws an exception, the behaviour of the
|
||||
* class is undefined.
|
||||
*
|
||||
* Iterators invalidation:
|
||||
* - clear, operator=, reserve, rehash: always invalidate the iterators.
|
||||
* - insert, emplace, emplace_hint, operator[]: if there is an effective
|
||||
* insert, invalidate the iterators.
|
||||
* - erase: always invalidate the iterators.
|
||||
*/
|
||||
template <class Key, class T, class Hash = std::hash<Key>,
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key, T>>,
|
||||
bool StoreHash = false,
|
||||
class GrowthPolicy = tsl::rh::power_of_two_growth_policy<2>>
|
||||
class robin_map {
|
||||
private:
|
||||
template <typename U>
|
||||
using has_is_transparent = tsl::detail_robin_hash::has_is_transparent<U>;
|
||||
|
||||
class KeySelect {
|
||||
public:
|
||||
using key_type = Key;
|
||||
|
||||
const key_type& operator()(
|
||||
const std::pair<Key, T>& key_value) const noexcept {
|
||||
return key_value.first;
|
||||
}
|
||||
|
||||
key_type& operator()(std::pair<Key, T>& key_value) noexcept {
|
||||
return key_value.first;
|
||||
}
|
||||
};
|
||||
|
||||
class ValueSelect {
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
const value_type& operator()(
|
||||
const std::pair<Key, T>& key_value) const noexcept {
|
||||
return key_value.second;
|
||||
}
|
||||
|
||||
value_type& operator()(std::pair<Key, T>& key_value) noexcept {
|
||||
return key_value.second;
|
||||
}
|
||||
};
|
||||
|
||||
using ht = detail_robin_hash::robin_hash<std::pair<Key, T>, KeySelect,
|
||||
ValueSelect, Hash, KeyEqual,
|
||||
Allocator, StoreHash, GrowthPolicy>;
|
||||
|
||||
public:
|
||||
using key_type = typename ht::key_type;
|
||||
using mapped_type = T;
|
||||
using value_type = typename ht::value_type;
|
||||
using size_type = typename ht::size_type;
|
||||
using difference_type = typename ht::difference_type;
|
||||
using hasher = typename ht::hasher;
|
||||
using key_equal = typename ht::key_equal;
|
||||
using allocator_type = typename ht::allocator_type;
|
||||
using reference = typename ht::reference;
|
||||
using const_reference = typename ht::const_reference;
|
||||
using pointer = typename ht::pointer;
|
||||
using const_pointer = typename ht::const_pointer;
|
||||
using iterator = typename ht::iterator;
|
||||
using const_iterator = typename ht::const_iterator;
|
||||
|
||||
public:
|
||||
/*
|
||||
* Constructors
|
||||
*/
|
||||
robin_map() : robin_map(ht::DEFAULT_INIT_BUCKETS_SIZE) {}
|
||||
|
||||
explicit robin_map(size_type bucket_count, const Hash& hash = Hash(),
|
||||
const KeyEqual& equal = KeyEqual(),
|
||||
const Allocator& alloc = Allocator())
|
||||
: m_ht(bucket_count, hash, equal, alloc) {}
|
||||
|
||||
robin_map(size_type bucket_count, const Allocator& alloc)
|
||||
: robin_map(bucket_count, Hash(), KeyEqual(), alloc) {}
|
||||
|
||||
robin_map(size_type bucket_count, const Hash& hash, const Allocator& alloc)
|
||||
: robin_map(bucket_count, hash, KeyEqual(), alloc) {}
|
||||
|
||||
explicit robin_map(const Allocator& alloc)
|
||||
: robin_map(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {}
|
||||
|
||||
template <class InputIt>
|
||||
robin_map(InputIt first, InputIt last,
|
||||
size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
|
||||
const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual(),
|
||||
const Allocator& alloc = Allocator())
|
||||
: robin_map(bucket_count, hash, equal, alloc) {
|
||||
insert(first, last);
|
||||
}
|
||||
|
||||
template <class InputIt>
|
||||
robin_map(InputIt first, InputIt last, size_type bucket_count,
|
||||
const Allocator& alloc)
|
||||
: robin_map(first, last, bucket_count, Hash(), KeyEqual(), alloc) {}
|
||||
|
||||
template <class InputIt>
|
||||
robin_map(InputIt first, InputIt last, size_type bucket_count,
|
||||
const Hash& hash, const Allocator& alloc)
|
||||
: robin_map(first, last, bucket_count, hash, KeyEqual(), alloc) {}
|
||||
|
||||
robin_map(std::initializer_list<value_type> init,
|
||||
size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
|
||||
const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual(),
|
||||
const Allocator& alloc = Allocator())
|
||||
: robin_map(init.begin(), init.end(), bucket_count, hash, equal, alloc) {}
|
||||
|
||||
robin_map(std::initializer_list<value_type> init, size_type bucket_count,
|
||||
const Allocator& alloc)
|
||||
: robin_map(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(),
|
||||
alloc) {}
|
||||
|
||||
robin_map(std::initializer_list<value_type> init, size_type bucket_count,
|
||||
const Hash& hash, const Allocator& alloc)
|
||||
: robin_map(init.begin(), init.end(), bucket_count, hash, KeyEqual(),
|
||||
alloc) {}
|
||||
|
||||
robin_map& operator=(std::initializer_list<value_type> ilist) {
|
||||
m_ht.clear();
|
||||
|
||||
m_ht.reserve(ilist.size());
|
||||
m_ht.insert(ilist.begin(), ilist.end());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
allocator_type get_allocator() const { return m_ht.get_allocator(); }
|
||||
|
||||
/*
|
||||
* Iterators
|
||||
*/
|
||||
iterator begin() noexcept { return m_ht.begin(); }
|
||||
const_iterator begin() const noexcept { return m_ht.begin(); }
|
||||
const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
|
||||
|
||||
iterator end() noexcept { return m_ht.end(); }
|
||||
const_iterator end() const noexcept { return m_ht.end(); }
|
||||
const_iterator cend() const noexcept { return m_ht.cend(); }
|
||||
|
||||
/*
|
||||
* Capacity
|
||||
*/
|
||||
bool empty() const noexcept { return m_ht.empty(); }
|
||||
size_type size() const noexcept { return m_ht.size(); }
|
||||
size_type max_size() const noexcept { return m_ht.max_size(); }
|
||||
|
||||
/*
|
||||
* Modifiers
|
||||
*/
|
||||
void clear() noexcept { m_ht.clear(); }
|
||||
|
||||
std::pair<iterator, bool> insert(const value_type& value) {
|
||||
return m_ht.insert(value);
|
||||
}
|
||||
|
||||
template <class P, typename std::enable_if<std::is_constructible<
|
||||
value_type, P&&>::value>::type* = nullptr>
|
||||
std::pair<iterator, bool> insert(P&& value) {
|
||||
return m_ht.emplace(std::forward<P>(value));
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(value_type&& value) {
|
||||
return m_ht.insert(std::move(value));
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, const value_type& value) {
|
||||
return m_ht.insert_hint(hint, value);
|
||||
}
|
||||
|
||||
template <class P, typename std::enable_if<std::is_constructible<
|
||||
value_type, P&&>::value>::type* = nullptr>
|
||||
iterator insert(const_iterator hint, P&& value) {
|
||||
return m_ht.emplace_hint(hint, std::forward<P>(value));
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, value_type&& value) {
|
||||
return m_ht.insert_hint(hint, std::move(value));
|
||||
}
|
||||
|
||||
template <class InputIt>
|
||||
void insert(InputIt first, InputIt last) {
|
||||
m_ht.insert(first, last);
|
||||
}
|
||||
|
||||
void insert(std::initializer_list<value_type> ilist) {
|
||||
m_ht.insert(ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
template <class M>
|
||||
std::pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj) {
|
||||
return m_ht.insert_or_assign(k, std::forward<M>(obj));
|
||||
}
|
||||
|
||||
template <class M>
|
||||
std::pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj) {
|
||||
return m_ht.insert_or_assign(std::move(k), std::forward<M>(obj));
|
||||
}
|
||||
|
||||
template <class M>
|
||||
iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj) {
|
||||
return m_ht.insert_or_assign(hint, k, std::forward<M>(obj));
|
||||
}
|
||||
|
||||
template <class M>
|
||||
iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj) {
|
||||
return m_ht.insert_or_assign(hint, std::move(k), std::forward<M>(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* Due to the way elements are stored, emplace will need to move or copy the
|
||||
* key-value once. The method is equivalent to
|
||||
* insert(value_type(std::forward<Args>(args)...));
|
||||
*
|
||||
* Mainly here for compatibility with the std::unordered_map interface.
|
||||
*/
|
||||
template <class... Args>
|
||||
std::pair<iterator, bool> emplace(Args&&... args) {
|
||||
return m_ht.emplace(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Due to the way elements are stored, emplace_hint will need to move or copy
|
||||
* the key-value once. The method is equivalent to insert(hint,
|
||||
* value_type(std::forward<Args>(args)...));
|
||||
*
|
||||
* Mainly here for compatibility with the std::unordered_map interface.
|
||||
*/
|
||||
template <class... Args>
|
||||
iterator emplace_hint(const_iterator hint, Args&&... args) {
|
||||
return m_ht.emplace_hint(hint, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args) {
|
||||
return m_ht.try_emplace(k, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args) {
|
||||
return m_ht.try_emplace(std::move(k), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args) {
|
||||
return m_ht.try_emplace_hint(hint, k, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args) {
|
||||
return m_ht.try_emplace_hint(hint, std::move(k),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
iterator erase(iterator pos) { return m_ht.erase(pos); }
|
||||
iterator erase(const_iterator pos) { return m_ht.erase(pos); }
|
||||
iterator erase(const_iterator first, const_iterator last) {
|
||||
return m_ht.erase(first, last);
|
||||
}
|
||||
size_type erase(const key_type& key) { return m_ht.erase(key); }
|
||||
|
||||
/**
|
||||
* Erase the element at position 'pos'. In contrast to the regular erase()
|
||||
* function, erase_fast() does not return an iterator. This allows it to be
|
||||
* faster especially in hash tables with a low load factor, where finding the
|
||||
* next nonempty bucket would be costly.
|
||||
*/
|
||||
void erase_fast(iterator pos) { return m_ht.erase_fast(pos); }
|
||||
|
||||
/**
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup to the value if you already have the hash.
|
||||
*/
|
||||
size_type erase(const key_type& key, std::size_t precalculated_hash) {
|
||||
return m_ht.erase(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* This overload only participates in the overload resolution if the typedef
|
||||
* KeyEqual::is_transparent exists. If so, K must be hashable and comparable
|
||||
* to Key.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
size_type erase(const K& key) {
|
||||
return m_ht.erase(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc erase(const K& key)
|
||||
*
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup to the value if you already have the hash.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
size_type erase(const K& key, std::size_t precalculated_hash) {
|
||||
return m_ht.erase(key, precalculated_hash);
|
||||
}
|
||||
|
||||
void swap(robin_map& other) { other.m_ht.swap(m_ht); }
|
||||
|
||||
/*
|
||||
* Lookup
|
||||
*/
|
||||
T& at(const Key& key) { return m_ht.at(key); }
|
||||
|
||||
/**
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
T& at(const Key& key, std::size_t precalculated_hash) {
|
||||
return m_ht.at(key, precalculated_hash);
|
||||
}
|
||||
|
||||
const T& at(const Key& key) const { return m_ht.at(key); }
|
||||
|
||||
/**
|
||||
* @copydoc at(const Key& key, std::size_t precalculated_hash)
|
||||
*/
|
||||
const T& at(const Key& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.at(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* This overload only participates in the overload resolution if the typedef
|
||||
* KeyEqual::is_transparent exists. If so, K must be hashable and comparable
|
||||
* to Key.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
T& at(const K& key) {
|
||||
return m_ht.at(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc at(const K& key)
|
||||
*
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
T& at(const K& key, std::size_t precalculated_hash) {
|
||||
return m_ht.at(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc at(const K& key)
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
const T& at(const K& key) const {
|
||||
return m_ht.at(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc at(const K& key, std::size_t precalculated_hash)
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
const T& at(const K& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.at(key, precalculated_hash);
|
||||
}
|
||||
|
||||
T& operator[](const Key& key) { return m_ht[key]; }
|
||||
T& operator[](Key&& key) { return m_ht[std::move(key)]; }
|
||||
|
||||
size_type count(const Key& key) const { return m_ht.count(key); }
|
||||
|
||||
/**
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
size_type count(const Key& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.count(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* This overload only participates in the overload resolution if the typedef
|
||||
* KeyEqual::is_transparent exists. If so, K must be hashable and comparable
|
||||
* to Key.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
size_type count(const K& key) const {
|
||||
return m_ht.count(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc count(const K& key) const
|
||||
*
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
size_type count(const K& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.count(key, precalculated_hash);
|
||||
}
|
||||
|
||||
iterator find(const Key& key) { return m_ht.find(key); }
|
||||
|
||||
/**
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
iterator find(const Key& key, std::size_t precalculated_hash) {
|
||||
return m_ht.find(key, precalculated_hash);
|
||||
}
|
||||
|
||||
const_iterator find(const Key& key) const { return m_ht.find(key); }
|
||||
|
||||
/**
|
||||
* @copydoc find(const Key& key, std::size_t precalculated_hash)
|
||||
*/
|
||||
const_iterator find(const Key& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.find(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* This overload only participates in the overload resolution if the typedef
|
||||
* KeyEqual::is_transparent exists. If so, K must be hashable and comparable
|
||||
* to Key.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
iterator find(const K& key) {
|
||||
return m_ht.find(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc find(const K& key)
|
||||
*
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
iterator find(const K& key, std::size_t precalculated_hash) {
|
||||
return m_ht.find(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc find(const K& key)
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
const_iterator find(const K& key) const {
|
||||
return m_ht.find(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc find(const K& key)
|
||||
*
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
const_iterator find(const K& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.find(key, precalculated_hash);
|
||||
}
|
||||
|
||||
bool contains(const Key& key) const { return m_ht.contains(key); }
|
||||
|
||||
/**
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
bool contains(const Key& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.contains(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* This overload only participates in the overload resolution if the typedef
|
||||
* KeyEqual::is_transparent exists. If so, K must be hashable and comparable
|
||||
* to Key.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
bool contains(const K& key) const {
|
||||
return m_ht.contains(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc contains(const K& key) const
|
||||
*
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
bool contains(const K& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.contains(key, precalculated_hash);
|
||||
}
|
||||
|
||||
std::pair<iterator, iterator> equal_range(const Key& key) {
|
||||
return m_ht.equal_range(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
std::pair<iterator, iterator> equal_range(const Key& key,
|
||||
std::size_t precalculated_hash) {
|
||||
return m_ht.equal_range(key, precalculated_hash);
|
||||
}
|
||||
|
||||
std::pair<const_iterator, const_iterator> equal_range(const Key& key) const {
|
||||
return m_ht.equal_range(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
|
||||
*/
|
||||
std::pair<const_iterator, const_iterator> equal_range(
|
||||
const Key& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.equal_range(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* This overload only participates in the overload resolution if the typedef
|
||||
* KeyEqual::is_transparent exists. If so, K must be hashable and comparable
|
||||
* to Key.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
std::pair<iterator, iterator> equal_range(const K& key) {
|
||||
return m_ht.equal_range(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc equal_range(const K& key)
|
||||
*
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
std::pair<iterator, iterator> equal_range(const K& key,
|
||||
std::size_t precalculated_hash) {
|
||||
return m_ht.equal_range(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc equal_range(const K& key)
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
std::pair<const_iterator, const_iterator> equal_range(const K& key) const {
|
||||
return m_ht.equal_range(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc equal_range(const K& key, std::size_t precalculated_hash)
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
std::pair<const_iterator, const_iterator> equal_range(
|
||||
const K& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.equal_range(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* Bucket interface
|
||||
*/
|
||||
size_type bucket_count() const { return m_ht.bucket_count(); }
|
||||
size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
|
||||
|
||||
/*
|
||||
* Hash policy
|
||||
*/
|
||||
float load_factor() const { return m_ht.load_factor(); }
|
||||
|
||||
float min_load_factor() const { return m_ht.min_load_factor(); }
|
||||
float max_load_factor() const { return m_ht.max_load_factor(); }
|
||||
|
||||
/**
|
||||
* Set the `min_load_factor` to `ml`. When the `load_factor` of the map goes
|
||||
* below `min_load_factor` after some erase operations, the map will be
|
||||
* shrunk when an insertion occurs. The erase method itself never shrinks
|
||||
* the map.
|
||||
*
|
||||
* The default value of `min_load_factor` is 0.0f, the map never shrinks by
|
||||
* default.
|
||||
*/
|
||||
void min_load_factor(float ml) { m_ht.min_load_factor(ml); }
|
||||
void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
|
||||
|
||||
void rehash(size_type count_) { m_ht.rehash(count_); }
|
||||
void reserve(size_type count_) { m_ht.reserve(count_); }
|
||||
|
||||
/*
|
||||
* Observers
|
||||
*/
|
||||
hasher hash_function() const { return m_ht.hash_function(); }
|
||||
key_equal key_eq() const { return m_ht.key_eq(); }
|
||||
|
||||
/*
|
||||
* Other
|
||||
*/
|
||||
|
||||
/**
|
||||
* Convert a const_iterator to an iterator.
|
||||
*/
|
||||
iterator mutable_iterator(const_iterator pos) {
|
||||
return m_ht.mutable_iterator(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the map through the `serializer` parameter.
|
||||
*
|
||||
* The `serializer` parameter must be a function object that supports the
|
||||
* following call:
|
||||
* - `template<typename U> void operator()(const U& value);` where the types
|
||||
* `std::int16_t`, `std::uint32_t`, `std::uint64_t`, `float` and
|
||||
* `std::pair<Key, T>` must be supported for U.
|
||||
*
|
||||
* The implementation leaves binary compatibility (endianness, IEEE 754 for
|
||||
* floats, ...) of the types it serializes in the hands of the `Serializer`
|
||||
* function object if compatibility is required.
|
||||
*/
|
||||
template <class Serializer>
|
||||
void serialize(Serializer& serializer) const {
|
||||
m_ht.serialize(serializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize a previously serialized map through the `deserializer`
|
||||
* parameter.
|
||||
*
|
||||
* The `deserializer` parameter must be a function object that supports the
|
||||
* following call:
|
||||
* - `template<typename U> U operator()();` where the types `std::int16_t`,
|
||||
* `std::uint32_t`, `std::uint64_t`, `float` and `std::pair<Key, T>` must be
|
||||
* supported for U.
|
||||
*
|
||||
* If the deserialized hash map type is hash compatible with the serialized
|
||||
* map, the deserialization process can be sped up by setting
|
||||
* `hash_compatible` to true. To be hash compatible, the Hash, KeyEqual and
|
||||
* GrowthPolicy must behave the same way than the ones used on the serialized
|
||||
* map and the StoreHash must have the same value. The `std::size_t` must also
|
||||
* be of the same size as the one on the platform used to serialize the map.
|
||||
* If these criteria are not met, the behaviour is undefined with
|
||||
* `hash_compatible` sets to true.
|
||||
*
|
||||
* The behaviour is undefined if the type `Key` and `T` of the `robin_map` are
|
||||
* not the same as the types used during serialization.
|
||||
*
|
||||
* The implementation leaves binary compatibility (endianness, IEEE 754 for
|
||||
* floats, size of int, ...) of the types it deserializes in the hands of the
|
||||
* `Deserializer` function object if compatibility is required.
|
||||
*/
|
||||
template <class Deserializer>
|
||||
static robin_map deserialize(Deserializer& deserializer,
|
||||
bool hash_compatible = false) {
|
||||
robin_map map(0);
|
||||
map.m_ht.deserialize(deserializer, hash_compatible);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
friend bool operator==(const robin_map& lhs, const robin_map& rhs) {
|
||||
if (lhs.size() != rhs.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& element_lhs : lhs) {
|
||||
const auto it_element_rhs = rhs.find(element_lhs.first);
|
||||
if (it_element_rhs == rhs.cend() ||
|
||||
element_lhs.second != it_element_rhs->second) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
friend bool operator!=(const robin_map& lhs, const robin_map& rhs) {
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
friend void swap(robin_map& lhs, robin_map& rhs) { lhs.swap(rhs); }
|
||||
|
||||
private:
|
||||
ht m_ht;
|
||||
};
|
||||
|
||||
/**
|
||||
* Same as `tsl::robin_map<Key, T, Hash, KeyEqual, Allocator, StoreHash,
|
||||
* tsl::rh::prime_growth_policy>`.
|
||||
*/
|
||||
template <class Key, class T, class Hash = std::hash<Key>,
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key, T>>,
|
||||
bool StoreHash = false>
|
||||
using robin_pg_map = robin_map<Key, T, Hash, KeyEqual, Allocator, StoreHash,
|
||||
tsl::rh::prime_growth_policy>;
|
||||
|
||||
} // end namespace tsl
|
||||
|
||||
#endif
|
||||
668
repos/ealanos/include/ealanos/util/tsl/robin_set.h
Normal file
668
repos/ealanos/include/ealanos/util/tsl/robin_set.h
Normal file
@@ -0,0 +1,668 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2017 Thibaut Goetghebuer-Planchon <tessil@gmx.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef TSL_ROBIN_SET_H
|
||||
#define TSL_ROBIN_SET_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "robin_hash.h"
|
||||
|
||||
namespace tsl {
|
||||
|
||||
/**
|
||||
* Implementation of a hash set using open-addressing and the robin hood hashing
|
||||
* algorithm with backward shift deletion.
|
||||
*
|
||||
* For operations modifying the hash set (insert, erase, rehash, ...), the
|
||||
* strong exception guarantee is only guaranteed when the expression
|
||||
* `std::is_nothrow_swappable<Key>::value &&
|
||||
* std::is_nothrow_move_constructible<Key>::value` is true, otherwise if an
|
||||
* exception is thrown during the swap or the move, the hash set may end up in a
|
||||
* undefined state. Per the standard a `Key` with a noexcept copy constructor
|
||||
* and no move constructor also satisfies the
|
||||
* `std::is_nothrow_move_constructible<Key>::value` criterion (and will thus
|
||||
* guarantee the strong exception for the set).
|
||||
*
|
||||
* When `StoreHash` is true, 32 bits of the hash are stored alongside the
|
||||
* values. It can improve the performance during lookups if the `KeyEqual`
|
||||
* function takes time (or engenders a cache-miss for example) as we then
|
||||
* compare the stored hashes before comparing the keys. When
|
||||
* `tsl::rh::power_of_two_growth_policy` is used as `GrowthPolicy`, it may also
|
||||
* speed-up the rehash process as we can avoid to recalculate the hash. When it
|
||||
* is detected that storing the hash will not incur any memory penalty due to
|
||||
* alignment (i.e. `sizeof(tsl::detail_robin_hash::bucket_entry<ValueType,
|
||||
* true>) == sizeof(tsl::detail_robin_hash::bucket_entry<ValueType, false>)`)
|
||||
* and `tsl::rh::power_of_two_growth_policy` is used, the hash will be stored
|
||||
* even if `StoreHash` is false so that we can speed-up the rehash (but it will
|
||||
* not be used on lookups unless `StoreHash` is true).
|
||||
*
|
||||
* `GrowthPolicy` defines how the set grows and consequently how a hash value is
|
||||
* mapped to a bucket. By default the set uses
|
||||
* `tsl::rh::power_of_two_growth_policy`. This policy keeps the number of
|
||||
* buckets to a power of two and uses a mask to set the hash to a bucket instead
|
||||
* of the slow modulo. Other growth policies are available and you may define
|
||||
* your own growth policy, check `tsl::rh::power_of_two_growth_policy` for the
|
||||
* interface.
|
||||
*
|
||||
* `Key` must be swappable.
|
||||
*
|
||||
* `Key` must be copy and/or move constructible.
|
||||
*
|
||||
* If the destructor of `Key` throws an exception, the behaviour of the class is
|
||||
* undefined.
|
||||
*
|
||||
* Iterators invalidation:
|
||||
* - clear, operator=, reserve, rehash: always invalidate the iterators.
|
||||
* - insert, emplace, emplace_hint, operator[]: if there is an effective
|
||||
* insert, invalidate the iterators.
|
||||
* - erase: always invalidate the iterators.
|
||||
*/
|
||||
template <class Key, class Hash = std::hash<Key>,
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<Key>, bool StoreHash = false,
|
||||
class GrowthPolicy = tsl::rh::power_of_two_growth_policy<2>>
|
||||
class robin_set {
|
||||
private:
|
||||
template <typename U>
|
||||
using has_is_transparent = tsl::detail_robin_hash::has_is_transparent<U>;
|
||||
|
||||
class KeySelect {
|
||||
public:
|
||||
using key_type = Key;
|
||||
|
||||
const key_type& operator()(const Key& key) const noexcept { return key; }
|
||||
|
||||
key_type& operator()(Key& key) noexcept { return key; }
|
||||
};
|
||||
|
||||
using ht = detail_robin_hash::robin_hash<Key, KeySelect, void, Hash, KeyEqual,
|
||||
Allocator, StoreHash, GrowthPolicy>;
|
||||
|
||||
public:
|
||||
using key_type = typename ht::key_type;
|
||||
using value_type = typename ht::value_type;
|
||||
using size_type = typename ht::size_type;
|
||||
using difference_type = typename ht::difference_type;
|
||||
using hasher = typename ht::hasher;
|
||||
using key_equal = typename ht::key_equal;
|
||||
using allocator_type = typename ht::allocator_type;
|
||||
using reference = typename ht::reference;
|
||||
using const_reference = typename ht::const_reference;
|
||||
using pointer = typename ht::pointer;
|
||||
using const_pointer = typename ht::const_pointer;
|
||||
using iterator = typename ht::iterator;
|
||||
using const_iterator = typename ht::const_iterator;
|
||||
|
||||
/*
|
||||
* Constructors
|
||||
*/
|
||||
robin_set() : robin_set(ht::DEFAULT_INIT_BUCKETS_SIZE) {}
|
||||
|
||||
explicit robin_set(size_type bucket_count, const Hash& hash = Hash(),
|
||||
const KeyEqual& equal = KeyEqual(),
|
||||
const Allocator& alloc = Allocator())
|
||||
: m_ht(bucket_count, hash, equal, alloc) {}
|
||||
|
||||
robin_set(size_type bucket_count, const Allocator& alloc)
|
||||
: robin_set(bucket_count, Hash(), KeyEqual(), alloc) {}
|
||||
|
||||
robin_set(size_type bucket_count, const Hash& hash, const Allocator& alloc)
|
||||
: robin_set(bucket_count, hash, KeyEqual(), alloc) {}
|
||||
|
||||
explicit robin_set(const Allocator& alloc)
|
||||
: robin_set(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {}
|
||||
|
||||
template <class InputIt>
|
||||
robin_set(InputIt first, InputIt last,
|
||||
size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
|
||||
const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual(),
|
||||
const Allocator& alloc = Allocator())
|
||||
: robin_set(bucket_count, hash, equal, alloc) {
|
||||
insert(first, last);
|
||||
}
|
||||
|
||||
template <class InputIt>
|
||||
robin_set(InputIt first, InputIt last, size_type bucket_count,
|
||||
const Allocator& alloc)
|
||||
: robin_set(first, last, bucket_count, Hash(), KeyEqual(), alloc) {}
|
||||
|
||||
template <class InputIt>
|
||||
robin_set(InputIt first, InputIt last, size_type bucket_count,
|
||||
const Hash& hash, const Allocator& alloc)
|
||||
: robin_set(first, last, bucket_count, hash, KeyEqual(), alloc) {}
|
||||
|
||||
robin_set(std::initializer_list<value_type> init,
|
||||
size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
|
||||
const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual(),
|
||||
const Allocator& alloc = Allocator())
|
||||
: robin_set(init.begin(), init.end(), bucket_count, hash, equal, alloc) {}
|
||||
|
||||
robin_set(std::initializer_list<value_type> init, size_type bucket_count,
|
||||
const Allocator& alloc)
|
||||
: robin_set(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(),
|
||||
alloc) {}
|
||||
|
||||
robin_set(std::initializer_list<value_type> init, size_type bucket_count,
|
||||
const Hash& hash, const Allocator& alloc)
|
||||
: robin_set(init.begin(), init.end(), bucket_count, hash, KeyEqual(),
|
||||
alloc) {}
|
||||
|
||||
robin_set& operator=(std::initializer_list<value_type> ilist) {
|
||||
m_ht.clear();
|
||||
|
||||
m_ht.reserve(ilist.size());
|
||||
m_ht.insert(ilist.begin(), ilist.end());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
allocator_type get_allocator() const { return m_ht.get_allocator(); }
|
||||
|
||||
/*
|
||||
* Iterators
|
||||
*/
|
||||
iterator begin() noexcept { return m_ht.begin(); }
|
||||
const_iterator begin() const noexcept { return m_ht.begin(); }
|
||||
const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
|
||||
|
||||
iterator end() noexcept { return m_ht.end(); }
|
||||
const_iterator end() const noexcept { return m_ht.end(); }
|
||||
const_iterator cend() const noexcept { return m_ht.cend(); }
|
||||
|
||||
/*
|
||||
* Capacity
|
||||
*/
|
||||
bool empty() const noexcept { return m_ht.empty(); }
|
||||
size_type size() const noexcept { return m_ht.size(); }
|
||||
size_type max_size() const noexcept { return m_ht.max_size(); }
|
||||
|
||||
/*
|
||||
* Modifiers
|
||||
*/
|
||||
void clear() noexcept { m_ht.clear(); }
|
||||
|
||||
std::pair<iterator, bool> insert(const value_type& value) {
|
||||
return m_ht.insert(value);
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(value_type&& value) {
|
||||
return m_ht.insert(std::move(value));
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, const value_type& value) {
|
||||
return m_ht.insert_hint(hint, value);
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, value_type&& value) {
|
||||
return m_ht.insert_hint(hint, std::move(value));
|
||||
}
|
||||
|
||||
template <class InputIt>
|
||||
void insert(InputIt first, InputIt last) {
|
||||
m_ht.insert(first, last);
|
||||
}
|
||||
|
||||
void insert(std::initializer_list<value_type> ilist) {
|
||||
m_ht.insert(ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* Due to the way elements are stored, emplace will need to move or copy the
|
||||
* key-value once. The method is equivalent to
|
||||
* insert(value_type(std::forward<Args>(args)...));
|
||||
*
|
||||
* Mainly here for compatibility with the std::unordered_map interface.
|
||||
*/
|
||||
template <class... Args>
|
||||
std::pair<iterator, bool> emplace(Args&&... args) {
|
||||
return m_ht.emplace(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Due to the way elements are stored, emplace_hint will need to move or copy
|
||||
* the key-value once. The method is equivalent to insert(hint,
|
||||
* value_type(std::forward<Args>(args)...));
|
||||
*
|
||||
* Mainly here for compatibility with the std::unordered_map interface.
|
||||
*/
|
||||
template <class... Args>
|
||||
iterator emplace_hint(const_iterator hint, Args&&... args) {
|
||||
return m_ht.emplace_hint(hint, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
iterator erase(iterator pos) { return m_ht.erase(pos); }
|
||||
iterator erase(const_iterator pos) { return m_ht.erase(pos); }
|
||||
iterator erase(const_iterator first, const_iterator last) {
|
||||
return m_ht.erase(first, last);
|
||||
}
|
||||
size_type erase(const key_type& key) { return m_ht.erase(key); }
|
||||
|
||||
/**
|
||||
* Erase the element at position 'pos'. In contrast to the regular erase()
|
||||
* function, erase_fast() does not return an iterator. This allows it to be
|
||||
* faster especially in hash sets with a low load factor, where finding the
|
||||
* next nonempty bucket would be costly.
|
||||
*/
|
||||
void erase_fast(iterator pos) { return m_ht.erase_fast(pos); }
|
||||
|
||||
/**
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup to the value if you already have the hash.
|
||||
*/
|
||||
size_type erase(const key_type& key, std::size_t precalculated_hash) {
|
||||
return m_ht.erase(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* This overload only participates in the overload resolution if the typedef
|
||||
* KeyEqual::is_transparent exists. If so, K must be hashable and comparable
|
||||
* to Key.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
size_type erase(const K& key) {
|
||||
return m_ht.erase(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc erase(const K& key)
|
||||
*
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup to the value if you already have the hash.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
size_type erase(const K& key, std::size_t precalculated_hash) {
|
||||
return m_ht.erase(key, precalculated_hash);
|
||||
}
|
||||
|
||||
void swap(robin_set& other) { other.m_ht.swap(m_ht); }
|
||||
|
||||
/*
|
||||
* Lookup
|
||||
*/
|
||||
size_type count(const Key& key) const { return m_ht.count(key); }
|
||||
|
||||
/**
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
size_type count(const Key& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.count(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* This overload only participates in the overload resolution if the typedef
|
||||
* KeyEqual::is_transparent exists. If so, K must be hashable and comparable
|
||||
* to Key.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
size_type count(const K& key) const {
|
||||
return m_ht.count(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc count(const K& key) const
|
||||
*
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
size_type count(const K& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.count(key, precalculated_hash);
|
||||
}
|
||||
|
||||
iterator find(const Key& key) { return m_ht.find(key); }
|
||||
|
||||
/**
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
iterator find(const Key& key, std::size_t precalculated_hash) {
|
||||
return m_ht.find(key, precalculated_hash);
|
||||
}
|
||||
|
||||
const_iterator find(const Key& key) const { return m_ht.find(key); }
|
||||
|
||||
/**
|
||||
* @copydoc find(const Key& key, std::size_t precalculated_hash)
|
||||
*/
|
||||
const_iterator find(const Key& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.find(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* This overload only participates in the overload resolution if the typedef
|
||||
* KeyEqual::is_transparent exists. If so, K must be hashable and comparable
|
||||
* to Key.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
iterator find(const K& key) {
|
||||
return m_ht.find(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc find(const K& key)
|
||||
*
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
iterator find(const K& key, std::size_t precalculated_hash) {
|
||||
return m_ht.find(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc find(const K& key)
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
const_iterator find(const K& key) const {
|
||||
return m_ht.find(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc find(const K& key)
|
||||
*
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
const_iterator find(const K& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.find(key, precalculated_hash);
|
||||
}
|
||||
|
||||
bool contains(const Key& key) const { return m_ht.contains(key); }
|
||||
|
||||
/**
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
bool contains(const Key& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.contains(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* This overload only participates in the overload resolution if the typedef
|
||||
* KeyEqual::is_transparent exists. If so, K must be hashable and comparable
|
||||
* to Key.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
bool contains(const K& key) const {
|
||||
return m_ht.contains(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc contains(const K& key) const
|
||||
*
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
bool contains(const K& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.contains(key, precalculated_hash);
|
||||
}
|
||||
|
||||
std::pair<iterator, iterator> equal_range(const Key& key) {
|
||||
return m_ht.equal_range(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
std::pair<iterator, iterator> equal_range(const Key& key,
|
||||
std::size_t precalculated_hash) {
|
||||
return m_ht.equal_range(key, precalculated_hash);
|
||||
}
|
||||
|
||||
std::pair<const_iterator, const_iterator> equal_range(const Key& key) const {
|
||||
return m_ht.equal_range(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
|
||||
*/
|
||||
std::pair<const_iterator, const_iterator> equal_range(
|
||||
const Key& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.equal_range(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* This overload only participates in the overload resolution if the typedef
|
||||
* KeyEqual::is_transparent exists. If so, K must be hashable and comparable
|
||||
* to Key.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
std::pair<iterator, iterator> equal_range(const K& key) {
|
||||
return m_ht.equal_range(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc equal_range(const K& key)
|
||||
*
|
||||
* Use the hash value 'precalculated_hash' instead of hashing the key. The
|
||||
* hash value should be the same as hash_function()(key). Useful to speed-up
|
||||
* the lookup if you already have the hash.
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
std::pair<iterator, iterator> equal_range(const K& key,
|
||||
std::size_t precalculated_hash) {
|
||||
return m_ht.equal_range(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc equal_range(const K& key)
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
std::pair<const_iterator, const_iterator> equal_range(const K& key) const {
|
||||
return m_ht.equal_range(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc equal_range(const K& key, std::size_t precalculated_hash)
|
||||
*/
|
||||
template <
|
||||
class K, class KE = KeyEqual,
|
||||
typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
|
||||
std::pair<const_iterator, const_iterator> equal_range(
|
||||
const K& key, std::size_t precalculated_hash) const {
|
||||
return m_ht.equal_range(key, precalculated_hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* Bucket interface
|
||||
*/
|
||||
size_type bucket_count() const { return m_ht.bucket_count(); }
|
||||
size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
|
||||
|
||||
/*
|
||||
* Hash policy
|
||||
*/
|
||||
float load_factor() const { return m_ht.load_factor(); }
|
||||
|
||||
float min_load_factor() const { return m_ht.min_load_factor(); }
|
||||
float max_load_factor() const { return m_ht.max_load_factor(); }
|
||||
|
||||
/**
|
||||
* Set the `min_load_factor` to `ml`. When the `load_factor` of the set goes
|
||||
* below `min_load_factor` after some erase operations, the set will be
|
||||
* shrunk when an insertion occurs. The erase method itself never shrinks
|
||||
* the set.
|
||||
*
|
||||
* The default value of `min_load_factor` is 0.0f, the set never shrinks by
|
||||
* default.
|
||||
*/
|
||||
void min_load_factor(float ml) { m_ht.min_load_factor(ml); }
|
||||
void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
|
||||
|
||||
void rehash(size_type count_) { m_ht.rehash(count_); }
|
||||
void reserve(size_type count_) { m_ht.reserve(count_); }
|
||||
|
||||
/*
|
||||
* Observers
|
||||
*/
|
||||
hasher hash_function() const { return m_ht.hash_function(); }
|
||||
key_equal key_eq() const { return m_ht.key_eq(); }
|
||||
|
||||
/*
|
||||
* Other
|
||||
*/
|
||||
|
||||
/**
|
||||
* Convert a const_iterator to an iterator.
|
||||
*/
|
||||
iterator mutable_iterator(const_iterator pos) {
|
||||
return m_ht.mutable_iterator(pos);
|
||||
}
|
||||
|
||||
friend bool operator==(const robin_set& lhs, const robin_set& rhs) {
|
||||
if (lhs.size() != rhs.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& element_lhs : lhs) {
|
||||
const auto it_element_rhs = rhs.find(element_lhs);
|
||||
if (it_element_rhs == rhs.cend()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the set through the `serializer` parameter.
|
||||
*
|
||||
* The `serializer` parameter must be a function object that supports the
|
||||
* following call:
|
||||
* - `template<typename U> void operator()(const U& value);` where the types
|
||||
* `std::int16_t`, `std::uint32_t`, `std::uint64_t`, `float` and `Key` must be
|
||||
* supported for U.
|
||||
*
|
||||
* The implementation leaves binary compatibility (endianness, IEEE 754 for
|
||||
* floats, ...) of the types it serializes in the hands of the `Serializer`
|
||||
* function object if compatibility is required.
|
||||
*/
|
||||
template <class Serializer>
|
||||
void serialize(Serializer& serializer) const {
|
||||
m_ht.serialize(serializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize a previously serialized set through the `deserializer`
|
||||
* parameter.
|
||||
*
|
||||
* The `deserializer` parameter must be a function object that supports the
|
||||
* following call:
|
||||
* - `template<typename U> U operator()();` where the types `std::int16_t`,
|
||||
* `std::uint32_t`, `std::uint64_t`, `float` and `Key` must be supported for
|
||||
* U.
|
||||
*
|
||||
* If the deserialized hash set type is hash compatible with the serialized
|
||||
* set, the deserialization process can be sped up by setting
|
||||
* `hash_compatible` to true. To be hash compatible, the Hash, KeyEqual and
|
||||
* GrowthPolicy must behave the same way than the ones used on the serialized
|
||||
* set and the StoreHash must have the same value. The `std::size_t` must also
|
||||
* be of the same size as the one on the platform used to serialize the set.
|
||||
* If these criteria are not met, the behaviour is undefined with
|
||||
* `hash_compatible` sets to true.
|
||||
*
|
||||
* The behaviour is undefined if the type `Key` of the `robin_set` is not the
|
||||
* same as the type used during serialization.
|
||||
*
|
||||
* The implementation leaves binary compatibility (endianness, IEEE 754 for
|
||||
* floats, size of int, ...) of the types it deserializes in the hands of the
|
||||
* `Deserializer` function object if compatibility is required.
|
||||
*/
|
||||
template <class Deserializer>
|
||||
static robin_set deserialize(Deserializer& deserializer,
|
||||
bool hash_compatible = false) {
|
||||
robin_set set(0);
|
||||
set.m_ht.deserialize(deserializer, hash_compatible);
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
friend bool operator!=(const robin_set& lhs, const robin_set& rhs) {
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
friend void swap(robin_set& lhs, robin_set& rhs) { lhs.swap(rhs); }
|
||||
|
||||
private:
|
||||
ht m_ht;
|
||||
};
|
||||
|
||||
/**
|
||||
* Same as `tsl::robin_set<Key, Hash, KeyEqual, Allocator, StoreHash,
|
||||
* tsl::rh::prime_growth_policy>`.
|
||||
*/
|
||||
template <class Key, class Hash = std::hash<Key>,
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<Key>, bool StoreHash = false>
|
||||
using robin_pg_set = robin_set<Key, Hash, KeyEqual, Allocator, StoreHash,
|
||||
tsl::rh::prime_growth_policy>;
|
||||
|
||||
} // end namespace tsl
|
||||
|
||||
#endif
|
||||
28
repos/ealanos/lib/mk/mxtasking.mk
Normal file
28
repos/ealanos/lib/mk/mxtasking.mk
Normal file
@@ -0,0 +1,28 @@
|
||||
MXTASKING_DIR := $(REP_DIR)/src/lib/mx
|
||||
GENODE_GCC_TOOLCHAIN_DIR := /usr/local/genode/tool/23.05
|
||||
|
||||
SRC_CC = $(shell find $(MXTASKING_DIR) -name "*.cpp")
|
||||
vpath %.cpp $(MXTASKING_DIR)
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/lib
|
||||
INC_DIR += $(REP_DIR)/include
|
||||
INC_DIR += $(REP_DIR)/include/ealanos/util
|
||||
INC_DIR += $(call select_from_repositories,src/lib/libc)
|
||||
INC_DIR += $(call select_from_repositories,src/lib/libc)/spec/x86_64
|
||||
vpath %.h ${INC_DIR}
|
||||
|
||||
CUSTOM_CXX = /usr/local/genode/tool/bin/clang++
|
||||
CUSTOM_CC = /usr/local/genode/tool/bin/clang
|
||||
|
||||
CC_OPT += --target=x86_64-genode --sysroot=/does/not/exist --gcc-toolchain=$(GENODE_GCC_TOOLCHAIN_DIR) -DCLANG_CXX11_ATOMICS
|
||||
CC_OPT += -std=c++20 -pedantic -Wall \
|
||||
-Wno-invalid-offsetof -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization \
|
||||
-Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Woverloaded-virtual \
|
||||
-Wredundant-decls -Wshadow -Wsign-promo -Wstrict-overflow=5 -Wswitch-default -Wundef \
|
||||
-Wno-unused -Wold-style-cast -Wno-uninitialized -O2 -g
|
||||
|
||||
CC_OPT += $(addprefix -I ,$(INC_DIR))
|
||||
CC_CXX_WARN_STRICT =
|
||||
|
||||
LIBS += base libm libc stdcxx
|
||||
EXT_OBJECTS += /usr/local/genode/tool/lib/clang/14.0.5/lib/linux/libclang_rt.builtins-x86_64.a /usr/local/genode/tool/lib/libatomic.a
|
||||
22
repos/ealanos/src/lib/mx/LICENSE
Normal file
22
repos/ealanos/src/lib/mx/LICENSE
Normal file
@@ -0,0 +1,22 @@
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2025 Michael Müller
|
||||
Copyright (c) 2023 Jan Mühlig
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
33
repos/ealanos/src/lib/mx/README.md
Normal file
33
repos/ealanos/src/lib/mx/README.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# MxTasking
|
||||
|
||||
The *MxTasking* lib implements the task engine.
|
||||
|
||||
## Structure
|
||||
### Memory
|
||||
The memory component can be found in the [memory](memory) folder.
|
||||
It implements different memory allocators (the [fixed size allocator](memory/fixed_size_allocator.h) mainly for tasks with a static size and the [dynamic size allocator](memory/dynamic_size_allocator.h) for variable sized data objects).
|
||||
Further, epoch-based memory reclamation is implemented by the [epoch manager](memory/reclamation/epoch_manager.h).
|
||||
|
||||
### Queue
|
||||
Different (task-) queues can be found in the [queue](queue) folder.
|
||||
It provides
|
||||
* a [non-synchronized single-core queue](queue/list.h) (for fast core-local dispatching),
|
||||
* a [multi-producer single-consumer queue](queue/mpsc.h) (for dispatching tasks to remote cores),
|
||||
* and a [(bound) multi-producer multi-consumer queue](queue/bound_mpmc.h) (mainly used for memory-reclamation).
|
||||
|
||||
### Resource
|
||||
The resource component can be found in the [resource](resource) folder.
|
||||
This package encapsulates
|
||||
* [annotations for resources](resource/annotation.h),
|
||||
* the [resource builder](resource/builder.h) which creates and schedules resources,
|
||||
* a [tagged pointer](resource/ptr.h) instance that links to resources including information (synchronization method and worker id),
|
||||
* and the [resource interface](resource/resource_interface.h) that has to be implemented by each to synchronized resource.
|
||||
|
||||
### Synchronization
|
||||
The synchronization component can be found in the [synchronization](synchronization) folder.
|
||||
This package provides different synchronization methods ([optimistic lock](synchronization/optimistic_lock.h), [rw lock](synchronization/rw_spinlock.h), [spinlock](synchronization/spinlock.h)) and [structures to define the required synchronization level](synchronization/synchronization.h).
|
||||
|
||||
### Tasking
|
||||
The tasking core can be found in the [tasking](tasking) folder.
|
||||
For more information see the tasking-specific [readme](tasking/README.md).
|
||||
|
||||
9
repos/ealanos/src/lib/mx/io/network/config.h
Normal file
9
repos/ealanos/src/lib/mx/io/network/config.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
namespace mx::io::network {
|
||||
class config
|
||||
{
|
||||
public:
|
||||
static constexpr auto max_connections() noexcept { return 64U; }
|
||||
};
|
||||
} // namespace mx::io::network
|
||||
153
repos/ealanos/src/lib/mx/io/network/server.cpp
Normal file
153
repos/ealanos/src/lib/mx/io/network/server.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
#include "server.h"
|
||||
#include <limits>
|
||||
#include <mx/tasking/runtime.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace mx::io::network;
|
||||
|
||||
Server::Server(std::unique_ptr<MessageHandler> &&message_handler, const std::uint16_t port,
|
||||
const std::uint16_t count_channels) noexcept
|
||||
: _port(port), _socket(-1), _client_sockets({0U}), _message_handler(std::move(message_handler)),
|
||||
_count_channels(count_channels)
|
||||
{
|
||||
this->_buffer.fill('\0');
|
||||
}
|
||||
bool Server::listen()
|
||||
{
|
||||
this->_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (this->_socket == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto option = std::int32_t{1};
|
||||
if (setsockopt(this->_socket, SOL_SOCKET, SO_REUSEADDR, &option, socklen_t{sizeof(std::int32_t)}) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto address = sockaddr_in{};
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
address.sin_port = htons(this->_port);
|
||||
|
||||
if (bind(this->_socket, reinterpret_cast<sockaddr *>(&address), sizeof(sockaddr_in)) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::listen(this->_socket, 3) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto address_length = socklen_t{sizeof(sockaddr_in)};
|
||||
auto socket_descriptors = fd_set{};
|
||||
auto max_socket_descriptor = this->_socket;
|
||||
auto client_socket = std::int32_t{-1};
|
||||
|
||||
while (this->_is_running)
|
||||
{
|
||||
FD_ZERO(&socket_descriptors); // NOLINT
|
||||
FD_SET(this->_socket, &socket_descriptors);
|
||||
|
||||
for (auto &socket_descriptor : this->_client_sockets)
|
||||
{
|
||||
if (socket_descriptor > 0)
|
||||
{
|
||||
FD_SET(socket_descriptor, &socket_descriptors);
|
||||
}
|
||||
|
||||
max_socket_descriptor = std::max(max_socket_descriptor, std::int32_t(socket_descriptor));
|
||||
}
|
||||
|
||||
auto timeout = timeval{};
|
||||
timeout.tv_usec = 10000;
|
||||
const auto count_ready_selectors =
|
||||
select(max_socket_descriptor + 1, &socket_descriptors, nullptr, nullptr, &timeout);
|
||||
|
||||
if (count_ready_selectors > 0)
|
||||
{
|
||||
if (FD_ISSET(this->_socket, &socket_descriptors))
|
||||
{
|
||||
if ((client_socket = accept(this->_socket, reinterpret_cast<sockaddr *>(&address), &address_length)) <
|
||||
0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this->add_client(client_socket);
|
||||
}
|
||||
|
||||
for (auto i = 0U; i < this->_client_sockets.size(); ++i)
|
||||
{
|
||||
const auto client = this->_client_sockets[i];
|
||||
if (FD_ISSET(client, &socket_descriptors))
|
||||
{
|
||||
const auto read_bytes = read(client, this->_buffer.data(), this->_buffer.size());
|
||||
if (read_bytes == 0U)
|
||||
{
|
||||
::close(client);
|
||||
this->_client_sockets[i] = 0U;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy incoming data locally.
|
||||
auto message = std::string(this->_buffer.data(), read_bytes);
|
||||
|
||||
// Spawn task that processes the message.
|
||||
auto *task = new MessageHandlerTask(*this->_message_handler.get(), i, std::move(message));
|
||||
task->annotate(std::uint16_t(this->_next_worker_id.fetch_add(1U) % this->_count_channels));
|
||||
tasking::runtime::spawn(*task);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto client : this->_client_sockets)
|
||||
{
|
||||
if (client > 0)
|
||||
{
|
||||
::close(client);
|
||||
}
|
||||
}
|
||||
::close(this->_socket);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Server::send(const std::uint32_t client_id, std::string &&message)
|
||||
{
|
||||
const auto length = std::uint64_t(message.size());
|
||||
auto response = std::string(length + sizeof(length), '\0');
|
||||
|
||||
// Write header
|
||||
std::memcpy(response.data(), static_cast<const void *>(&length), sizeof(length));
|
||||
|
||||
// Write data
|
||||
std::memmove(response.data() + sizeof(length), message.data(), length);
|
||||
|
||||
::send(this->_client_sockets[client_id], response.c_str(), response.length(), 0);
|
||||
}
|
||||
|
||||
std::uint16_t Server::add_client(const std::int32_t client_socket)
|
||||
{
|
||||
for (auto i = 0U; i < this->_client_sockets.size(); ++i)
|
||||
{
|
||||
if (this->_client_sockets[i] == 0U)
|
||||
{
|
||||
this->_client_sockets[i] = client_socket;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return std::numeric_limits<std::uint16_t>::max();
|
||||
}
|
||||
|
||||
void Server::stop() noexcept
|
||||
{
|
||||
this->_is_running = false;
|
||||
}
|
||||
662
repos/ealanos/src/lib/mx/io/network/server.d
Normal file
662
repos/ealanos/src/lib/mx/io/network/server.d
Normal file
@@ -0,0 +1,662 @@
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/server.o /home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/server.d: \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/server.cpp \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/server.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/fixed_size_allocator.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646 \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp \
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h \
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/task_allocator_interface.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/core_set.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/scheduler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_distance.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/shared_task_queue.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/bound_mpmc.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/priority_queue.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_squad.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/mpsc.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/worker.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/load.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_counter.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/aligned_t.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_buffer.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/ecpp/static_vector.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/compare \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_cycle_sampler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_map.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_hash.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_growth_policy.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/climits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ratio \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_execution_time_history.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool_occupancy.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/annotation.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_queues.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/set \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/maybe_atomic.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/runtime.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/builder.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/thread.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/pthread.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/logger.h \
|
||||
/home/mml/genode-igb/repos/libports/include/libc/component.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/netinet/in.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sockaddr_storage.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/netinet6/in6.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/socket.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_iovec.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/_align.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/_align.h
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/server.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/fixed_size_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/task_allocator_interface.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/core_set.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/scheduler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_distance.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/shared_task_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/bound_mpmc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/priority_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_squad.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/mpsc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/worker.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/load.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_counter.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/aligned_t.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_buffer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/ecpp/static_vector.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/compare:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_cycle_sampler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_map.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_hash.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_growth_policy.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/climits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ratio:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_execution_time_history.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool_occupancy.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/annotation.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_queues.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/set:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/maybe_atomic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/runtime.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/builder.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/thread.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/pthread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/logger.h:
|
||||
|
||||
/home/mml/genode-igb/repos/libports/include/libc/component.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/netinet/in.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sockaddr_storage.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/netinet6/in6.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/socket.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_iovec.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/_align.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/_align.h:
|
||||
76
repos/ealanos/src/lib/mx/io/network/server.h
Normal file
76
repos/ealanos/src/lib/mx/io/network/server.h
Normal file
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mx/memory/fixed_size_allocator.h>
|
||||
#include <mx/system/cpu.h>
|
||||
#include <mx/tasking/config.h>
|
||||
#include <mx/tasking/scheduler.h>
|
||||
#include <mx/util/core_set.h>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace mx::io::network {
|
||||
class MessageHandler
|
||||
{
|
||||
public:
|
||||
constexpr MessageHandler() noexcept = default;
|
||||
virtual ~MessageHandler() noexcept = default;
|
||||
|
||||
virtual mx::tasking::TaskResult handle(std::uint16_t worker_id, std::uint32_t client_id, std::string &&message) = 0;
|
||||
};
|
||||
|
||||
class MessageHandlerTask final : public tasking::TaskInterface
|
||||
{
|
||||
public:
|
||||
MessageHandlerTask(MessageHandler &message_handler, const std::uint32_t client_id, std::string &&message) noexcept
|
||||
: _message_handler(message_handler), _client_id(client_id), _message(std::move(message))
|
||||
{
|
||||
}
|
||||
|
||||
~MessageHandlerTask() noexcept override = default;
|
||||
|
||||
tasking::TaskResult execute(const std::uint16_t worker_id) override
|
||||
{
|
||||
auto result = _message_handler.handle(worker_id, _client_id, std::move(_message));
|
||||
delete this;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
MessageHandler &_message_handler;
|
||||
const std::uint32_t _client_id;
|
||||
std::string _message;
|
||||
};
|
||||
|
||||
class Server
|
||||
{
|
||||
public:
|
||||
Server(std::unique_ptr<MessageHandler> &&message_handler, std::uint16_t port,
|
||||
std::uint16_t count_channels) noexcept;
|
||||
~Server() noexcept = default;
|
||||
|
||||
[[nodiscard]] std::uint16_t port() const noexcept { return _port; }
|
||||
void stop() noexcept;
|
||||
void send(std::uint32_t client_id, std::string &&message);
|
||||
bool listen();
|
||||
|
||||
[[nodiscard]] bool is_running() const noexcept { return _is_running; }
|
||||
|
||||
private:
|
||||
const std::uint16_t _port;
|
||||
std::int32_t _socket;
|
||||
std::array<std::uint32_t, config::max_connections()> _client_sockets;
|
||||
std::array<char, 2048U> _buffer;
|
||||
std::unique_ptr<MessageHandler> _message_handler;
|
||||
|
||||
alignas(64) bool _is_running = true;
|
||||
alignas(64) std::atomic_uint64_t _next_worker_id{0U};
|
||||
const std::uint16_t _count_channels;
|
||||
|
||||
std::uint16_t add_client(std::int32_t client_socket);
|
||||
};
|
||||
} // namespace mx::io::network
|
||||
39
repos/ealanos/src/lib/mx/memory/alignment_helper.h
Normal file
39
repos/ealanos/src/lib/mx/memory/alignment_helper.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace mx::memory {
|
||||
/**
|
||||
* Helper for setting the correct size on aligned allocation:
|
||||
* The allocation size has to be a multiple of the alignment.
|
||||
*/
|
||||
class alignment_helper
|
||||
{
|
||||
public:
|
||||
template <typename T> static constexpr T next_multiple(const T value, const T base)
|
||||
{
|
||||
if (value > base)
|
||||
{
|
||||
const auto mod = value % base;
|
||||
if (mod == 0U)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return value + base - mod;
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
static constexpr bool is_power_of_two(const std::uint64_t value)
|
||||
{
|
||||
return ((value != 0U) && ((value & (value - 1U)) == 0U));
|
||||
}
|
||||
|
||||
static constexpr std::uint64_t next_power_of_two(const std::uint64_t value)
|
||||
{
|
||||
return is_power_of_two(value) ? value : 1ULL << (sizeof(std::uint64_t) * 8 - __builtin_clzll(value));
|
||||
}
|
||||
};
|
||||
} // namespace mx::memory
|
||||
32
repos/ealanos/src/lib/mx/memory/config.h
Normal file
32
repos/ealanos/src/lib/mx/memory/config.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include <chrono>
|
||||
#include <iterator>
|
||||
|
||||
namespace mx::memory {
|
||||
class config
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @return Number of maximal provided NUMA regions.
|
||||
*/
|
||||
static constexpr std::uint8_t max_numa_nodes() { return 8U; }
|
||||
|
||||
/**
|
||||
* @return Cycles for prefetching a single cache line.
|
||||
*/
|
||||
static constexpr std::uint32_t latency_per_prefetched_cache_line() { return 290U; }
|
||||
|
||||
/**
|
||||
* @return Interval of each epoch, if memory reclamation is used.
|
||||
*/
|
||||
static constexpr std::chrono::milliseconds epoch_interval() { return std::chrono::milliseconds(50U); }
|
||||
|
||||
/**
|
||||
* @return True, if garbage is removed local.
|
||||
*/
|
||||
static constexpr bool local_garbage_collection() { return false; }
|
||||
|
||||
static constexpr std::size_t min_block_size() { return 2048; }
|
||||
static constexpr std::size_t superblock_cutoff() { return 1024 * min_block_size();}
|
||||
};
|
||||
} // namespace mx::memory
|
||||
331
repos/ealanos/src/lib/mx/memory/dynamic_size_allocator.cpp
Normal file
331
repos/ealanos/src/lib/mx/memory/dynamic_size_allocator.cpp
Normal file
@@ -0,0 +1,331 @@
|
||||
#include "dynamic_size_allocator.h"
|
||||
#include "global_heap.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <mx/system/cpu.h>
|
||||
|
||||
using namespace mx::memory::dynamic;
|
||||
|
||||
AllocationBlock::AllocationBlock(const std::uint32_t id, const std::uint8_t numa_node_id, const std::size_t size)
|
||||
: _id(id), _numa_node_id(numa_node_id), _size(size), _available_size(size)
|
||||
{
|
||||
this->_allocated_block = GlobalHeap::allocate(numa_node_id, size);
|
||||
this->_free_elements.emplace_back(FreeHeader{reinterpret_cast<std::uintptr_t>(this->_allocated_block), size});
|
||||
this->_lock.unlock();
|
||||
}
|
||||
|
||||
AllocationBlock::AllocationBlock(AllocationBlock &&other) noexcept
|
||||
: _id(other._id), _numa_node_id(other._numa_node_id), _size(other._size),
|
||||
_allocated_block(std::exchange(other._allocated_block, nullptr)), _free_elements(std::move(other._free_elements)),
|
||||
_available_size(other._available_size)
|
||||
{
|
||||
this->_lock.unlock();
|
||||
}
|
||||
|
||||
AllocationBlock &AllocationBlock::operator=(AllocationBlock &&other) noexcept
|
||||
{
|
||||
this->_id = other._id;
|
||||
this->_numa_node_id = other._numa_node_id;
|
||||
this->_size = other._size;
|
||||
this->_allocated_block = std::exchange(other._allocated_block, nullptr);
|
||||
this->_free_elements = std::move(other._free_elements);
|
||||
this->_available_size = other._available_size;
|
||||
this->_lock.unlock();
|
||||
return *this;
|
||||
}
|
||||
|
||||
AllocationBlock::~AllocationBlock()
|
||||
{
|
||||
if (this->_allocated_block != nullptr)
|
||||
{
|
||||
GlobalHeap::free(this->_allocated_block, this->_size, this->_numa_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
void *AllocationBlock::allocate(const std::size_t alignment, const std::size_t size) noexcept
|
||||
{
|
||||
assert(alignment && (!(alignment & (alignment - 1))) && "Alignment must be > 0 and power of 2");
|
||||
this->_lock.lock();
|
||||
|
||||
if (this->_available_size < size)
|
||||
{
|
||||
this->_lock.unlock();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto block = this->find_block(alignment, size);
|
||||
if (block.has_value() == false)
|
||||
{
|
||||
this->_lock.unlock();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto [free_block_index, aligned_size_including_header] = block.value();
|
||||
auto &free_block = this->_free_elements[free_block_index];
|
||||
|
||||
const auto free_block_start = free_block.start();
|
||||
const auto free_block_end = free_block_start + free_block.size();
|
||||
const auto remaining_size = free_block.size() - aligned_size_including_header;
|
||||
|
||||
auto size_before_header = std::uint16_t{0U};
|
||||
if (remaining_size >= 256U)
|
||||
{
|
||||
free_block.contract(aligned_size_including_header);
|
||||
this->_available_size -= aligned_size_including_header;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_before_header = remaining_size;
|
||||
this->_available_size -= free_block.size();
|
||||
this->_free_elements.erase(this->_free_elements.begin() + free_block_index);
|
||||
}
|
||||
this->_lock.unlock();
|
||||
|
||||
const auto allocation_header_address = free_block_end - aligned_size_including_header;
|
||||
new (reinterpret_cast<void *>(allocation_header_address)) AllocatedHeader(
|
||||
aligned_size_including_header - sizeof(AllocatedHeader), size_before_header, this->_numa_node_id, this->_id);
|
||||
assert((allocation_header_address + sizeof(AllocatedHeader)) % alignment == 0 && "Not aligned");
|
||||
|
||||
return reinterpret_cast<void *>(allocation_header_address + sizeof(AllocatedHeader));
|
||||
}
|
||||
|
||||
void AllocationBlock::free(AllocatedHeader *allocation_header) noexcept
|
||||
{
|
||||
const auto allocated_size = allocation_header->size;
|
||||
const auto unused_size_before_header = allocation_header->unused_size_before_header;
|
||||
const auto block_address = reinterpret_cast<std::uintptr_t>(allocation_header) - unused_size_before_header;
|
||||
const auto size = allocated_size + unused_size_before_header + sizeof(AllocatedHeader);
|
||||
|
||||
const auto free_element = FreeHeader{block_address, size};
|
||||
|
||||
this->_lock.lock();
|
||||
|
||||
if (this->_free_elements.empty())
|
||||
{
|
||||
this->_free_elements.push_back(free_element);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto lower_bound_iterator =
|
||||
std::lower_bound(this->_free_elements.begin(), this->_free_elements.end(), free_element);
|
||||
const auto index = std::distance(this->_free_elements.begin(), lower_bound_iterator);
|
||||
assert(index >= 0 && "Index is negative");
|
||||
const auto real_index = std::size_t(index);
|
||||
|
||||
// Try to merge to the right.
|
||||
if (real_index < this->_free_elements.size() && free_element.borders(this->_free_elements[real_index]))
|
||||
{
|
||||
this->_free_elements[real_index].merge(free_element);
|
||||
|
||||
// Okay, we inserted the new free element as merge, we do not insert it "real".
|
||||
// Try to merge the expanded right with the left.
|
||||
if (real_index > 0U && this->_free_elements[real_index - 1U].borders(this->_free_elements[real_index]))
|
||||
{
|
||||
this->_free_elements[real_index - 1].merge(this->_free_elements[real_index]);
|
||||
this->_free_elements.erase(this->_free_elements.begin() + real_index);
|
||||
}
|
||||
}
|
||||
else if (real_index > 0U && this->_free_elements[real_index - 1U].borders(free_element))
|
||||
{
|
||||
// In this case, we could not merge with the right, but can we merge
|
||||
// to the left? By this, we could save up the real insert.
|
||||
this->_free_elements[real_index - 1U].merge(free_element);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We could not merge anything. Just insert.
|
||||
this->_free_elements.insert(this->_free_elements.begin() + real_index, free_element);
|
||||
}
|
||||
}
|
||||
this->_available_size += free_element.size();
|
||||
|
||||
this->_lock.unlock();
|
||||
}
|
||||
|
||||
std::optional<std::pair<std::size_t, std::size_t>> AllocationBlock::find_block(const std::size_t alignment,
|
||||
const std::size_t size) const noexcept
|
||||
{
|
||||
/**
|
||||
* Check each block of the free list for enough space to include the wanted space.
|
||||
* If enough, check the alignment (starting at the end).
|
||||
*
|
||||
* +----------------------------+
|
||||
* | 2000byte |
|
||||
* +----------------------------+
|
||||
* => wanted: 700byte
|
||||
* => align border -> 1300 is not aligned, expand to 720byte -> 1280 is aligned
|
||||
* +----------------------------+
|
||||
* | 1280byte | 720byte |
|
||||
* +----------------------------+
|
||||
*
|
||||
*/
|
||||
|
||||
const auto size_including_header = size + sizeof(AllocatedHeader);
|
||||
|
||||
for (auto index = 0U; index < this->_free_elements.size(); ++index)
|
||||
{
|
||||
const auto &free_element = this->_free_elements[index];
|
||||
if (free_element >= size_including_header)
|
||||
{
|
||||
const auto start = free_element.start();
|
||||
|
||||
// The free block ends here.
|
||||
const auto end = start + free_element.size();
|
||||
|
||||
// This is where we would start the memory block on allocation
|
||||
// But this may be not aligned.
|
||||
const auto possible_block_begin = end - size;
|
||||
|
||||
// This is the size we need to start the block aligned.
|
||||
const auto aligned_size = size + (possible_block_begin & (alignment - 1U));
|
||||
|
||||
// This is the size we need aligned and for header.
|
||||
const auto aligned_size_including_header = aligned_size + sizeof(AllocatedHeader);
|
||||
|
||||
if (free_element >= aligned_size_including_header)
|
||||
{
|
||||
// aligned_size_including_header
|
||||
return std::make_optional(std::make_pair(index, aligned_size_including_header));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Allocator::Allocator()
|
||||
{
|
||||
this->initialize_empty();
|
||||
}
|
||||
|
||||
void *Allocator::allocate(const std::uint8_t numa_node_id, const std::size_t alignment, const std::size_t size) noexcept
|
||||
{
|
||||
auto &allocation_blocks = this->_numa_allocation_blocks[numa_node_id];
|
||||
|
||||
auto *memory = allocation_blocks.back().allocate(alignment, size);
|
||||
if (memory == nullptr)
|
||||
{
|
||||
// This will be allocated default...
|
||||
constexpr auto default_alloc_size = std::size_t(1ULL << 28U);
|
||||
|
||||
// ... but if the requested size is higher, allocate more.
|
||||
const auto size_to_alloc = std::max(default_alloc_size, alignment_helper::next_multiple(size, 64UL));
|
||||
|
||||
// Try to allocate until allocation was successful.
|
||||
// It is possible, that another core tries to allocate at the
|
||||
// same time, therefore we capture the allocation flag (one per region)
|
||||
auto &flag = this->_numa_allocation_flags[numa_node_id].value();
|
||||
while (memory == nullptr)
|
||||
{
|
||||
allocate_new_block(numa_node_id, size_to_alloc, allocation_blocks, flag);
|
||||
memory = allocation_blocks.back().allocate(alignment, size);
|
||||
}
|
||||
}
|
||||
|
||||
return memory;
|
||||
}
|
||||
|
||||
void Allocator::allocate_new_block(const std::uint8_t numa_node_id, const std::size_t size,
|
||||
std::vector<AllocationBlock> &blocks, std::atomic<bool> &flag)
|
||||
{
|
||||
// Acquire the allocation flag to ensure only one thread to allocate.
|
||||
auto expected = false;
|
||||
const auto can_allocate = flag.compare_exchange_strong(expected, true);
|
||||
|
||||
if (can_allocate)
|
||||
{
|
||||
// If that was this thread go for it...
|
||||
const auto next_id = this->_next_allocation_id[numa_node_id].value().fetch_add(1U, std::memory_order_acq_rel);
|
||||
blocks.emplace_back(AllocationBlock{next_id, numa_node_id, size});
|
||||
|
||||
// .. but release the allocation flag afterward.
|
||||
flag.store(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If that was another thread, wait until he finished.
|
||||
while (flag.load())
|
||||
{
|
||||
system::builtin::pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Allocator::free(void *pointer) noexcept
|
||||
{
|
||||
// Every allocated memory belongs to one allocation block.
|
||||
// The reason is, that we can only return full blocks to
|
||||
// the global heap that is managed by the operating system.
|
||||
const auto address = reinterpret_cast<std::uintptr_t>(pointer);
|
||||
|
||||
// Access the header to identify the allocation block.
|
||||
const auto header_address = address - sizeof(AllocatedHeader);
|
||||
auto *allocation_header = reinterpret_cast<AllocatedHeader *>(header_address);
|
||||
|
||||
// Check all blocks to find the matching one.
|
||||
for (auto &block : this->_numa_allocation_blocks[allocation_header->numa_node_id])
|
||||
{
|
||||
if (allocation_header->allocation_block_id == block.id())
|
||||
{
|
||||
block.free(allocation_header);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Allocator::defragment() noexcept
|
||||
{
|
||||
// Remove all blocks that are unused to free as much memory as possible.
|
||||
for (auto i = 0U; i <= system::cpu::max_node_id(); ++i)
|
||||
{
|
||||
auto &numa_blocks = this->_numa_allocation_blocks[i];
|
||||
numa_blocks.erase(
|
||||
std::remove_if(numa_blocks.begin(), numa_blocks.end(), [](const auto &block) { return block.is_free(); }),
|
||||
numa_blocks.end());
|
||||
}
|
||||
|
||||
// If all memory was released, acquire new.
|
||||
this->initialize_empty();
|
||||
}
|
||||
|
||||
void Allocator::initialize_empty()
|
||||
{
|
||||
// For performance reasons: Each list must contain at least
|
||||
// one block. This way, we do not have to check every time.
|
||||
for (auto i = 0U; i <= system::cpu::max_node_id(); ++i)
|
||||
{
|
||||
auto &blocks = this->_numa_allocation_blocks[i];
|
||||
if (blocks.empty())
|
||||
{
|
||||
const auto next_id = this->_next_allocation_id[i].value().fetch_add(1U, std::memory_order_relaxed);
|
||||
blocks.emplace_back(AllocationBlock{next_id, std::uint8_t(i), 4096U * 4096U});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Allocator::is_free() const noexcept
|
||||
{
|
||||
for (auto i = 0U; i <= system::cpu::max_node_id(); ++i)
|
||||
{
|
||||
const auto &numa_blocks = this->_numa_allocation_blocks[i];
|
||||
const auto iterator = std::find_if(numa_blocks.cbegin(), numa_blocks.cend(), [](const auto &allocation_block) {
|
||||
return allocation_block.is_free() == false;
|
||||
});
|
||||
|
||||
if (iterator != numa_blocks.cend())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Allocator::release_allocated_memory() noexcept
|
||||
{
|
||||
for (auto i = 0U; i <= system::cpu::max_node_id(); ++i)
|
||||
{
|
||||
this->_numa_allocation_blocks[i].clear();
|
||||
this->_next_allocation_id[i].value().store(0U);
|
||||
}
|
||||
}
|
||||
446
repos/ealanos/src/lib/mx/memory/dynamic_size_allocator.d
Normal file
446
repos/ealanos/src/lib/mx/memory/dynamic_size_allocator.d
Normal file
@@ -0,0 +1,446 @@
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/dynamic_size_allocator.o /home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/dynamic_size_allocator.d: \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/dynamic_size_allocator.cpp \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/dynamic_size_allocator.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/aligned_t.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646 \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp \
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h \
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/dynamic_size_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/aligned_t.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h:
|
||||
186
repos/ealanos/src/lib/mx/memory/dynamic_size_allocator.h
Normal file
186
repos/ealanos/src/lib/mx/memory/dynamic_size_allocator.h
Normal file
@@ -0,0 +1,186 @@
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <mx/synchronization/spinlock.h>
|
||||
#include <mx/util/aligned_t.h>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace mx::memory::dynamic {
|
||||
|
||||
/**
|
||||
* Represents free space within an allocation block.
|
||||
* Holds the start and the size of a free object.
|
||||
*/
|
||||
class FreeHeader
|
||||
{
|
||||
public:
|
||||
constexpr FreeHeader(const std::uintptr_t start, const std::size_t size) noexcept : _start(start), _size(size) {}
|
||||
constexpr FreeHeader(const FreeHeader &other) noexcept = default;
|
||||
~FreeHeader() noexcept = default;
|
||||
|
||||
void contract(const std::size_t size) noexcept { _size -= size; }
|
||||
[[nodiscard]] std::uintptr_t start() const noexcept { return _start; }
|
||||
[[nodiscard]] std::uintptr_t size() const noexcept { return _size; }
|
||||
|
||||
bool operator<(const FreeHeader &other) const noexcept { return _start < other._start; }
|
||||
bool operator>=(const std::size_t size) const noexcept { return _size >= size; }
|
||||
|
||||
[[nodiscard]] bool borders(const FreeHeader &other) const noexcept { return (_start + _size) == other._start; }
|
||||
|
||||
void merge(const FreeHeader &other) noexcept
|
||||
{
|
||||
if (other._start < _start)
|
||||
{
|
||||
assert(other.borders(*this) && "Can not merge: Elements are not next to each other");
|
||||
_start = other._start;
|
||||
_size += other._size;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(borders(other) && "Can not merge: Elements are not next to each other");
|
||||
_size += other._size;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::uintptr_t _start;
|
||||
std::size_t _size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Header in front of allocated memory, storing the
|
||||
* size, the size which is unused because of alignment,
|
||||
* the ID of the NUMA node the memory is allocated on,
|
||||
* and the source allocation block of this memory.
|
||||
*/
|
||||
struct AllocatedHeader
|
||||
{
|
||||
constexpr AllocatedHeader(const std::size_t size_, const std::uint16_t unused_size_before_header_,
|
||||
const std::uint8_t numa_node_id_, const std::uint32_t allocation_block_id_) noexcept
|
||||
: size(size_), unused_size_before_header(unused_size_before_header_), numa_node_id(numa_node_id_),
|
||||
allocation_block_id(allocation_block_id_)
|
||||
{
|
||||
}
|
||||
|
||||
const std::size_t size;
|
||||
const std::uint16_t unused_size_before_header;
|
||||
const std::uint8_t numa_node_id;
|
||||
const std::uint32_t allocation_block_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set of on or more free tiles, that can be allocated.
|
||||
*/
|
||||
class AllocationBlock
|
||||
{
|
||||
public:
|
||||
AllocationBlock(std::uint32_t id, std::uint8_t numa_node_id, std::size_t size);
|
||||
AllocationBlock(const AllocationBlock &other) = delete;
|
||||
AllocationBlock(AllocationBlock &&other) noexcept;
|
||||
AllocationBlock &operator=(AllocationBlock &&other) noexcept;
|
||||
~AllocationBlock();
|
||||
|
||||
/**
|
||||
* Allocates memory from the allocation block.
|
||||
*
|
||||
* @param alignment Requested alignment.
|
||||
* @param size Requested size.
|
||||
* @return Pointer to the allocated memory.
|
||||
*/
|
||||
void *allocate(std::size_t alignment, std::size_t size) noexcept;
|
||||
|
||||
/**
|
||||
* Frees memory.
|
||||
*
|
||||
* @param allocation_header Pointer to the header of the freed memory.
|
||||
*/
|
||||
void free(AllocatedHeader *allocation_header) noexcept;
|
||||
|
||||
/**
|
||||
* @return Unique number of this allocation block.
|
||||
*/
|
||||
[[nodiscard]] std::uint32_t id() const noexcept { return _id; }
|
||||
|
||||
/**
|
||||
* @return True, if the full block is free.
|
||||
*/
|
||||
[[nodiscard]] bool is_free() const noexcept
|
||||
{
|
||||
return _free_elements.empty() || (_free_elements.size() == 1 && _free_elements[0].size() == _size);
|
||||
}
|
||||
|
||||
private:
|
||||
alignas(64) std::uint32_t _id;
|
||||
std::uint8_t _numa_node_id;
|
||||
std::size_t _size;
|
||||
|
||||
void *_allocated_block;
|
||||
std::vector<FreeHeader> _free_elements;
|
||||
|
||||
alignas(64) std::size_t _available_size;
|
||||
synchronization::Spinlock _lock;
|
||||
|
||||
std::optional<std::pair<std::size_t, std::size_t>> find_block(std::size_t alignment,
|
||||
std::size_t size) const noexcept;
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocator which holds a set of allocation blocks separated
|
||||
* for each numa node region.
|
||||
*/
|
||||
class Allocator
|
||||
{
|
||||
public:
|
||||
Allocator();
|
||||
~Allocator() = default;
|
||||
|
||||
void *allocate(std::uint8_t numa_node_id, std::size_t alignment, std::size_t size) noexcept;
|
||||
void free(void *pointer) noexcept;
|
||||
|
||||
/**
|
||||
* Frees unused allocation blocks.
|
||||
*/
|
||||
void defragment() noexcept;
|
||||
|
||||
/**
|
||||
* Releases all allocated memory.
|
||||
*/
|
||||
void release_allocated_memory() noexcept;
|
||||
|
||||
/**
|
||||
* Adds minimal memory to all numa node regions.
|
||||
*/
|
||||
void initialize_empty();
|
||||
|
||||
/**
|
||||
* @return True, if all blocks of all numa regions are free.
|
||||
*/
|
||||
[[nodiscard]] bool is_free() const noexcept;
|
||||
|
||||
private:
|
||||
// Allocation blocks per numa node region.
|
||||
std::array<std::vector<AllocationBlock>, config::max_numa_nodes()> _numa_allocation_blocks;
|
||||
|
||||
// Allocation flags, used for synchronization when allocating, per numa node region.
|
||||
std::array<util::aligned_t<std::atomic<bool>>, config::max_numa_nodes()> _numa_allocation_flags;
|
||||
|
||||
// Sequence for block allocation per numa node region.
|
||||
std::array<util::aligned_t<std::atomic_uint32_t>, config::max_numa_nodes()> _next_allocation_id;
|
||||
|
||||
/**
|
||||
* Allocates (thread-safe) a block of fresh memory
|
||||
* @param numa_node_id
|
||||
* @param size
|
||||
* @param blocks
|
||||
* @param flag
|
||||
*/
|
||||
void allocate_new_block(std::uint8_t numa_node_id, std::size_t size, std::vector<AllocationBlock> &blocks,
|
||||
std::atomic<bool> &flag);
|
||||
};
|
||||
|
||||
} // namespace mx::memory::dynamic
|
||||
396
repos/ealanos/src/lib/mx/memory/fixed_size_allocator.h
Normal file
396
repos/ealanos/src/lib/mx/memory/fixed_size_allocator.h
Normal file
@@ -0,0 +1,396 @@
|
||||
#pragma once
|
||||
|
||||
#include "alignment_helper.h"
|
||||
#include "config.h"
|
||||
#include "global_heap.h"
|
||||
#include "task_allocator_interface.h"
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <mx/synchronization/spinlock.h>
|
||||
#include <mx/system/cache.h>
|
||||
#include <mx/system/cpu.h>
|
||||
#include <mx/tasking/config.h>
|
||||
#include <mx/util/core_set.h>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace mx::memory::fixed {
|
||||
/**
|
||||
* Represents a free memory object.
|
||||
*/
|
||||
class FreeHeader
|
||||
{
|
||||
public:
|
||||
constexpr FreeHeader() noexcept = default;
|
||||
~FreeHeader() noexcept = default;
|
||||
|
||||
[[nodiscard]] FreeHeader *next() const noexcept { return _next; }
|
||||
void next(FreeHeader *next) noexcept { _next = next; }
|
||||
|
||||
void numa_node_id(const std::uint8_t numa_node_id) noexcept { _numa_node_id = numa_node_id; }
|
||||
[[nodiscard]] std::uint8_t numa_node_id() const noexcept { return _numa_node_id; }
|
||||
|
||||
private:
|
||||
FreeHeader *_next = nullptr;
|
||||
std::uint8_t _numa_node_id = 0U;
|
||||
};
|
||||
|
||||
/**
|
||||
* The Chunk holds a fixed size of memory.
|
||||
*/
|
||||
class Chunk
|
||||
{
|
||||
public:
|
||||
Chunk() noexcept = default;
|
||||
Chunk(void *memory, const bool is_allocated) noexcept : _memory(memory), _is_allocated(is_allocated) {}
|
||||
~Chunk() noexcept = default;
|
||||
|
||||
static constexpr auto size() { return 32U * 1024U * 1024U; /* 32mb */ }
|
||||
|
||||
explicit operator void *() const noexcept { return _memory; }
|
||||
explicit operator std::uintptr_t() const noexcept { return reinterpret_cast<std::uintptr_t>(_memory); }
|
||||
explicit operator bool() const noexcept { return _memory != nullptr && _is_allocated; }
|
||||
|
||||
private:
|
||||
void *_memory{nullptr};
|
||||
bool _is_allocated{true};
|
||||
};
|
||||
|
||||
/**
|
||||
* The ProcessorHeap holds memory for a single socket.
|
||||
* All cores sitting on this socket can allocate memory.
|
||||
* Internal, the ProcessorHeap bufferes allocated memory
|
||||
* to minimize access to the global heap.
|
||||
*/
|
||||
class alignas(64) ProcessorHeap
|
||||
{
|
||||
public:
|
||||
ProcessorHeap() noexcept = default;
|
||||
|
||||
explicit ProcessorHeap(const std::uint8_t numa_node_id) noexcept : _numa_node_id(numa_node_id)
|
||||
{
|
||||
_allocated_chunks.reserve(1024U);
|
||||
fill_buffer<true>();
|
||||
}
|
||||
|
||||
~ProcessorHeap() noexcept
|
||||
{
|
||||
if (_numa_node_id > mx::system::cpu::max_node_id())
|
||||
return;
|
||||
|
||||
for (const auto allocated_chunk : _allocated_chunks)
|
||||
{
|
||||
GlobalHeap::free(static_cast<void *>(allocated_chunk), Chunk::size(), this->_numa_node_id);
|
||||
}
|
||||
|
||||
for (const auto free_chunk : _free_chunk_buffer)
|
||||
{
|
||||
if (static_cast<bool>(free_chunk))
|
||||
{
|
||||
GlobalHeap::free(static_cast<void *>(free_chunk), Chunk::size(), this->_numa_node_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProcessorHeap &operator=(ProcessorHeap &&other) noexcept
|
||||
{
|
||||
_numa_node_id = std::exchange(other._numa_node_id, std::numeric_limits<std::uint8_t>::max());
|
||||
_free_chunk_buffer = other._free_chunk_buffer;
|
||||
other._free_chunk_buffer.fill(Chunk{});
|
||||
_next_free_chunk.store(other._next_free_chunk.load());
|
||||
_fill_buffer_flag.store(other._fill_buffer_flag.load());
|
||||
_allocated_chunks = std::move(other._allocated_chunks);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ID of the NUMA node the memory is allocated on.
|
||||
*/
|
||||
[[nodiscard]] std::uint8_t numa_node_id() const noexcept { return _numa_node_id; }
|
||||
|
||||
/**
|
||||
* Allocates a chunk of memory from the internal buffer.
|
||||
* In case the buffer is empty, new Chunks from the GlobalHeap
|
||||
* will be allocated.
|
||||
*
|
||||
* @return A chunk of allocated memory.
|
||||
*/
|
||||
Chunk allocate() noexcept
|
||||
{
|
||||
const auto next_free_chunk = _next_free_chunk.fetch_add(1U, std::memory_order_relaxed);
|
||||
if (next_free_chunk < _free_chunk_buffer.size())
|
||||
{
|
||||
return _free_chunk_buffer[next_free_chunk];
|
||||
}
|
||||
|
||||
auto expect = false;
|
||||
const auto can_fill = _fill_buffer_flag.compare_exchange_strong(expect, true);
|
||||
if (can_fill)
|
||||
{
|
||||
fill_buffer<false>();
|
||||
_fill_buffer_flag = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (_fill_buffer_flag)
|
||||
{
|
||||
system::builtin::pause();
|
||||
}
|
||||
}
|
||||
|
||||
return allocate();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::pair<std::uintptr_t, std::uintptr_t>> allocated_chunks()
|
||||
{
|
||||
auto chunks = std::vector<std::pair<std::uintptr_t, std::uintptr_t>>{};
|
||||
chunks.reserve(_free_chunk_buffer.size() + _allocated_chunks.size());
|
||||
|
||||
for (const auto chunk : _free_chunk_buffer)
|
||||
{
|
||||
const auto start = static_cast<std::uintptr_t>(chunk);
|
||||
if (start > 0U)
|
||||
{
|
||||
chunks.emplace_back(std::make_pair(start, start + Chunk::size()));
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto chunk : _allocated_chunks)
|
||||
{
|
||||
const auto start = static_cast<std::uintptr_t>(chunk);
|
||||
if (start > 0U)
|
||||
{
|
||||
chunks.emplace_back(std::make_pair(start, start + Chunk::size()));
|
||||
}
|
||||
}
|
||||
|
||||
return chunks;
|
||||
}
|
||||
|
||||
private:
|
||||
// Size of the internal chunk buffer.
|
||||
inline static constexpr auto CHUNKS = 128U;
|
||||
|
||||
// ID of the NUMA node of this ProcessorHeap.
|
||||
std::uint8_t _numa_node_id{std::numeric_limits<std::uint8_t>::max()};
|
||||
|
||||
// Buffer for free chunks.
|
||||
std::array<Chunk, CHUNKS> _free_chunk_buffer;
|
||||
|
||||
// Pointer to the next free chunk in the buffer.
|
||||
alignas(64) std::atomic_uint8_t _next_free_chunk{0U};
|
||||
|
||||
// Flag, used for allocation from the global Heap for mutual exclusion.
|
||||
std::atomic_bool _fill_buffer_flag{false};
|
||||
|
||||
// List of all allocated chunks, they will be freed later.
|
||||
std::vector<Chunk> _allocated_chunks;
|
||||
|
||||
/**
|
||||
* Allocates a very big chunk from the GlobalHeap and
|
||||
* splits it into smaller chunks to store them in the
|
||||
* internal buffer.
|
||||
*/
|
||||
template <bool IS_FIRST = false> void fill_buffer() noexcept
|
||||
{
|
||||
if constexpr (IS_FIRST == false)
|
||||
{
|
||||
for (const auto &chunk : _free_chunk_buffer)
|
||||
{
|
||||
_allocated_chunks.push_back(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
auto *heap_memory = GlobalHeap::allocate(_numa_node_id, Chunk::size() * _free_chunk_buffer.size());
|
||||
auto heap_memory_address = reinterpret_cast<std::uintptr_t>(heap_memory);
|
||||
for (auto i = 0U; i < _free_chunk_buffer.size(); ++i)
|
||||
{
|
||||
_free_chunk_buffer[i] = Chunk(reinterpret_cast<void *>(heap_memory_address + (i * Chunk::size())), i == 0U);
|
||||
|
||||
/// Touch the page to handle page fault.
|
||||
reinterpret_cast<char *>(_free_chunk_buffer[i].operator void *())[0] = '\0';
|
||||
}
|
||||
|
||||
_next_free_chunk.store(0U);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The worker local heap represents the allocator on a single core.
|
||||
* By this, allocations are latch-free.
|
||||
*/
|
||||
template <std::size_t S> class alignas(64) WorkerLocalHeap
|
||||
{
|
||||
public:
|
||||
explicit WorkerLocalHeap(ProcessorHeap *processor_heap) noexcept : _processor_heap(processor_heap)
|
||||
{
|
||||
fill_buffer<true>();
|
||||
}
|
||||
|
||||
WorkerLocalHeap() noexcept = default;
|
||||
|
||||
~WorkerLocalHeap() noexcept = default;
|
||||
|
||||
/**
|
||||
* Allocates new memory from the worker local heap.
|
||||
* When the internal buffer is empty, the worker local heap
|
||||
* will allocate new chunks from the ProcessorHeap.
|
||||
*
|
||||
* @return Pointer to the new allocated memory.
|
||||
*/
|
||||
[[nodiscard]] void *allocate() noexcept
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
/// Maybe, we have an item in the overflow queue.
|
||||
if (_overflow_first != nullptr)
|
||||
{
|
||||
auto *free_element = std::exchange(_overflow_first, _overflow_first->next());
|
||||
return static_cast<void *>(free_element);
|
||||
}
|
||||
|
||||
fill_buffer<false>();
|
||||
}
|
||||
|
||||
return reinterpret_cast<void *>(_free_elements[_free_head++]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees a memory object. The new available memory location
|
||||
* will be placed in front of the "available"-list. By this,
|
||||
* the next allocation will use the just freed object, which
|
||||
* may be still in the CPU cache.
|
||||
*
|
||||
* @param pointer Pointer to the memory object to be freed.
|
||||
*/
|
||||
void free(void *pointer) noexcept
|
||||
{
|
||||
if (_free_head > 0U)
|
||||
{
|
||||
_free_elements[--_free_head] = std::uintptr_t(pointer);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto *free_object = reinterpret_cast<FreeHeader *>(pointer);
|
||||
free_object->next(_overflow_first);
|
||||
_overflow_first = free_object;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the buffer by asking the ProcessorHeap for more memory.
|
||||
* This is latch-free since just a single core calls this method.
|
||||
*/
|
||||
template <bool IS_FIRST> void fill_buffer()
|
||||
{
|
||||
auto chunk = _processor_heap->allocate();
|
||||
const auto chunk_address = static_cast<std::uintptr_t>(chunk);
|
||||
|
||||
constexpr auto count_objects = std::uint64_t{Chunk::size() / S};
|
||||
|
||||
_free_head = 0U;
|
||||
for (auto i = 0U; i < count_objects; ++i)
|
||||
{
|
||||
_free_elements[i] = chunk_address + i * S;
|
||||
if (IS_FIRST)
|
||||
{
|
||||
reinterpret_cast<FreeHeader *>(_free_elements[i])->next(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Processor heap to allocate new chunks.
|
||||
ProcessorHeap *_processor_heap{nullptr};
|
||||
|
||||
std::uint64_t _free_head{Chunk::size() / S};
|
||||
|
||||
// Free elements
|
||||
std::array<std::uintptr_t, Chunk::size() / S> _free_elements;
|
||||
|
||||
// First element of the list of free memory objects.
|
||||
FreeHeader *_overflow_first{nullptr};
|
||||
|
||||
/**
|
||||
* @return True, when the buffer is empty.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const noexcept { return _free_head == _free_elements.max_size(); }
|
||||
};
|
||||
|
||||
/**
|
||||
* The Allocator is the interface to the internal worker local heaps.
|
||||
*/
|
||||
template <std::size_t S> class Allocator final : public TaskAllocatorInterface
|
||||
{
|
||||
public:
|
||||
explicit Allocator(const util::core_set &core_set)
|
||||
{
|
||||
for (auto node_id = std::uint8_t(0U); node_id <= system::cpu::max_node_id(); ++node_id)
|
||||
{
|
||||
if (core_set.has_core_of_numa_node(node_id))
|
||||
{
|
||||
_processor_heaps[node_id] = ProcessorHeap{node_id};
|
||||
}
|
||||
}
|
||||
|
||||
for (auto worker_id = 0U; worker_id < core_set.count_cores(); ++worker_id)
|
||||
{
|
||||
const auto node_id = system::cpu::node_id(core_set[worker_id]);
|
||||
_worker_local_heaps[worker_id] = WorkerLocalHeap<S>{&_processor_heaps[node_id]};
|
||||
}
|
||||
}
|
||||
|
||||
explicit Allocator(util::core_set &&core_set) : Allocator(core_set) {}
|
||||
|
||||
~Allocator() override = default;
|
||||
|
||||
/**
|
||||
* Allocates memory from the given worker local heap.
|
||||
*
|
||||
* @param worker_id ID of the worker.
|
||||
* @return Allocated memory object.
|
||||
*/
|
||||
[[nodiscard]] void *allocate(const std::uint16_t worker_id) override
|
||||
{
|
||||
return _worker_local_heaps[worker_id].allocate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees memory.
|
||||
*
|
||||
* @param worker_id ID of the worker to place the free object in.
|
||||
* @param address Pointer to the memory object.
|
||||
*/
|
||||
void free(const std::uint16_t worker_id, void *address) noexcept override
|
||||
{
|
||||
_worker_local_heaps[worker_id].free(address);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unordered_map<std::string, std::vector<std::pair<std::uintptr_t, std::uintptr_t>>>
|
||||
allocated_chunks() override
|
||||
{
|
||||
auto tags = std::unordered_map<std::string, std::vector<std::pair<std::uintptr_t, std::uintptr_t>>>{};
|
||||
|
||||
auto chunks = _processor_heaps.front().allocated_chunks();
|
||||
for (auto i = 1U; i < _processor_heaps.max_size(); ++i)
|
||||
{
|
||||
auto processor_chunks = _processor_heaps[i].allocated_chunks();
|
||||
std::move(processor_chunks.begin(), processor_chunks.end(), std::back_inserter(chunks));
|
||||
}
|
||||
|
||||
tags.insert(std::make_pair("tasks", std::move(chunks)));
|
||||
return tags;
|
||||
}
|
||||
|
||||
private:
|
||||
// Heap for every processor socket/NUMA region.
|
||||
std::array<ProcessorHeap, config::max_numa_nodes()> _processor_heaps;
|
||||
|
||||
// Map from core_id to core-local allocator.
|
||||
std::array<WorkerLocalHeap<S>, tasking::config::max_cores()> _worker_local_heaps;
|
||||
};
|
||||
} // namespace mx::memory::fixed
|
||||
60
repos/ealanos/src/lib/mx/memory/global_heap.h
Normal file
60
repos/ealanos/src/lib/mx/memory/global_heap.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
#include "alignment_helper.h"
|
||||
#include "config.h"
|
||||
#include "ealanos/util/json.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <mx/system/cache.h>
|
||||
#include <ealanos/memory/hamstraaja.h>
|
||||
|
||||
namespace mx::memory {
|
||||
/**
|
||||
* The global heap represents the heap, provided by the OS.
|
||||
*/
|
||||
class GlobalHeap
|
||||
{
|
||||
public:
|
||||
|
||||
static Ealan::Memory::Hamstraaja<config::min_block_size(), config::superblock_cutoff()> *_heap;
|
||||
|
||||
static bool initialized() { return _heap != nullptr; }
|
||||
|
||||
static void init(
|
||||
Ealan::Memory::Hamstraaja<config::min_block_size(), config::superblock_cutoff()> *_alloc)
|
||||
{
|
||||
_heap = _alloc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates the given size on the given NUMA node.
|
||||
*
|
||||
* @param numa_node_id ID of the NUMA node, the memory should allocated on.
|
||||
* @param size Size of the memory to be allocated.
|
||||
* @return Pointer to allocated memory.
|
||||
*/
|
||||
static void *allocate(const std::uint8_t numa_node_id, const std::size_t size)
|
||||
{
|
||||
return _heap->alloc(size, numa_node_id); //numa_alloc_onnode(size, numa_node_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates the given memory aligned to the cache line
|
||||
* with a multiple of the alignment as a size.
|
||||
* The allocated memory is not NUMA aware.
|
||||
* @param size Size to be allocated.
|
||||
* @return Allocated memory
|
||||
*/
|
||||
static void *allocate_cache_line_aligned(const std::size_t size)
|
||||
{
|
||||
return _heap->alloc(alignment_helper::next_multiple(size, 64UL));//std::aligned_alloc(mx::system::cache::line_size(), alignment_helper::next_multiple(size, 64UL));
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the given memory.
|
||||
*
|
||||
* @param memory Pointer to memory.
|
||||
* @param size Size of the allocated object.
|
||||
*/
|
||||
static void free(void *memory, const std::size_t size, [[maybe_unused]] const std::uint8_t numa_node_id) { _heap->free(memory); }
|
||||
};
|
||||
} // namespace mx::memory
|
||||
155
repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.cpp
Normal file
155
repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
#include "epoch_manager.h"
|
||||
#include <mx/queue/list.h>
|
||||
#include <mx/system/cpu.h>
|
||||
#include <mx/tasking/runtime.h>
|
||||
#include <thread>
|
||||
|
||||
using namespace mx::memory::reclamation;
|
||||
|
||||
void EpochManager::enter_epoch_periodically()
|
||||
{
|
||||
// Wait until the scheduler starts the system.
|
||||
while (this->_is_running == false)
|
||||
{
|
||||
system::builtin::pause();
|
||||
}
|
||||
|
||||
// Enter new epochs and collect garbage periodically
|
||||
// while the system is running.
|
||||
while (this->_is_running)
|
||||
{
|
||||
// Enter new epoch.
|
||||
this->_global_epoch.fetch_add(1U);
|
||||
|
||||
if constexpr (config::local_garbage_collection())
|
||||
{
|
||||
// Collect local garbage.
|
||||
// TODO: This might be buggy (even with cpu id, since threads could be interrupted within allocation)!
|
||||
const auto core_id = mx::system::cpu::core_id();
|
||||
for (auto worker_id = std::uint16_t(0U); worker_id < this->_count_channels; ++worker_id)
|
||||
{
|
||||
auto *garbage_task =
|
||||
mx::tasking::runtime::new_task<ReclaimEpochGarbageTask>(core_id, *this, this->_allocator);
|
||||
garbage_task->annotate(worker_id);
|
||||
mx::tasking::runtime::spawn(*garbage_task);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Collect global garbage of finished epochs.
|
||||
this->reclaim_epoch_garbage();
|
||||
}
|
||||
|
||||
// Wait some time until next epoch.
|
||||
std::this_thread::sleep_until(std::chrono::system_clock::now() + config::epoch_interval());
|
||||
}
|
||||
}
|
||||
|
||||
void EpochManager::reclaim_epoch_garbage() noexcept
|
||||
{
|
||||
// Items logically removed in an epoch leq than
|
||||
// this epoch can be removed physically.
|
||||
const auto min_epoch = this->min_local_epoch();
|
||||
|
||||
// Items that could not be physically removed in this epoch
|
||||
// and therefore have to be scheduled to the next one.
|
||||
queue::List<resource::ResourceInterface> deferred_resources{};
|
||||
|
||||
resource::ResourceInterface *resource;
|
||||
while ((resource = reinterpret_cast<resource::ResourceInterface *>(this->_global_garbage_queue.pop_front())) !=
|
||||
nullptr)
|
||||
{
|
||||
if (resource->remove_epoch() < min_epoch)
|
||||
{
|
||||
resource->on_reclaim();
|
||||
this->_allocator.free(static_cast<void *>(resource));
|
||||
}
|
||||
else
|
||||
{
|
||||
deferred_resources.push_back(resource);
|
||||
}
|
||||
}
|
||||
|
||||
// Resources that could not be deleted physically
|
||||
// need to be deleted in next epochs.
|
||||
if (deferred_resources.empty() == false)
|
||||
{
|
||||
this->_global_garbage_queue.push_back(deferred_resources.begin(), deferred_resources.end());
|
||||
}
|
||||
}
|
||||
|
||||
void EpochManager::reclaim_all() noexcept
|
||||
{
|
||||
if constexpr (config::local_garbage_collection())
|
||||
{
|
||||
for (auto worker_id = 0U; worker_id < this->_count_channels; ++worker_id)
|
||||
{
|
||||
resource::ResourceInterface *resource;
|
||||
while ((resource = reinterpret_cast<resource::ResourceInterface *>(
|
||||
this->_local_garbage_queues[worker_id].value().pop_front())) != nullptr)
|
||||
{
|
||||
resource->on_reclaim();
|
||||
this->_allocator.free(static_cast<void *>(resource));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resource::ResourceInterface *resource;
|
||||
while ((resource = reinterpret_cast<resource::ResourceInterface *>(this->_global_garbage_queue.pop_front())) !=
|
||||
nullptr)
|
||||
{
|
||||
resource->on_reclaim();
|
||||
this->_allocator.free(static_cast<void *>(resource));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EpochManager::reset() noexcept
|
||||
{
|
||||
if (this->_allocator.is_free())
|
||||
{
|
||||
this->_global_epoch.store(0U);
|
||||
for (auto worker_id = 0U; worker_id < tasking::config::max_cores(); ++worker_id)
|
||||
{
|
||||
_local_epochs[worker_id] = std::numeric_limits<epoch_t>::max();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mx::tasking::TaskResult ReclaimEpochGarbageTask::execute(const std::uint16_t worker_id)
|
||||
{
|
||||
// Items logically removed in an epoch leq than
|
||||
// this epoch can be removed physically.
|
||||
const auto min_epoch = this->_epoch_manager.min_local_epoch();
|
||||
|
||||
// Items that could not be physically removed in this epoch
|
||||
// and therefore have to be scheduled to the next one.
|
||||
queue::List<resource::ResourceInterface> deferred_resources{};
|
||||
|
||||
// Queue with channel-local garbage.
|
||||
auto &garbage_queue = this->_epoch_manager.local_garbage(worker_id);
|
||||
|
||||
resource::ResourceInterface *resource;
|
||||
while ((resource = reinterpret_cast<resource::ResourceInterface *>(garbage_queue.pop_front())) != nullptr)
|
||||
{
|
||||
if (resource->remove_epoch() < min_epoch)
|
||||
{
|
||||
resource->on_reclaim();
|
||||
this->_allocator.free(static_cast<void *>(resource));
|
||||
}
|
||||
else
|
||||
{
|
||||
deferred_resources.push_back(resource);
|
||||
}
|
||||
}
|
||||
|
||||
// Resources that could not be deleted physically
|
||||
// need to be deleted in next epochs.
|
||||
if (deferred_resources.empty() == false)
|
||||
{
|
||||
garbage_queue.push_back(deferred_resources.begin(), deferred_resources.end());
|
||||
}
|
||||
|
||||
return tasking::TaskResult::make_remove();
|
||||
}
|
||||
641
repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.d
Normal file
641
repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.d
Normal file
@@ -0,0 +1,641 @@
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.o /home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.d: \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.cpp \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646 \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp \
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h \
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/mpsc.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/core_set.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/set \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/aligned_t.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/maybe_atomic.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/runtime.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_distance.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/scheduler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/shared_task_queue.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/bound_mpmc.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/priority_queue.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_squad.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/worker.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/load.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_counter.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_buffer.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/ecpp/static_vector.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/compare \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_cycle_sampler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_map.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_hash.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_growth_policy.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/climits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ratio \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_execution_time_history.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool_occupancy.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/annotation.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_queues.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/server.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/config.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/fixed_size_allocator.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/task_allocator_interface.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/builder.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/thread.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/pthread.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/logger.h \
|
||||
/home/mml/genode-igb/repos/libports/include/libc/component.h
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/mpsc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/core_set.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/set:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/aligned_t.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/maybe_atomic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/runtime.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_distance.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/scheduler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/shared_task_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/bound_mpmc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/priority_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_squad.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/worker.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/load.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_counter.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_buffer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/ecpp/static_vector.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/compare:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_cycle_sampler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_map.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_hash.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_growth_policy.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/climits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ratio:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_execution_time_history.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool_occupancy.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/annotation.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_queues.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/server.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/config.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/fixed_size_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/task_allocator_interface.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/builder.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/thread.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/pthread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/logger.h:
|
||||
|
||||
/home/mml/genode-igb/repos/libports/include/libc/component.h:
|
||||
183
repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.h
Normal file
183
repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.h
Normal file
@@ -0,0 +1,183 @@
|
||||
#pragma once
|
||||
|
||||
#include "epoch_t.h"
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <mx/memory/config.h>
|
||||
#include <mx/memory/worker_local_dynamic_size_allocator.h>
|
||||
#include <mx/queue/mpsc.h>
|
||||
#include <mx/resource/resource_interface.h>
|
||||
#include <mx/system/builtin.h>
|
||||
#include <mx/tasking/config.h>
|
||||
#include <mx/tasking/task.h>
|
||||
#include <mx/util/aligned_t.h>
|
||||
#include <mx/util/core_set.h>
|
||||
#include <mx/util/maybe_atomic.h>
|
||||
#include <thread>
|
||||
|
||||
namespace mx::memory::reclamation {
|
||||
class alignas(64) LocalEpoch
|
||||
{
|
||||
public:
|
||||
constexpr LocalEpoch() noexcept = default;
|
||||
~LocalEpoch() noexcept = default;
|
||||
|
||||
LocalEpoch &operator=(const epoch_t epoch) noexcept
|
||||
{
|
||||
_epoch = epoch;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void enter(const std::atomic<epoch_t> &global_epoch) noexcept
|
||||
{
|
||||
_epoch.store(global_epoch.load(std::memory_order_seq_cst), std::memory_order_seq_cst);
|
||||
}
|
||||
void leave() noexcept { _epoch.store(std::numeric_limits<epoch_t>::max()); }
|
||||
|
||||
[[nodiscard]] epoch_t operator()() const noexcept { return _epoch.load(std::memory_order_seq_cst); }
|
||||
|
||||
private:
|
||||
std::atomic<epoch_t> _epoch{std::numeric_limits<epoch_t>::max()};
|
||||
};
|
||||
|
||||
/**
|
||||
* The Epoch Manager manages periodic epochs which
|
||||
* are used to protect reads against concurrent
|
||||
* delete operations. Therefore, a global epoch
|
||||
* will be incremented every 50ms (configurable).
|
||||
* Read operations, on the other hand, will update
|
||||
* their local epoch every time before reading an
|
||||
* optimistic resource.
|
||||
* When (logically) deleting an optimistic resource,
|
||||
* the resource will be deleted physically, when
|
||||
* every local epoch is greater than the epoch
|
||||
* when the resource is deleted.
|
||||
*/
|
||||
class EpochManager
|
||||
{
|
||||
public:
|
||||
EpochManager(const std::uint16_t count_channels, dynamic::local::Allocator &allocator,
|
||||
util::maybe_atomic<bool> &is_running) noexcept
|
||||
: _count_channels(count_channels), _is_running(is_running), _allocator(allocator)
|
||||
{
|
||||
}
|
||||
|
||||
EpochManager(const EpochManager &) = delete;
|
||||
|
||||
~EpochManager() = default;
|
||||
|
||||
LocalEpoch &operator[](const std::uint16_t worker_id) noexcept { return _local_epochs[worker_id]; }
|
||||
|
||||
/**
|
||||
* @return Access to read to global epoch.
|
||||
*/
|
||||
[[nodiscard]] const std::atomic<epoch_t> &global_epoch() const noexcept { return _global_epoch; }
|
||||
|
||||
/**
|
||||
* @return The minimal epoch of all channels.
|
||||
*/
|
||||
[[nodiscard]] epoch_t min_local_epoch() const noexcept
|
||||
{
|
||||
auto min_epoch = _local_epochs[0U]();
|
||||
for (auto worker_id = 1U; worker_id < _count_channels; ++worker_id)
|
||||
{
|
||||
min_epoch = std::min(min_epoch, _local_epochs[worker_id]());
|
||||
}
|
||||
|
||||
return min_epoch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an optimistic resource to garbage collection.
|
||||
* @param resource Resource to logically delete.
|
||||
*/
|
||||
void add_to_garbage_collection(resource::ResourceInterface *resource,
|
||||
[[maybe_unused]] const std::uint16_t owning_worker_id) noexcept
|
||||
{
|
||||
resource->remove_epoch(_global_epoch.load());
|
||||
|
||||
if constexpr (config::local_garbage_collection())
|
||||
{
|
||||
_local_garbage_queues[owning_worker_id].value().push_back(resource);
|
||||
}
|
||||
else
|
||||
{
|
||||
_global_garbage_queue.push_back(resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called periodically by a separate thread.
|
||||
*/
|
||||
void enter_epoch_periodically();
|
||||
|
||||
/**
|
||||
* Reclaims all garbage, mainly right before shut down tasking.
|
||||
*/
|
||||
void reclaim_all() noexcept;
|
||||
|
||||
/**
|
||||
* Grants access to the local garbage queue of a specific channel.
|
||||
*
|
||||
* @param worker_id Channel Id.
|
||||
* @return Local garbage queue.
|
||||
*/
|
||||
[[nodiscard]] queue::MPSC<resource::ResourceInterface> &local_garbage(const std::uint16_t worker_id) noexcept
|
||||
{
|
||||
return _local_garbage_queues[worker_id].value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all local and the global epoch to initial values
|
||||
* if no memory is in use.
|
||||
*/
|
||||
void reset() noexcept;
|
||||
|
||||
private:
|
||||
// Number of used channels; important for min-calculation.
|
||||
const std::uint16_t _count_channels;
|
||||
|
||||
// Flag of the scheduler indicating the state of the system.
|
||||
util::maybe_atomic<bool> &_is_running;
|
||||
|
||||
// Allocator to free collected resources.
|
||||
dynamic::local::Allocator &_allocator;
|
||||
|
||||
// Global epoch, incremented periodically.
|
||||
std::atomic<epoch_t> _global_epoch{0U};
|
||||
|
||||
// Local epochs, one for every channel.
|
||||
alignas(64) std::array<LocalEpoch, tasking::config::max_cores()> _local_epochs;
|
||||
|
||||
// Queue that holds all logically deleted objects in a global space.
|
||||
alignas(64) queue::MPSC<resource::ResourceInterface> _global_garbage_queue;
|
||||
|
||||
// Queues for every worker thread. Logically deleted objects are stored here
|
||||
// whenever local garbage collection is used.
|
||||
alignas(64) std::array<util::aligned_t<queue::MPSC<resource::ResourceInterface>>,
|
||||
tasking::config::max_cores()> _local_garbage_queues;
|
||||
|
||||
/**
|
||||
* Reclaims resources with regard to the epoch.
|
||||
*/
|
||||
void reclaim_epoch_garbage() noexcept;
|
||||
};
|
||||
|
||||
class ReclaimEpochGarbageTask final : public tasking::TaskInterface
|
||||
{
|
||||
public:
|
||||
constexpr ReclaimEpochGarbageTask(EpochManager &epoch_manager, dynamic::local::Allocator &allocator) noexcept
|
||||
: _epoch_manager(epoch_manager), _allocator(allocator)
|
||||
{
|
||||
}
|
||||
~ReclaimEpochGarbageTask() noexcept override = default;
|
||||
|
||||
tasking::TaskResult execute(std::uint16_t worker_id) override;
|
||||
|
||||
private:
|
||||
EpochManager &_epoch_manager;
|
||||
dynamic::local::Allocator &_allocator;
|
||||
};
|
||||
} // namespace mx::memory::reclamation
|
||||
5
repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h
Normal file
5
repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
namespace mx::memory::reclamation {
|
||||
using epoch_t = std::uint32_t;
|
||||
}
|
||||
103
repos/ealanos/src/lib/mx/memory/tagged_ptr.h
Normal file
103
repos/ealanos/src/lib/mx/memory/tagged_ptr.h
Normal file
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
namespace mx::memory {
|
||||
/**
|
||||
* Holds the memory address of an instance of the class T
|
||||
* and decodes a 16bit core address within the memory address.
|
||||
* The size of the tagged_ptr<T> is equal to T*.
|
||||
*/
|
||||
template <class T, typename I> class tagged_ptr
|
||||
{
|
||||
public:
|
||||
constexpr tagged_ptr() noexcept
|
||||
{
|
||||
static_assert(sizeof(I) == 2U);
|
||||
static_assert(sizeof(tagged_ptr) == 8U);
|
||||
}
|
||||
|
||||
constexpr explicit tagged_ptr(T *pointer) noexcept : _object_pointer(std::uintptr_t(pointer)) {}
|
||||
|
||||
constexpr explicit tagged_ptr(T *pointer, const I information) noexcept
|
||||
: _object_pointer(std::uintptr_t(pointer)), _information(information)
|
||||
{
|
||||
}
|
||||
|
||||
~tagged_ptr() noexcept = default;
|
||||
|
||||
/**
|
||||
* @return The decoded info.
|
||||
*/
|
||||
inline I info() const noexcept { return _information; }
|
||||
|
||||
/**
|
||||
* @return The memory address without the info.
|
||||
*/
|
||||
template <typename S = T> inline S *get() const noexcept { return reinterpret_cast<S *>(_object_pointer); }
|
||||
|
||||
/**
|
||||
* Decodes the given info within the pointer.
|
||||
*
|
||||
* @param info Info to store in the tagged pointer.
|
||||
*/
|
||||
inline void reset(const I information) noexcept { _information = information; }
|
||||
|
||||
/**
|
||||
* Replaces the internal pointer by a new one.
|
||||
*
|
||||
* @param new_pointer Pointer to the new memory object.
|
||||
*/
|
||||
inline void reset(T *new_pointer = nullptr) noexcept { _object_pointer = std::uintptr_t(new_pointer); }
|
||||
|
||||
T *operator->() const noexcept { return get(); }
|
||||
|
||||
explicit operator T *() const noexcept { return get(); }
|
||||
|
||||
explicit operator bool() const noexcept { return _object_pointer != 0U; }
|
||||
|
||||
explicit operator std::uintptr_t() const noexcept { return _object_pointer; }
|
||||
|
||||
tagged_ptr<T, I> &operator=(const tagged_ptr<T, I> &other) noexcept = default;
|
||||
|
||||
bool operator==(const tagged_ptr<T, I> &other) const noexcept { return other._object_pointer == _object_pointer; }
|
||||
|
||||
bool operator==(const T *other) const noexcept { return other == get(); }
|
||||
|
||||
bool operator==(std::nullptr_t) const noexcept { return _object_pointer == 0U; }
|
||||
|
||||
bool operator!=(const tagged_ptr<T, I> &other) const noexcept { return other.get() != get(); }
|
||||
|
||||
bool operator!=(std::nullptr_t) const noexcept { return _object_pointer != 0U; }
|
||||
|
||||
bool operator<(const tagged_ptr<T, I> &other) noexcept { return other.get() < get(); }
|
||||
|
||||
bool operator<=(const tagged_ptr<T, I> &other) noexcept { return other.get() <= get(); }
|
||||
|
||||
bool operator>(const tagged_ptr<T, I> &other) noexcept { return other.get() > get(); }
|
||||
|
||||
bool operator>=(const tagged_ptr<T, I> &other) noexcept { return other.get() >= get(); }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Pointer to the instance of T, only 48bit are used.
|
||||
*/
|
||||
std::uintptr_t _object_pointer : 48 {0U};
|
||||
|
||||
/**
|
||||
* Information stored within this pointer, remaining 16bit are used.
|
||||
*/
|
||||
I _information{};
|
||||
} __attribute__((packed));
|
||||
} // namespace mx::memory
|
||||
|
||||
namespace std {
|
||||
template <class T, typename I> struct hash<mx::memory::tagged_ptr<T, I>>
|
||||
{
|
||||
std::size_t operator()(const mx::memory::tagged_ptr<T, I> &ptr) const noexcept
|
||||
{
|
||||
return std::hash<T *>().operator()(ptr.get());
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
70
repos/ealanos/src/lib/mx/memory/task_allocator_interface.h
Normal file
70
repos/ealanos/src/lib/mx/memory/task_allocator_interface.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include "mx/memory/global_heap.h"
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <mx/system/cache.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace mx::memory {
|
||||
/**
|
||||
* Interface for task allocators (e.g. using systems malloc
|
||||
* or the internal allocator).
|
||||
*/
|
||||
class TaskAllocatorInterface
|
||||
{
|
||||
public:
|
||||
constexpr TaskAllocatorInterface() noexcept = default;
|
||||
virtual ~TaskAllocatorInterface() noexcept = default;
|
||||
|
||||
/**
|
||||
* Allocates memory for the given core.
|
||||
* @param worker_id Worker to allocate memory for.
|
||||
* @return Allocated memory.
|
||||
*/
|
||||
[[nodiscard]] virtual void *allocate(std::uint16_t worker_id) = 0;
|
||||
|
||||
/**
|
||||
* Frees the memory at the given core.
|
||||
* @param worker_id Worker to store free memory.
|
||||
* @param address Address to free.
|
||||
*/
|
||||
virtual void free(std::uint16_t worker_id, void *address) noexcept = 0;
|
||||
|
||||
[[nodiscard]] virtual std::unordered_map<std::string, std::vector<std::pair<std::uintptr_t, std::uintptr_t>>>
|
||||
allocated_chunks() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Task allocator using the systems (aligned_)malloc/free interface.
|
||||
*/
|
||||
template <std::size_t S> class SystemTaskAllocator final : public TaskAllocatorInterface
|
||||
{
|
||||
public:
|
||||
constexpr SystemTaskAllocator() noexcept = default;
|
||||
~SystemTaskAllocator() noexcept override = default;
|
||||
|
||||
/**
|
||||
* @return Allocated memory using systems malloc (but aligned).
|
||||
*/
|
||||
[[nodiscard]] void *allocate(const std::uint16_t /*worker_id*/) override
|
||||
{
|
||||
return memory::GlobalHeap::allocate_cache_line_aligned(S);
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the given memory using systems free.
|
||||
* @param address Memory to free.
|
||||
*/
|
||||
void free(const std::uint16_t /*worker_id*/, void *address) noexcept override { std::free(address); }
|
||||
|
||||
[[nodiscard]] std::unordered_map<std::string, std::vector<std::pair<std::uintptr_t, std::uintptr_t>>>
|
||||
allocated_chunks() override
|
||||
{
|
||||
return std::unordered_map<std::string, std::vector<std::pair<std::uintptr_t, std::uintptr_t>>>{};
|
||||
}
|
||||
};
|
||||
} // namespace mx::memory
|
||||
@@ -0,0 +1,433 @@
|
||||
#include "worker_local_dynamic_size_allocator.h"
|
||||
#include "alignment_helper.h"
|
||||
#include "global_heap.h"
|
||||
#include <cassert>
|
||||
|
||||
using namespace mx::memory::dynamic::local;
|
||||
|
||||
std::tuple<std::set<AllocatedBlock::FreeHeaderDescriptor>::iterator, bool, std::size_t, std::size_t> AllocatedBlock::
|
||||
find_free_header(const std::size_t alignment, std::size_t size) const
|
||||
{
|
||||
/// This is the minimal size we need to allocate,
|
||||
/// if and only if the address is perfectly aligned.
|
||||
/// However, we can filter out all free blocks with a
|
||||
/// size lower than that.
|
||||
const auto size_including_header = size + sizeof(AllocationHeader);
|
||||
|
||||
for (auto iterator = this->_free_header.begin(); iterator != this->_free_header.end(); ++iterator)
|
||||
{
|
||||
const auto &descriptor = *iterator;
|
||||
|
||||
if (descriptor.size() >= size_including_header)
|
||||
{
|
||||
const auto free_block_start_address = std::uintptr_t(descriptor.header());
|
||||
|
||||
/// Calculate the number of bytes needed to fullfill the wanted aligntment for
|
||||
/// the given free block.
|
||||
/// The real allocation block will look like:
|
||||
/// | (additional_size_to_fulfill_alignment[=0])(AllocationHeader)(size [+rest if free header has too
|
||||
/// less left]) |
|
||||
const auto allocation_start_address = free_block_start_address + sizeof(AllocationHeader);
|
||||
const auto additional_size_to_fulfill_alignment = alignment - allocation_start_address % alignment;
|
||||
|
||||
/// Check if the block has enough space to fullfill the alignment.
|
||||
const auto size_to_fulfill_alignment = size_including_header + additional_size_to_fulfill_alignment;
|
||||
if (descriptor.size() >= size_to_fulfill_alignment)
|
||||
{
|
||||
/// Check if we should split the block.
|
||||
const auto remaining_size = descriptor.size() - size_to_fulfill_alignment;
|
||||
|
||||
/// The header will be take totally because the rest would be too small.
|
||||
/// We will increase the size (full free size - size for header - size before header for alignment).
|
||||
return std::make_tuple(iterator, remaining_size > 256U, size_including_header,
|
||||
additional_size_to_fulfill_alignment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_tuple(this->_free_header.end(), false, 0U, 0U);
|
||||
}
|
||||
|
||||
void *AllocatedBlock::allocate(const std::uint16_t worker_id, const std::uint8_t numa_node_id,
|
||||
const std::size_t alignment, std::size_t size)
|
||||
{
|
||||
const auto [iterator, is_split, size_including_header, additional_size_to_fulfill_alignment] =
|
||||
this->find_free_header(alignment, size);
|
||||
if (iterator == this->_free_header.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto *free_header = iterator->header();
|
||||
const auto free_header_size = iterator->size();
|
||||
auto next_iterator = this->_free_header.erase(iterator);
|
||||
|
||||
const auto size_to_fulfill_alignment = size_including_header + additional_size_to_fulfill_alignment;
|
||||
|
||||
if (is_split)
|
||||
{
|
||||
const auto remaining_size = free_header->size() - size_to_fulfill_alignment;
|
||||
auto *new_free_header = new (reinterpret_cast<void *>(std::uintptr_t(free_header) + size_to_fulfill_alignment))
|
||||
FreeHeader(remaining_size, numa_node_id, this->_id);
|
||||
|
||||
this->_free_header.insert(next_iterator, FreeHeaderDescriptor{new_free_header, remaining_size});
|
||||
}
|
||||
else
|
||||
{
|
||||
size = free_header_size - sizeof(AllocationHeader) - additional_size_to_fulfill_alignment;
|
||||
}
|
||||
|
||||
const auto header_address = std::uintptr_t(free_header) + additional_size_to_fulfill_alignment;
|
||||
auto *allocation_header = new (reinterpret_cast<void *>(header_address))
|
||||
AllocationHeader(size, additional_size_to_fulfill_alignment, worker_id, numa_node_id, this->_id);
|
||||
return allocation_header + 1U;
|
||||
}
|
||||
|
||||
void AllocatedBlock::free(AllocationHeader *allocation_header)
|
||||
{
|
||||
assert(this->_id == allocation_header->block_id());
|
||||
|
||||
const auto ptr = std::uintptr_t(allocation_header) - allocation_header->unused_size_before_header();
|
||||
|
||||
auto *free_header = new (reinterpret_cast<void *>(ptr)) FreeHeader(
|
||||
allocation_header->unused_size_before_header() + sizeof(AllocationHeader) + allocation_header->size(),
|
||||
allocation_header->numa_node_id(), this->_id);
|
||||
|
||||
this->refund(free_header);
|
||||
}
|
||||
|
||||
void AllocatedBlock::refund(FreeHeader *free_header)
|
||||
{
|
||||
assert(std::uintptr_t(free_header) >= std::uintptr_t(this->_data));
|
||||
assert((std::uintptr_t(free_header) + free_header->size()) <= (std::uintptr_t(this->_data) + this->_size));
|
||||
|
||||
auto descriptor = FreeHeaderDescriptor{free_header, free_header->size()};
|
||||
|
||||
/// Try to merge with the descriptor next to the free one.
|
||||
auto next_descriptor = this->_free_header.upper_bound(descriptor);
|
||||
if (next_descriptor != this->_free_header.end())
|
||||
{
|
||||
if (free_header->is_right_neighbour(next_descriptor->header()))
|
||||
{
|
||||
descriptor.grow(next_descriptor->size());
|
||||
next_descriptor = this->_free_header.erase(next_descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
auto iterator = this->_free_header.insert(next_descriptor, descriptor);
|
||||
|
||||
if (iterator != this->_free_header.begin())
|
||||
{
|
||||
auto inserted_iterator = iterator--;
|
||||
|
||||
if (iterator->header()->is_right_neighbour(
|
||||
free_header)) /// Iterator is now the free header before inserted_iterator.
|
||||
{
|
||||
auto new_descriptor = *iterator;
|
||||
new_descriptor.grow(inserted_iterator->size());
|
||||
|
||||
/// Remove the i-1 and i.
|
||||
this->_free_header.erase(inserted_iterator);
|
||||
auto next_iterator = this->_free_header.erase(iterator);
|
||||
|
||||
/// Re-insert as a grown header.
|
||||
this->_free_header.insert(next_iterator, new_descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WorkerHeap::WorkerHeap(std::uint16_t worker_id, std::uint8_t numa_node_id)
|
||||
: _worker_id(worker_id), _numa_node_id(numa_node_id)
|
||||
{
|
||||
}
|
||||
|
||||
WorkerHeap::WorkerHeap(mx::memory::dynamic::local::WorkerHeap &&other) noexcept
|
||||
: _worker_id(other._worker_id), _numa_node_id(other._numa_node_id), _next_block_id(other._next_block_id)
|
||||
{
|
||||
for (auto i = 0U; i < config::max_numa_nodes(); ++i)
|
||||
{
|
||||
this->_allocated_blocks[i] = std::move(other._allocated_blocks[i]);
|
||||
this->_allocated_block_indices[i] = std::move(other._allocated_block_indices[i]);
|
||||
|
||||
FreeHeader *free_header;
|
||||
while ((free_header = other._remote_free_lists[i].pop_front()) != nullptr)
|
||||
{
|
||||
this->_remote_free_lists[i].push_back(free_header);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *WorkerHeap::allocate(const std::uint8_t numa_node_id, const std::size_t alignment, const std::size_t size)
|
||||
{
|
||||
/// (1) Check all blocks for free memory.
|
||||
auto &numa_blocks = this->_allocated_blocks[numa_node_id];
|
||||
for (auto i = std::int64_t(numa_blocks.size() - 1U); i >= 0; --i)
|
||||
{
|
||||
auto *allocated_block = numa_blocks[i].allocate(this->_worker_id, numa_node_id, alignment, size);
|
||||
if (allocated_block != nullptr)
|
||||
{
|
||||
return allocated_block;
|
||||
}
|
||||
}
|
||||
|
||||
/// (2) Check free list from other cores for free memory.
|
||||
FreeHeader *header;
|
||||
while ((header = this->_remote_free_lists[numa_node_id].pop_front()) != nullptr)
|
||||
{
|
||||
header->next(nullptr);
|
||||
|
||||
const auto qualifies = header->size() >= size;
|
||||
|
||||
auto &index = this->_allocated_block_indices[header->numa_node_id()];
|
||||
if (auto iterator = index.find(header->block_id()); iterator != index.end())
|
||||
{
|
||||
auto &block = this->_allocated_blocks[header->numa_node_id()][iterator->second];
|
||||
assert(block.id() == header->block_id());
|
||||
block.refund(header);
|
||||
|
||||
if (qualifies)
|
||||
{
|
||||
auto *allocation = block.allocate(this->_worker_id, numa_node_id, alignment, size);
|
||||
if (allocation != nullptr)
|
||||
{
|
||||
return allocation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// (3) Allocate a new block.
|
||||
const auto size_to_alloc_from_global_heap = std::max<std::size_t>(
|
||||
AllocatedBlock::DEFAULT_SIZE_IN_BYTES, alignment_helper::next_multiple(size + sizeof(AllocationHeader), 64UL));
|
||||
auto *data = GlobalHeap::allocate(numa_node_id, size_to_alloc_from_global_heap);
|
||||
auto &allocated_block = this->_allocated_blocks[numa_node_id].emplace_back(this->_next_block_id++, numa_node_id,
|
||||
size_to_alloc_from_global_heap, data);
|
||||
|
||||
/// Update the index.
|
||||
this->_allocated_block_indices[numa_node_id].insert(
|
||||
std::make_pair(allocated_block.id(), this->_allocated_blocks[numa_node_id].size() - 1U));
|
||||
|
||||
return allocated_block.allocate(this->_worker_id, numa_node_id, alignment, size);
|
||||
}
|
||||
|
||||
void WorkerHeap::free(AllocationHeader *allocated_block)
|
||||
{
|
||||
auto &index = this->_allocated_block_indices[allocated_block->numa_node_id()];
|
||||
if (auto iterator = index.find(allocated_block->block_id()); iterator != index.end())
|
||||
{
|
||||
this->_allocated_blocks[allocated_block->numa_node_id()][iterator->second].free(allocated_block);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void WorkerHeap::release_free_memory()
|
||||
{
|
||||
this->refund_remote_freed_memory();
|
||||
|
||||
for (auto numa_node_id = 0U; numa_node_id < this->_allocated_blocks.size(); ++numa_node_id)
|
||||
{
|
||||
auto &allocated_blocks = this->_allocated_blocks[numa_node_id];
|
||||
|
||||
allocated_blocks.erase(std::remove_if(allocated_blocks.begin(), allocated_blocks.end(),
|
||||
[](const auto &block) { return block.is_free(); }),
|
||||
allocated_blocks.end());
|
||||
|
||||
auto &index = this->_allocated_block_indices[numa_node_id];
|
||||
index.clear();
|
||||
for (auto i = 0UL; i < allocated_blocks.size(); ++i)
|
||||
{
|
||||
index.insert(std::make_pair(allocated_blocks[i].id(), i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorkerHeap::release_all_memory()
|
||||
{
|
||||
for (auto &allocated_blocks : this->_allocated_blocks)
|
||||
{
|
||||
allocated_blocks.clear();
|
||||
}
|
||||
|
||||
for (auto &index : this->_allocated_block_indices)
|
||||
{
|
||||
index.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void WorkerHeap::refund_remote_freed_memory()
|
||||
{
|
||||
for (auto i = 0U; i < this->_remote_free_lists.max_size(); ++i)
|
||||
{
|
||||
/// Check local numa region first.
|
||||
const auto nid = (this->_numa_node_id + i) & (this->_remote_free_lists.max_size() - 1U);
|
||||
FreeHeader *header;
|
||||
while ((header = this->_remote_free_lists[nid].pop_front()) != nullptr)
|
||||
{
|
||||
header->next(nullptr);
|
||||
|
||||
auto &index = this->_allocated_block_indices[header->numa_node_id()];
|
||||
if (auto iterator = index.find(header->block_id()); iterator != index.end())
|
||||
{
|
||||
auto &block = this->_allocated_blocks[header->numa_node_id()][iterator->second];
|
||||
assert(block.id() == header->block_id());
|
||||
block.refund(header);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorkerHeap::initialize(const std::uint8_t numa_nodes)
|
||||
{
|
||||
for (auto numa_node_id = 0U; numa_node_id < numa_nodes; ++numa_node_id)
|
||||
{
|
||||
auto &index = this->_allocated_block_indices[numa_node_id];
|
||||
if (index.max_size() < 1024U)
|
||||
{
|
||||
index.reserve(1024U);
|
||||
}
|
||||
|
||||
if (this->_allocated_blocks[numa_node_id].empty())
|
||||
{
|
||||
const auto size = AllocatedBlock::DEFAULT_SIZE_IN_BYTES *
|
||||
(1U + (static_cast<std::uint8_t>(numa_node_id == this->_numa_node_id) * 3U));
|
||||
|
||||
auto *data = GlobalHeap::allocate(numa_node_id, size);
|
||||
auto &block = this->_allocated_blocks[numa_node_id].emplace_back(this->_next_block_id++, numa_node_id, size, data);
|
||||
|
||||
index.insert(std::make_pair(block.id(), this->_allocated_blocks[numa_node_id].size() - 1U));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WorkerHeap::is_free() const noexcept
|
||||
{
|
||||
for (const auto &allocated_blocks : this->_allocated_blocks)
|
||||
{
|
||||
for (const auto &block : allocated_blocks)
|
||||
{
|
||||
if (block.is_free() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Allocator::Allocator(const util::core_set &cores) : _count_workers(cores.count_cores())
|
||||
{
|
||||
this->_worker_local_heaps = reinterpret_cast<WorkerHeap *>(
|
||||
GlobalHeap::allocate_cache_line_aligned(sizeof(WorkerHeap) * cores.count_cores()));
|
||||
for (auto i = std::uint16_t(0U); i < cores.count_cores(); ++i)
|
||||
{
|
||||
auto numa_node_id = cores.numa_node_id(i);
|
||||
new (reinterpret_cast<void *>(&this->_worker_local_heaps[i])) WorkerHeap(i, numa_node_id);
|
||||
this->_numa_node_ids[i] = numa_node_id;
|
||||
}
|
||||
}
|
||||
|
||||
void Allocator::initialize_heap(const std::uint16_t worker_id, const std::uint8_t count_numa_nodes)
|
||||
{
|
||||
this->_worker_local_heaps[worker_id].initialize(count_numa_nodes);
|
||||
}
|
||||
|
||||
Allocator::~Allocator()
|
||||
{
|
||||
for (auto i = 0U; i < this->_count_workers; ++i)
|
||||
{
|
||||
this->_worker_local_heaps[i].~WorkerHeap();
|
||||
}
|
||||
std::free(this->_worker_local_heaps);
|
||||
}
|
||||
|
||||
void *Allocator::allocate(const std::uint16_t worker_id, const std::uint8_t numa_node_id, const std::size_t alignment,
|
||||
const std::size_t size)
|
||||
{
|
||||
return this->_worker_local_heaps[worker_id].allocate(numa_node_id, alignment, size);
|
||||
}
|
||||
|
||||
void Allocator::free(const std::uint16_t calling_worker_id, void *pointer)
|
||||
{
|
||||
auto *allocation_header = reinterpret_cast<AllocationHeader *>(std::uintptr_t(pointer) - sizeof(AllocationHeader));
|
||||
auto &heap = this->_worker_local_heaps[allocation_header->worker_id()];
|
||||
|
||||
if (allocation_header->worker_id() == calling_worker_id)
|
||||
{
|
||||
heap.free(allocation_header);
|
||||
}
|
||||
else
|
||||
{
|
||||
heap.free(this->_numa_node_ids[calling_worker_id], allocation_header);
|
||||
}
|
||||
}
|
||||
|
||||
void Allocator::free(void *pointer)
|
||||
{
|
||||
auto *allocation_header = reinterpret_cast<AllocationHeader *>(std::uintptr_t(pointer) - sizeof(AllocationHeader));
|
||||
auto &heap = _worker_local_heaps[allocation_header->worker_id()];
|
||||
|
||||
heap.free(system::cpu::node_id(), allocation_header);
|
||||
}
|
||||
|
||||
void Allocator::reset(const util::core_set &cores, bool force_free_memory)
|
||||
{
|
||||
if (force_free_memory)
|
||||
{
|
||||
for (auto i = 0U; i < this->_count_workers; ++i)
|
||||
{
|
||||
this->_worker_local_heaps[i].release_all_memory();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto i = 0U; i < this->_count_workers; ++i)
|
||||
{
|
||||
this->_worker_local_heaps[i].release_free_memory();
|
||||
}
|
||||
}
|
||||
|
||||
if (this->_count_workers < cores.count_cores())
|
||||
{
|
||||
const auto old_count_workers = std::exchange(this->_count_workers, cores.count_cores());
|
||||
|
||||
auto *old_local_worker_heaps = this->_worker_local_heaps;
|
||||
auto *new_local_worker_heaps = reinterpret_cast<WorkerHeap *>(
|
||||
GlobalHeap::allocate_cache_line_aligned(sizeof(WorkerHeap) * cores.count_cores()));
|
||||
|
||||
/// Re-initialize old workers on new storage.
|
||||
auto worker_id = 0U;
|
||||
for (; worker_id < old_count_workers; ++worker_id)
|
||||
{
|
||||
const auto numa_node_id = cores.numa_node_id(worker_id);
|
||||
new (reinterpret_cast<void *>(&new_local_worker_heaps[worker_id]))
|
||||
WorkerHeap(std::move(old_local_worker_heaps[worker_id]));
|
||||
this->_numa_node_ids[worker_id] = numa_node_id;
|
||||
}
|
||||
|
||||
/// Create new workers on new storage.
|
||||
for (; worker_id < cores.count_cores(); ++worker_id)
|
||||
{
|
||||
const auto numa_node_id = cores.numa_node_id(worker_id);
|
||||
new (reinterpret_cast<void *>(&new_local_worker_heaps[worker_id])) WorkerHeap(worker_id, numa_node_id);
|
||||
this->_numa_node_ids[worker_id] = numa_node_id;
|
||||
}
|
||||
|
||||
/// Free old storage.
|
||||
std::free(old_local_worker_heaps);
|
||||
this->_worker_local_heaps = new_local_worker_heaps;
|
||||
}
|
||||
}
|
||||
|
||||
bool Allocator::is_free() const noexcept
|
||||
{
|
||||
for (auto i = 0U; i < this->_count_workers; ++i)
|
||||
{
|
||||
if (this->_worker_local_heaps[i].is_free() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,521 @@
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.o /home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.d: \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.cpp \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646 \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp \
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h \
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/mpsc.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/core_set.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/set
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/mpsc.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/core_set.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/set:
|
||||
@@ -0,0 +1,345 @@
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
#include "global_heap.h"
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <mx/queue/mpsc.h>
|
||||
#include <mx/tasking/config.h>
|
||||
#include <mx/tasking/task.h>
|
||||
#include <mx/util/core_set.h>
|
||||
#include <set>
|
||||
|
||||
namespace mx::memory::dynamic::local {
|
||||
/**
|
||||
* Header of a free element.
|
||||
*/
|
||||
class FreeHeader
|
||||
{
|
||||
public:
|
||||
constexpr FreeHeader(const std::size_t size, const std::uint8_t numa_node_id, const std::uint32_t block_id) noexcept
|
||||
: _size(size), _numa_node_id(numa_node_id), _block_id(block_id)
|
||||
{
|
||||
}
|
||||
~FreeHeader() noexcept = default;
|
||||
|
||||
[[nodiscard]] std::size_t size() const noexcept { return _size; }
|
||||
[[nodiscard]] std::uint8_t numa_node_id() const noexcept { return _numa_node_id; }
|
||||
[[nodiscard]] std::uint32_t block_id() const noexcept { return _block_id; }
|
||||
[[nodiscard]] FreeHeader *next() const noexcept { return _next; }
|
||||
|
||||
void next(FreeHeader *next) noexcept
|
||||
{
|
||||
assert(next != this);
|
||||
_next = next;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_right_neighbour(FreeHeader *possible_right_neighbour)
|
||||
{
|
||||
assert(this->_block_id == possible_right_neighbour->_block_id);
|
||||
|
||||
return (std::uintptr_t(this) + _size) == std::uintptr_t(possible_right_neighbour);
|
||||
}
|
||||
|
||||
void append(FreeHeader *other) { grow(other->_size); }
|
||||
|
||||
void grow(const std::size_t size) { _size += size; }
|
||||
|
||||
private:
|
||||
/// Size of the full block, including the header size.
|
||||
/// We include the header size because that is the size that is usable for allocation.
|
||||
std::size_t _size;
|
||||
|
||||
/// Id of the numa node the block was allocated in. Needed when returning
|
||||
/// remote free memory.
|
||||
const std::uint8_t _numa_node_id;
|
||||
|
||||
/// Id of the block within the worker heap.
|
||||
const std::uint32_t _block_id;
|
||||
|
||||
/// Will be used for allocation within allocation block
|
||||
/// and for queue in remote free list.
|
||||
FreeHeader *_next{nullptr};
|
||||
};
|
||||
|
||||
/**
|
||||
* Header of a block that is allocated.
|
||||
*/
|
||||
class AllocationHeader
|
||||
{
|
||||
public:
|
||||
constexpr AllocationHeader(const std::size_t size, const std::uint16_t unused_size_before_header,
|
||||
const std::uint16_t worker_id, const std::uint8_t numa_node_id,
|
||||
const std::uint32_t block_id) noexcept
|
||||
: _size(size), _unused_size_before_header(unused_size_before_header), _worker_id(worker_id),
|
||||
_numa_node_id(numa_node_id), _block_id(block_id)
|
||||
{
|
||||
}
|
||||
|
||||
~AllocationHeader() noexcept = default;
|
||||
|
||||
[[nodiscard]] std::size_t size() const noexcept { return _size; }
|
||||
[[nodiscard]] std::uint16_t unused_size_before_header() const noexcept { return _unused_size_before_header; }
|
||||
[[nodiscard]] std::uint16_t worker_id() const noexcept { return _worker_id; }
|
||||
[[nodiscard]] std::uint8_t numa_node_id() const noexcept { return _numa_node_id; }
|
||||
[[nodiscard]] std::uint32_t block_id() const noexcept { return _block_id; }
|
||||
|
||||
[[nodiscard]] FreeHeader *to_free_header() const noexcept
|
||||
{
|
||||
const auto size = _size + _unused_size_before_header + sizeof(AllocationHeader);
|
||||
return new (reinterpret_cast<void *>(std::uintptr_t(this) - _unused_size_before_header))
|
||||
FreeHeader(size, _numa_node_id, _block_id);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Size of the block after the header.
|
||||
const std::size_t _size;
|
||||
|
||||
/// Size in front of the header that is not used but needed for alignment.
|
||||
const std::uint16_t _unused_size_before_header;
|
||||
|
||||
/// Id of the worker.
|
||||
const std::uint16_t _worker_id;
|
||||
|
||||
/// Numa region the block was allocated in.
|
||||
std::uint8_t _numa_node_id;
|
||||
|
||||
/// Id of the block within the worker heap.
|
||||
const std::uint32_t _block_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* A block allocated from global memory into a worker-local heap.
|
||||
*/
|
||||
class AllocatedBlock
|
||||
{
|
||||
private:
|
||||
class FreeHeaderDescriptor
|
||||
{
|
||||
public:
|
||||
constexpr FreeHeaderDescriptor(FreeHeader *header, const std::size_t size) noexcept
|
||||
: _header(header), _size(size)
|
||||
{
|
||||
}
|
||||
|
||||
~FreeHeaderDescriptor() noexcept = default;
|
||||
|
||||
[[nodiscard]] FreeHeader *header() const noexcept { return _header; }
|
||||
[[nodiscard]] std::size_t size() const noexcept { return _size; }
|
||||
|
||||
void grow(const std::size_t size) noexcept
|
||||
{
|
||||
_size += size;
|
||||
_header->grow(size);
|
||||
}
|
||||
|
||||
bool operator<(const FreeHeaderDescriptor other) const noexcept
|
||||
{
|
||||
return std::uintptr_t(_header) < std::uintptr_t(other._header);
|
||||
}
|
||||
|
||||
private:
|
||||
FreeHeader *_header;
|
||||
std::size_t _size;
|
||||
};
|
||||
|
||||
public:
|
||||
static inline constexpr auto DEFAULT_SIZE_IN_BYTES = 1024UL * 1024UL * 128U;
|
||||
|
||||
AllocatedBlock(const std::uint32_t id, const std::uint8_t numa_node_id, const std::size_t size, void *data) noexcept
|
||||
: _id(id), _numa_node_id(numa_node_id), _size(size), _data(data)
|
||||
{
|
||||
_free_header.insert(FreeHeaderDescriptor{new (_data) FreeHeader(size, 0U, id), size});
|
||||
}
|
||||
|
||||
AllocatedBlock(AllocatedBlock &&other) noexcept
|
||||
: _id(other._id), _numa_node_id(other._numa_node_id), _size(other._size), _data(std::exchange(other._data, nullptr)),
|
||||
_free_header(std::move(other._free_header))
|
||||
{
|
||||
}
|
||||
|
||||
~AllocatedBlock()
|
||||
{
|
||||
if (_data != nullptr)
|
||||
{
|
||||
GlobalHeap::free(std::exchange(_data, nullptr), _size, _numa_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
AllocatedBlock &operator=(AllocatedBlock &&other) noexcept
|
||||
{
|
||||
_id = other._id;
|
||||
_size = other._size;
|
||||
_data = std::exchange(other._data, nullptr);
|
||||
_free_header = std::move(other._free_header);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint32_t id() const noexcept { return _id; }
|
||||
[[nodiscard]] void *data() const noexcept { return _data; }
|
||||
[[nodiscard]] std::size_t size() const noexcept { return _size; }
|
||||
|
||||
[[nodiscard]] void *allocate(std::uint16_t worker_id, std::uint8_t numa_node_id, std::size_t alignment,
|
||||
std::size_t size);
|
||||
void free(AllocationHeader *allocation_header);
|
||||
void refund(FreeHeader *free_header);
|
||||
|
||||
[[nodiscard]] bool is_free() const noexcept
|
||||
{
|
||||
return _free_header.size() == 1U && _free_header.begin()->size() == _size;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::tuple<std::set<FreeHeaderDescriptor>::iterator, bool, std::size_t, std::size_t> find_free_header(
|
||||
std::size_t alignment, std::size_t size) const;
|
||||
|
||||
private:
|
||||
std::uint32_t _id;
|
||||
std::uint8_t _numa_node_id;
|
||||
std::size_t _size;
|
||||
void *_data;
|
||||
std::set<FreeHeaderDescriptor> _free_header;
|
||||
};
|
||||
|
||||
class alignas(64) WorkerHeap
|
||||
{
|
||||
public:
|
||||
WorkerHeap(std::uint16_t worker_id, std::uint8_t numa_node_id);
|
||||
WorkerHeap(WorkerHeap &&other) noexcept;
|
||||
~WorkerHeap() = default;
|
||||
|
||||
/**
|
||||
* Allocates memory from the list of allocated blocks,
|
||||
* or, when no memory available, from the remote free list.
|
||||
* If, however, no memory is available, a new block is allocated.
|
||||
*
|
||||
* @param numa_node_id NUMA node id to allocate memory for.
|
||||
* @param alignment Alignment of the allocated address.
|
||||
* @param size Size to allocate.
|
||||
* @return Pointer to the allocated memory.
|
||||
*/
|
||||
void *allocate(std::uint8_t numa_node_id, std::size_t alignment, std::size_t size);
|
||||
|
||||
/**
|
||||
* Frees memory from a remote worker.
|
||||
* The memory will be freed lazy, using
|
||||
* a list that will be used for allocation.
|
||||
*
|
||||
* @param calling_numa_id NUMA node id of the freeing worker.
|
||||
* @param allocated_item Header to the allocation.
|
||||
*/
|
||||
void free(const std::uint8_t calling_numa_id, AllocationHeader *allocated_item)
|
||||
{
|
||||
auto *free_header = allocated_item->to_free_header();
|
||||
_remote_free_lists[calling_numa_id].push_back(free_header);
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees a local-worker allocated block.
|
||||
*
|
||||
* @param allocated_block Header to the allocation.
|
||||
*/
|
||||
void free(AllocationHeader *allocated_block);
|
||||
|
||||
/**
|
||||
* Releases all free blocks.
|
||||
*/
|
||||
void release_free_memory();
|
||||
|
||||
/**
|
||||
* Releases all blocks.
|
||||
*/
|
||||
void release_all_memory();
|
||||
|
||||
/**
|
||||
* Refunds memory from the remote list.
|
||||
*/
|
||||
void refund_remote_freed_memory();
|
||||
|
||||
void initialize(std::uint8_t numa_nodes);
|
||||
|
||||
[[nodiscard]] bool is_free() const noexcept;
|
||||
|
||||
private:
|
||||
const std::uint16_t _worker_id;
|
||||
const std::uint8_t _numa_node_id;
|
||||
std::uint32_t _next_block_id{0U};
|
||||
|
||||
/// Every worker can allocate blocks for every numa region.
|
||||
std::array<std::vector<AllocatedBlock>, config::max_numa_nodes()> _allocated_blocks;
|
||||
|
||||
/// Index for every numa node that points from block_id to index in _allocated_blocks.
|
||||
std::array<std::unordered_map<std::uint32_t, std::uint64_t>, config::max_numa_nodes()> _allocated_block_indices;
|
||||
|
||||
std::array<queue::MPSC<FreeHeader>, config::max_numa_nodes()> _remote_free_lists;
|
||||
};
|
||||
|
||||
class Allocator
|
||||
{
|
||||
public:
|
||||
Allocator(const util::core_set &cores);
|
||||
~Allocator();
|
||||
|
||||
void initialize_heap(std::uint16_t worker_id, std::uint8_t count_numa_nodes);
|
||||
|
||||
void *allocate(std::uint16_t worker_id, std::uint8_t numa_node_id, std::size_t alignment, std::size_t size);
|
||||
void free(std::uint16_t calling_worker_id, void *pointer);
|
||||
|
||||
/**
|
||||
* Frees the memory always as a "remote" caller.
|
||||
* For performance reason, this should be used carefully!
|
||||
*
|
||||
* @param pointer Pointer to the data.
|
||||
*/
|
||||
void free(void *pointer);
|
||||
|
||||
/**
|
||||
* Resets all worker-local allocators.
|
||||
*
|
||||
* @param cores New core set (may change in contrast to the current).
|
||||
* @param force_free_memory If set to true, memory should be freed.
|
||||
*/
|
||||
void reset(const util::core_set &cores, bool force_free_memory);
|
||||
|
||||
/**
|
||||
* Cleans the remote free'd memory of a worker-local heap.
|
||||
*
|
||||
* @param worker_id Worker id to clean up.
|
||||
*/
|
||||
void clean_up_remote_freed_memory(const std::uint16_t worker_id)
|
||||
{
|
||||
_worker_local_heaps[worker_id].refund_remote_freed_memory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True, if all blocks of all numa regions are free.
|
||||
*/
|
||||
[[nodiscard]] bool is_free() const noexcept;
|
||||
|
||||
private:
|
||||
/// Map from worker id to numa node id.
|
||||
std::array<std::uint8_t, tasking::config::max_cores()> _numa_node_ids;
|
||||
|
||||
/// One heap for every worker.
|
||||
WorkerHeap *_worker_local_heaps;
|
||||
|
||||
std::uint16_t _count_workers;
|
||||
};
|
||||
|
||||
class CleanUpMemoryTask final : public tasking::TaskInterface
|
||||
{
|
||||
public:
|
||||
constexpr CleanUpMemoryTask(Allocator &allocator) noexcept : _allocator(allocator) {}
|
||||
~CleanUpMemoryTask() noexcept override = default;
|
||||
|
||||
tasking::TaskResult execute(const std::uint16_t worker_id) override
|
||||
{
|
||||
_allocator.clean_up_remote_freed_memory(worker_id);
|
||||
|
||||
return tasking::TaskResult::make_remove();
|
||||
}
|
||||
|
||||
private:
|
||||
Allocator &_allocator;
|
||||
};
|
||||
} // namespace mx::memory::dynamic::local
|
||||
179
repos/ealanos/src/lib/mx/queue/bound_mpmc.h
Normal file
179
repos/ealanos/src/lib/mx/queue/bound_mpmc.h
Normal file
@@ -0,0 +1,179 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <mx/memory/global_heap.h>
|
||||
#include <mx/system/builtin.h>
|
||||
|
||||
namespace mx::queue {
|
||||
/**
|
||||
* Multi producer, multi consumer queue with a fixed number of slots.
|
||||
* Every thread can push and pop values into the queue without using latches.
|
||||
*
|
||||
* Inspired by http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
|
||||
*/
|
||||
template <typename T> class BoundMPMC
|
||||
{
|
||||
public:
|
||||
explicit BoundMPMC(const std::uint64_t capacity) noexcept : _capacity(capacity)
|
||||
{
|
||||
_storage =
|
||||
new (memory::GlobalHeap::allocate_cache_line_aligned(sizeof(std::pair<std::atomic_uint64_t, T>) * capacity))
|
||||
std::pair<std::atomic_uint64_t, T>[capacity];
|
||||
std::memset(static_cast<void *>(_storage), 0, sizeof(std::pair<std::atomic_uint64_t, T>) * capacity);
|
||||
|
||||
for (auto i = 0U; i < capacity; ++i)
|
||||
{
|
||||
std::get<0>(_storage[i]).store(i, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
~BoundMPMC() noexcept { std::free(_storage); }
|
||||
|
||||
// BoundMPMC(const BoundMPMCQueue<T> &) = delete;
|
||||
// BoundMPMC(BoundMPMCQueue<T> &&) = delete;
|
||||
//
|
||||
// BoundMPMC<T> &operator=(const BoundMPMCQueue<T> &) = delete;
|
||||
// BoundMPMC<T> &operator=(BoundMPMCQueue<T> &&) = delete;
|
||||
|
||||
[[nodiscard]] bool empty() const noexcept { return _head.load() == _tail.load(); }
|
||||
|
||||
/**
|
||||
* Inserts the given value.
|
||||
* May block until a slot is available.
|
||||
*
|
||||
* @param item Data to insert.
|
||||
*/
|
||||
void push_back(const T &item) noexcept
|
||||
{
|
||||
while (try_push_back(item) == false)
|
||||
{
|
||||
system::builtin::pause();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes out the next value.
|
||||
* May block until data is available.
|
||||
*
|
||||
* @return The popped value.
|
||||
*/
|
||||
T pop_front() noexcept
|
||||
{
|
||||
T item;
|
||||
while (try_pop_front(item) == false)
|
||||
{
|
||||
system::builtin::pause();
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to take out the next value or the given default value,
|
||||
* if no data is available.
|
||||
*
|
||||
* @param default_value Data that will be returned if no data is available.
|
||||
* @return Popped data or default value.
|
||||
*/
|
||||
T pop_front_or(const T &default_value) noexcept
|
||||
{
|
||||
T item;
|
||||
if (try_pop_front(item))
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
return default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to insert value into the queue.
|
||||
*
|
||||
* @param item Item to insert.
|
||||
* @return True, when successful inserted; false if no slot was available.
|
||||
*/
|
||||
bool try_push_back(const T &item) noexcept
|
||||
{
|
||||
auto pos = _head.load(std::memory_order_relaxed);
|
||||
std::uint64_t slot;
|
||||
for (;;)
|
||||
{
|
||||
slot = pos % _capacity;
|
||||
const auto sequence = std::get<0>(_storage[slot]).load(std::memory_order_acquire);
|
||||
const auto difference = std::int64_t(sequence) - std::int64_t(pos);
|
||||
if (difference == 0)
|
||||
{
|
||||
if (_head.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (difference < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = _head.load(std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
std::get<1>(_storage[slot]) = item;
|
||||
std::get<0>(_storage[slot]).store(pos + 1, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to take the next value.
|
||||
*
|
||||
* @param return_item Item where the next value will be stored.
|
||||
* @return True, when pop was successful; false if no data was available.
|
||||
*/
|
||||
bool try_pop_front(T &return_item) noexcept
|
||||
{
|
||||
auto pos = _tail.load(std::memory_order_relaxed);
|
||||
std::uint64_t slot;
|
||||
for (;;)
|
||||
{
|
||||
slot = pos % _capacity;
|
||||
const auto sequence = std::get<0>(_storage[slot]).load(std::memory_order_acquire);
|
||||
const auto difference = std::int64_t(sequence) - std::int64_t(pos + 1);
|
||||
if (difference == 0)
|
||||
{
|
||||
if (_tail.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (difference < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = _tail.load(std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
return_item = std::get<1>(_storage[slot]);
|
||||
std::get<0>(_storage[slot]).store(pos + _capacity, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Capacity of the queue.
|
||||
const std::uint64_t _capacity;
|
||||
|
||||
// Array of status flags and data slots.
|
||||
std::pair<std::atomic_uint64_t, T> *_storage;
|
||||
|
||||
// Index of the head.
|
||||
alignas(64) std::atomic_uint64_t _head{0U};
|
||||
|
||||
// Index of the tail.
|
||||
alignas(64) std::atomic_uint64_t _tail{0U};
|
||||
};
|
||||
} // namespace mx::queue
|
||||
39
repos/ealanos/src/lib/mx/queue/dynamic_ringpuffer.h
Normal file
39
repos/ealanos/src/lib/mx/queue/dynamic_ringpuffer.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace mx::queue
|
||||
{
|
||||
template<typename T>
|
||||
class DynamicRingpuffer
|
||||
{
|
||||
public:
|
||||
DynamicRingpuffer()
|
||||
{
|
||||
_data = std::aligned_alloc(64U, sizeof(T*) * _capacity);
|
||||
}
|
||||
|
||||
~DynamicRingpuffer()
|
||||
{
|
||||
std::free(_data);
|
||||
}
|
||||
|
||||
void push_back(T* item)
|
||||
{
|
||||
const auto index = (_head++) & _capacity;
|
||||
if (index == _tail)
|
||||
{
|
||||
/// TODO: Reallocate
|
||||
}
|
||||
_data[index] = item;
|
||||
}
|
||||
private:
|
||||
T **_data;
|
||||
std::uint64_t _capacity {1024U};
|
||||
std::uint64_t _head {0U};
|
||||
std::uint64_t _tail {0U};
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
149
repos/ealanos/src/lib/mx/queue/list.h
Normal file
149
repos/ealanos/src/lib/mx/queue/list.h
Normal file
@@ -0,0 +1,149 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace mx::queue {
|
||||
/**
|
||||
* Single producer and consumer queue. This queue is not thread safe.
|
||||
*/
|
||||
template <class T> class alignas(64) List
|
||||
{
|
||||
public:
|
||||
constexpr List() noexcept = default;
|
||||
~List() noexcept = default;
|
||||
|
||||
/**
|
||||
* Inserts an item into the queue.
|
||||
* @param item Item to be inserted.
|
||||
*/
|
||||
void push_back(T *item) noexcept
|
||||
{
|
||||
item->next(nullptr);
|
||||
|
||||
if (_tail != nullptr) [[likely]]
|
||||
{
|
||||
_tail->next(item);
|
||||
_tail = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
_head = _tail = item;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a list of items into the queue.
|
||||
* The items have to be concatenated.
|
||||
*
|
||||
* @param first First item to be inserted.
|
||||
* @param last Last item to be inserted.
|
||||
*/
|
||||
void push_back(T *first, T *last) noexcept
|
||||
{
|
||||
last->next(nullptr);
|
||||
|
||||
if (_tail != nullptr) [[likely]]
|
||||
{
|
||||
_tail->next(first);
|
||||
_tail = last;
|
||||
}
|
||||
else
|
||||
{
|
||||
_head = first;
|
||||
_tail = last;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Begin of the queue.
|
||||
*/
|
||||
[[nodiscard]] T *begin() noexcept { return _head; }
|
||||
|
||||
/**
|
||||
* @return End of the queue.
|
||||
*/
|
||||
[[nodiscard]] const T *end() const noexcept { return _tail; }
|
||||
|
||||
/**
|
||||
* @return End of the queue.
|
||||
*/
|
||||
[[nodiscard]] T *end() noexcept { return _tail; }
|
||||
|
||||
/**
|
||||
* @return True, when the queue is empty.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const noexcept { return _head == nullptr; }
|
||||
|
||||
/**
|
||||
* @return Takes and removes the first item from the queue.
|
||||
*/
|
||||
T *pop_front() noexcept
|
||||
{
|
||||
if (_head == nullptr) [[unlikely]]
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto *head = _head;
|
||||
auto *new_head = head->next();
|
||||
if (new_head == nullptr) [[unlikely]]
|
||||
{
|
||||
_tail = nullptr;
|
||||
}
|
||||
|
||||
_head = new_head;
|
||||
return head;
|
||||
}
|
||||
|
||||
std::pair<T *, std::uint16_t> pop_front(const std::uint16_t limit) noexcept
|
||||
{
|
||||
auto count = 0U;
|
||||
auto *head = _head;
|
||||
auto *current = _head;
|
||||
do
|
||||
{
|
||||
current = current->next();
|
||||
++count;
|
||||
} while (count < limit && current != nullptr);
|
||||
|
||||
_head = current;
|
||||
if (current == nullptr) [[unlikely]]
|
||||
{
|
||||
_tail = nullptr;
|
||||
}
|
||||
|
||||
return std::make_pair(head, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops all items from the list. The items will be concatenated.
|
||||
*
|
||||
* @return Pair of first and last task
|
||||
*/
|
||||
[[nodiscard]] std::pair<T *, T *> pop() noexcept
|
||||
{
|
||||
if (_head == nullptr)
|
||||
{
|
||||
return std::make_pair(nullptr, nullptr);
|
||||
}
|
||||
|
||||
if (_head == _tail)
|
||||
{
|
||||
auto *head = _head;
|
||||
_head = _tail = nullptr;
|
||||
return std::make_pair(head, nullptr);
|
||||
}
|
||||
|
||||
auto *head = std::exchange(_head, nullptr);
|
||||
auto *tail = std::exchange(_tail, nullptr);
|
||||
return std::make_pair(head, tail);
|
||||
}
|
||||
|
||||
private:
|
||||
// Pointer to the head.
|
||||
T *_head{nullptr};
|
||||
|
||||
// Pointer to the tail.
|
||||
T *_tail{nullptr};
|
||||
};
|
||||
} // namespace mx::queue
|
||||
165
repos/ealanos/src/lib/mx/queue/mpsc.h
Normal file
165
repos/ealanos/src/lib/mx/queue/mpsc.h
Normal file
@@ -0,0 +1,165 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <mx/system/cache.h>
|
||||
#include <utility>
|
||||
|
||||
namespace mx::queue {
|
||||
/**
|
||||
* Multi producer, single consumer queue with unlimited slots.
|
||||
* Every thread can push values into the queue without using latches.
|
||||
*
|
||||
* Inspired by http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue
|
||||
*/
|
||||
template <class T> class MPSC
|
||||
{
|
||||
public:
|
||||
constexpr MPSC() noexcept
|
||||
: _head(reinterpret_cast<T *>(_stub.data())), _tail(reinterpret_cast<T *>(_stub.data())),
|
||||
_end(reinterpret_cast<T *>(_stub.data()))
|
||||
{
|
||||
}
|
||||
~MPSC() noexcept = default;
|
||||
|
||||
/**
|
||||
* Inserts the given item into the queue.
|
||||
* @param item Item to insert.
|
||||
*/
|
||||
void push_back(T *item) noexcept
|
||||
{
|
||||
item->next(nullptr);
|
||||
auto *prev = __atomic_exchange_n(&_head, item, __ATOMIC_RELAXED);
|
||||
prev->next(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts all items between begin and end into the queue.
|
||||
* Items must be linked among themselves.
|
||||
* @param begin First item to insert.
|
||||
* @param end Last item to insert.
|
||||
*/
|
||||
void push_back(T *begin, T *end) noexcept
|
||||
{
|
||||
end->next(nullptr);
|
||||
auto *old_head = __atomic_exchange_n(&_head, end, __ATOMIC_RELAXED);
|
||||
old_head->next(begin);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return End of the queue.
|
||||
*/
|
||||
[[nodiscard]] const T *end() const noexcept { return _end; }
|
||||
|
||||
/**
|
||||
* @return True, when the queue is empty.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const noexcept
|
||||
{
|
||||
return _tail == _end && reinterpret_cast<T const &>(_stub).next() == nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Takes and removes the first item from the queue.
|
||||
*/
|
||||
[[nodiscard]] T *pop_front() noexcept;
|
||||
|
||||
/**
|
||||
* Pops all items from the list. The items will be concatenated.
|
||||
* This operation is NOT thread safe.
|
||||
*
|
||||
* @return Pair of first and last task
|
||||
*/
|
||||
[[nodiscard]] std::pair<T *, T *> pop() noexcept;
|
||||
|
||||
private:
|
||||
// Head of the queue (accessed by every producer).
|
||||
alignas(64) T *_head;
|
||||
|
||||
// Tail of the queue (accessed by the consumer and producers if queue is empty)-
|
||||
alignas(64) T *_tail;
|
||||
|
||||
// Pointer to the end.
|
||||
alignas(16) T *const _end;
|
||||
|
||||
// Dummy item for empty queue.
|
||||
alignas(64) std::array<std::byte, sizeof(T)> _stub = {};
|
||||
};
|
||||
|
||||
template <class T> T *MPSC<T>::pop_front() noexcept
|
||||
{
|
||||
auto *tail = this->_tail;
|
||||
auto *next = tail->next();
|
||||
|
||||
if (tail == this->_end)
|
||||
{
|
||||
if (next == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
this->_tail = next;
|
||||
tail = next;
|
||||
next = next->next();
|
||||
}
|
||||
|
||||
if (next != nullptr)
|
||||
{
|
||||
this->_tail = next;
|
||||
return tail;
|
||||
}
|
||||
|
||||
const auto *head = this->_head;
|
||||
if (tail != head)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
this->push_back(this->_end);
|
||||
|
||||
next = tail->next();
|
||||
if (next != nullptr)
|
||||
{
|
||||
this->_tail = next;
|
||||
return tail;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
template <class T> std::pair<T *, T *> MPSC<T>::pop() noexcept
|
||||
{
|
||||
T *head = nullptr;
|
||||
/// Head and tail are interchanged, head is tail and tail is head.
|
||||
if (this->_tail != nullptr)
|
||||
{
|
||||
if (this->_tail != this->_end)
|
||||
{
|
||||
head = this->_tail;
|
||||
}
|
||||
else
|
||||
{
|
||||
head = this->_tail->next();
|
||||
}
|
||||
}
|
||||
|
||||
if (head == nullptr)
|
||||
{
|
||||
return std::make_pair(nullptr, nullptr);
|
||||
}
|
||||
|
||||
if (this->_head == nullptr || this->_head == this->_end)
|
||||
{
|
||||
head->next(nullptr);
|
||||
return std::make_pair(head, nullptr);
|
||||
}
|
||||
|
||||
auto *tail = std::exchange(this->_head, this->_end);
|
||||
tail->next(nullptr);
|
||||
this->_tail = this->_end;
|
||||
|
||||
return std::make_pair(head, tail);
|
||||
}
|
||||
|
||||
} // namespace mx::queue
|
||||
49
repos/ealanos/src/lib/mx/queue/priority_queue.h
Normal file
49
repos/ealanos/src/lib/mx/queue/priority_queue.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <mx/tasking/priority.h>
|
||||
|
||||
namespace mx::queue {
|
||||
template <class Q, tasking::priority MIN_PRIORITY, tasking::priority MAX_PRIORITY> class PriorityQueue
|
||||
{
|
||||
public:
|
||||
PriorityQueue() = default;
|
||||
~PriorityQueue() = default;
|
||||
|
||||
template <tasking::priority P> Q &get() noexcept
|
||||
{
|
||||
static_assert(static_cast<std::uint8_t>(P) >= static_cast<std::uint8_t>(MIN_PRIORITY));
|
||||
static_assert(static_cast<std::uint8_t>(P) <= static_cast<std::uint8_t>(MAX_PRIORITY));
|
||||
|
||||
return _queues[static_cast<std::uint8_t>(P) - static_cast<std::uint8_t>(MIN_PRIORITY)];
|
||||
}
|
||||
|
||||
template <tasking::priority P> const Q &get() const noexcept
|
||||
{
|
||||
static_assert(static_cast<std::uint8_t>(P) >= static_cast<std::uint8_t>(MIN_PRIORITY));
|
||||
static_assert(static_cast<std::uint8_t>(P) <= static_cast<std::uint8_t>(MAX_PRIORITY));
|
||||
|
||||
return _queues[static_cast<std::uint8_t>(P) - static_cast<std::uint8_t>(MIN_PRIORITY)];
|
||||
}
|
||||
|
||||
Q &get(const tasking::priority priority) noexcept
|
||||
{
|
||||
assert(priority >= static_cast<std::uint8_t>(MIN_PRIORITY));
|
||||
assert(priority <= static_cast<std::uint8_t>(MAX_PRIORITY));
|
||||
|
||||
return _queues[static_cast<std::uint8_t>(priority) - static_cast<std::uint8_t>(MIN_PRIORITY)];
|
||||
}
|
||||
|
||||
const Q &get(const tasking::priority priority) const noexcept
|
||||
{
|
||||
assert(priority >= static_cast<std::uint8_t>(MIN_PRIORITY));
|
||||
assert(priority <= static_cast<std::uint8_t>(MAX_PRIORITY));
|
||||
|
||||
return _queues[static_cast<std::uint8_t>(priority) - static_cast<std::uint8_t>(MIN_PRIORITY)];
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<Q, static_cast<std::uint8_t>(MAX_PRIORITY) - static_cast<std::uint8_t>(MIN_PRIORITY) + 1U> _queues{};
|
||||
};
|
||||
} // namespace mx::queue
|
||||
146
repos/ealanos/src/lib/mx/resource/annotation.h
Normal file
146
repos/ealanos/src/lib/mx/resource/annotation.h
Normal file
@@ -0,0 +1,146 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <mx/synchronization/synchronization.h>
|
||||
#include <variant>
|
||||
|
||||
namespace mx::resource {
|
||||
enum expected_access_frequency : std::uint8_t
|
||||
{
|
||||
excessive = 0U,
|
||||
high = 1U,
|
||||
normal = 2U,
|
||||
unused = 3U,
|
||||
};
|
||||
|
||||
enum expected_read_write_ratio : std::uint8_t
|
||||
{
|
||||
heavy_read = 0U,
|
||||
mostly_read = 1U,
|
||||
balanced = 2U,
|
||||
mostly_written = 3U,
|
||||
heavy_written = 4U
|
||||
};
|
||||
|
||||
class annotation
|
||||
{
|
||||
public:
|
||||
constexpr annotation() noexcept = default;
|
||||
constexpr explicit annotation(const std::uint8_t node_id) noexcept : _target(node_id) {}
|
||||
constexpr explicit annotation(const std::uint16_t worker_id) noexcept : _target(worker_id) {}
|
||||
constexpr explicit annotation(const synchronization::isolation_level isolation_level) noexcept
|
||||
: _isolation_level(isolation_level)
|
||||
{
|
||||
}
|
||||
constexpr explicit annotation(const expected_access_frequency access_frequency) noexcept
|
||||
: _access_frequency(access_frequency)
|
||||
{
|
||||
}
|
||||
constexpr annotation(const std::uint16_t worker_id, const synchronization::isolation_level isolation_level) noexcept
|
||||
: _target(worker_id), _isolation_level(isolation_level)
|
||||
{
|
||||
}
|
||||
constexpr annotation(const std::uint8_t node_id, const synchronization::isolation_level isolation_level) noexcept
|
||||
: _target(node_id), _isolation_level(isolation_level)
|
||||
{
|
||||
}
|
||||
constexpr annotation(const std::uint8_t node_id, const synchronization::isolation_level isolation_level,
|
||||
const synchronization::protocol preferred_protocol) noexcept
|
||||
: _target(node_id), _isolation_level(isolation_level), _preferred_protocol(preferred_protocol)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr annotation(const std::uint16_t worker_id, const synchronization::isolation_level isolation_level,
|
||||
const synchronization::protocol preferred_protocol) noexcept
|
||||
: _target(worker_id), _isolation_level(isolation_level), _preferred_protocol(preferred_protocol)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr annotation(const std::uint8_t node_id, const expected_access_frequency access_frequency) noexcept
|
||||
: _target(node_id), _access_frequency(access_frequency)
|
||||
{
|
||||
}
|
||||
constexpr annotation(const synchronization::isolation_level isolation_level,
|
||||
const expected_access_frequency access_frequency) noexcept
|
||||
: _access_frequency(access_frequency), _isolation_level(isolation_level)
|
||||
{
|
||||
}
|
||||
constexpr annotation(const synchronization::isolation_level isolation_level,
|
||||
const synchronization::protocol preferred_protocol,
|
||||
const expected_access_frequency access_frequency) noexcept
|
||||
: _access_frequency(access_frequency), _isolation_level(isolation_level),
|
||||
_preferred_protocol(preferred_protocol)
|
||||
{
|
||||
}
|
||||
constexpr annotation(const synchronization::isolation_level isolation_level,
|
||||
const synchronization::protocol preferred_protocol,
|
||||
const expected_access_frequency access_frequency,
|
||||
const expected_read_write_ratio read_write_ratio) noexcept
|
||||
: _access_frequency(access_frequency), _read_write_ratio(read_write_ratio), _isolation_level(isolation_level),
|
||||
_preferred_protocol(preferred_protocol)
|
||||
{
|
||||
}
|
||||
constexpr annotation(const std::uint8_t node_id, const synchronization::isolation_level isolation_level,
|
||||
const expected_access_frequency access_frequency) noexcept
|
||||
: _target(node_id), _access_frequency(access_frequency), _isolation_level(isolation_level)
|
||||
{
|
||||
}
|
||||
constexpr annotation(const std::uint8_t node_id, const synchronization::isolation_level isolation_level,
|
||||
const synchronization::protocol preferred_protocol,
|
||||
const expected_access_frequency access_frequency) noexcept
|
||||
: _target(node_id), _access_frequency(access_frequency), _isolation_level(isolation_level),
|
||||
_preferred_protocol(preferred_protocol)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr annotation(annotation &&) noexcept = default;
|
||||
constexpr annotation(const annotation &) noexcept = default;
|
||||
|
||||
~annotation() = default;
|
||||
|
||||
annotation &operator=(annotation &&) noexcept = default;
|
||||
annotation &operator=(const annotation &) noexcept = default;
|
||||
|
||||
[[nodiscard]] bool has_numa_node_id() const noexcept { return std::holds_alternative<std::uint8_t>(_target); }
|
||||
[[nodiscard]] std::uint8_t numa_node_id() const noexcept { return std::get<std::uint8_t>(_target); }
|
||||
|
||||
[[nodiscard]] bool has_worker_id() const noexcept { return std::holds_alternative<std::uint16_t>(_target); }
|
||||
[[nodiscard]] std::uint16_t worker_id() const noexcept { return std::get<std::uint16_t>(_target); }
|
||||
[[nodiscard]] expected_access_frequency access_frequency() const noexcept { return _access_frequency; }
|
||||
[[nodiscard]] expected_read_write_ratio read_write_ratio() const noexcept { return _read_write_ratio; }
|
||||
[[nodiscard]] synchronization::isolation_level isolation_level() const noexcept { return _isolation_level; }
|
||||
[[nodiscard]] synchronization::protocol preferred_protocol() const noexcept { return _preferred_protocol; }
|
||||
|
||||
bool operator==(const synchronization::isolation_level isolation_level) const noexcept
|
||||
{
|
||||
return _isolation_level == isolation_level;
|
||||
}
|
||||
|
||||
bool operator!=(const synchronization::isolation_level isolation_level) const noexcept
|
||||
{
|
||||
return _isolation_level != isolation_level;
|
||||
}
|
||||
|
||||
bool operator==(const synchronization::protocol protocol) const noexcept { return _preferred_protocol == protocol; }
|
||||
|
||||
bool operator!=(const synchronization::protocol protocol) const noexcept { return _preferred_protocol != protocol; }
|
||||
|
||||
private:
|
||||
// Preferred NUMA region or CPU core (if any).
|
||||
std::variant<std::uint8_t, std::uint16_t, std::monostate> _target{std::monostate{}};
|
||||
|
||||
// Expected access frequency; normal by default.
|
||||
enum expected_access_frequency _access_frequency
|
||||
{
|
||||
expected_access_frequency::normal
|
||||
};
|
||||
|
||||
// Expected read/write ratio; normal by default.
|
||||
expected_read_write_ratio _read_write_ratio{expected_read_write_ratio::balanced};
|
||||
|
||||
// Preferred isolation level; no synchronization by default.
|
||||
synchronization::isolation_level _isolation_level{synchronization::isolation_level::None};
|
||||
|
||||
// Preferred synchronization protocol (queue, latch, ...); no synchronization by default.
|
||||
synchronization::protocol _preferred_protocol{synchronization::protocol::None};
|
||||
};
|
||||
} // namespace mx::resource
|
||||
80
repos/ealanos/src/lib/mx/resource/builder.cpp
Normal file
80
repos/ealanos/src/lib/mx/resource/builder.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#include "builder.h"
|
||||
#include <mx/synchronization/primitive_matrix.h>
|
||||
|
||||
using namespace mx::resource;
|
||||
|
||||
std::pair<std::uint16_t, std::uint8_t> Builder::schedule(const resource::annotation &annotation)
|
||||
{
|
||||
// Scheduling was done by the hint.
|
||||
if (annotation.has_worker_id())
|
||||
{
|
||||
this->_scheduler.predict_usage(annotation.worker_id(), annotation.access_frequency());
|
||||
return std::make_pair(annotation.worker_id(), this->_scheduler.numa_node_id(annotation.worker_id()));
|
||||
}
|
||||
|
||||
// Schedule resources round robin to the channels.
|
||||
const auto count_worker = this->_scheduler.count_cores();
|
||||
auto worker_id = this->_round_robin_worker_id.fetch_add(1U, std::memory_order_relaxed) % count_worker;
|
||||
|
||||
// If the chosen channel contains an excessive accessed resource, get another.
|
||||
if (count_worker > 2U && annotation.isolation_level() == synchronization::isolation_level::Exclusive &&
|
||||
this->_scheduler.has_excessive_usage_prediction(worker_id))
|
||||
{
|
||||
worker_id = this->_round_robin_worker_id.fetch_add(1U, std::memory_order_relaxed) % count_worker;
|
||||
}
|
||||
this->_scheduler.predict_usage(worker_id, annotation.access_frequency());
|
||||
|
||||
// TODO: NUMA NODE ID is for worker, not channel.
|
||||
const auto numa_node_id =
|
||||
annotation.has_numa_node_id() ? annotation.numa_node_id() : this->_scheduler.numa_node_id(worker_id);
|
||||
|
||||
return std::make_pair(worker_id, numa_node_id);
|
||||
}
|
||||
|
||||
mx::synchronization::primitive Builder::isolation_level_to_synchronization_primitive(
|
||||
const annotation &annotation) noexcept
|
||||
{
|
||||
// The developer did not define any fixed protocol for
|
||||
// synchronization; we choose one depending on the hints.
|
||||
if (annotation == synchronization::protocol::None)
|
||||
{
|
||||
return synchronization::PrimitiveMatrix::select_primitive(
|
||||
annotation.isolation_level(), annotation.access_frequency(), annotation.read_write_ratio());
|
||||
}
|
||||
|
||||
// The developer hinted a specific protocol (latched, queued, ...)
|
||||
// and a relaxed isolation level.
|
||||
if (annotation == synchronization::isolation_level::ExclusiveWriter)
|
||||
{
|
||||
switch (annotation.preferred_protocol())
|
||||
{
|
||||
case synchronization::protocol::Latch:
|
||||
return synchronization::primitive::ReaderWriterLatch;
|
||||
case synchronization::protocol::OLFIT:
|
||||
return synchronization::primitive::OLFIT;
|
||||
case synchronization::protocol::RestrictedTransactionalMemory:
|
||||
return synchronization::primitive::RestrictedTransactionalMemory;
|
||||
default:
|
||||
return synchronization::primitive::ScheduleWriter;
|
||||
}
|
||||
}
|
||||
|
||||
// The developer hinted a specific protocol (latched, queued, ...)
|
||||
// and a strict isolation level.
|
||||
if (annotation == synchronization::isolation_level::Exclusive)
|
||||
{
|
||||
switch (annotation.preferred_protocol())
|
||||
{
|
||||
case synchronization::protocol::Latch:
|
||||
return synchronization::primitive::ExclusiveLatch;
|
||||
case synchronization::protocol::Batched:
|
||||
return synchronization::primitive::Batched;
|
||||
case synchronization::protocol::RestrictedTransactionalMemory:
|
||||
return synchronization::primitive::RestrictedTransactionalMemory;
|
||||
default:
|
||||
return synchronization::primitive::ScheduleAll;
|
||||
}
|
||||
}
|
||||
|
||||
return mx::synchronization::primitive::None;
|
||||
}
|
||||
617
repos/ealanos/src/lib/mx/resource/builder.d
Normal file
617
repos/ealanos/src/lib/mx/resource/builder.d
Normal file
@@ -0,0 +1,617 @@
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/builder.o /home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/builder.d: \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/builder.cpp \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/builder.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/annotation.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646 \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp \
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h \
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/mpsc.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/core_set.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/set \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/scheduler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_distance.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/shared_task_queue.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/bound_mpmc.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/priority_queue.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_squad.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/worker.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/load.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_counter.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/aligned_t.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_buffer.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/ecpp/static_vector.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/compare \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_cycle_sampler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_map.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_hash.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_growth_policy.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/climits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ratio \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_execution_time_history.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool_occupancy.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_queues.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/maybe_atomic.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/primitive_matrix.h
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/builder.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/annotation.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/mpsc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/core_set.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/set:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/scheduler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_distance.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/shared_task_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/bound_mpmc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/priority_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_squad.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/worker.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/load.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_counter.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/aligned_t.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_buffer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/ecpp/static_vector.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/compare:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_cycle_sampler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_map.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_hash.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_growth_policy.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/climits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ratio:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_execution_time_history.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool_occupancy.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_queues.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/maybe_atomic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/primitive_matrix.h:
|
||||
175
repos/ealanos/src/lib/mx/resource/builder.h
Normal file
175
repos/ealanos/src/lib/mx/resource/builder.h
Normal file
@@ -0,0 +1,175 @@
|
||||
#pragma once
|
||||
#include "annotation.h"
|
||||
#include "ptr.h"
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <mx/memory/global_heap.h>
|
||||
#include <mx/memory/worker_local_dynamic_size_allocator.h>
|
||||
#include <mx/tasking/config.h>
|
||||
#include <mx/tasking/scheduler.h>
|
||||
#include <mx/util/aligned_t.h>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace mx::resource {
|
||||
/**
|
||||
* The Builder constructs and deletes data objects.
|
||||
* Besides, the Builder schedules data objects to
|
||||
* channels.
|
||||
*/
|
||||
class Builder
|
||||
{
|
||||
public:
|
||||
Builder(tasking::Scheduler &scheduler, memory::dynamic::local::Allocator &allocator) noexcept
|
||||
: _allocator(allocator), _scheduler(scheduler)
|
||||
{
|
||||
}
|
||||
|
||||
~Builder() noexcept = default;
|
||||
|
||||
/**
|
||||
* Build a data object of given type with given
|
||||
* size and arguments. The hint defines the synchronization
|
||||
* requirements and affects scheduling.
|
||||
*
|
||||
* @param calling_worker_id Id of the calling worker for local allocation.
|
||||
* @param size Size of the data object.
|
||||
* @param hint Hint for scheduling and synchronization.
|
||||
* @param arguments Arguments to the constructor.
|
||||
* @return Tagged pointer holding the synchronization, assigned channel and pointer.
|
||||
*/
|
||||
template <typename T, typename... Args>
|
||||
ptr build(const std::uint16_t calling_worker_id, const std::size_t size, annotation &&annotation,
|
||||
Args &&...arguments) noexcept
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (annotation != synchronization::isolation_level::None &&
|
||||
(annotation != synchronization::isolation_level::Exclusive ||
|
||||
annotation != synchronization::protocol::Queue) &&
|
||||
(annotation != synchronization::isolation_level::Exclusive &&
|
||||
annotation != synchronization::protocol::Batched))
|
||||
{
|
||||
if constexpr (std::is_base_of<ResourceInterface, T>::value == false)
|
||||
{
|
||||
assert(false && "Type must be inherited from mx::resource::ResourceInterface");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto synchronization_method = Builder::isolation_level_to_synchronization_primitive(annotation);
|
||||
|
||||
const auto [mapped_worker_id, numa_node_id] = schedule(annotation);
|
||||
|
||||
auto *resource = new (_allocator.allocate(calling_worker_id, numa_node_id, system::cache::line_size(), size))
|
||||
T(std::forward<Args>(arguments)...);
|
||||
|
||||
if constexpr (std::is_base_of<ResourceInterface, T>::value)
|
||||
{
|
||||
switch (synchronization_method)
|
||||
{
|
||||
case synchronization::primitive::ExclusiveLatch:
|
||||
case synchronization::primitive::RestrictedTransactionalMemory:
|
||||
resource->initialize(ResourceInterface::SynchronizationType::Exclusive);
|
||||
break;
|
||||
case synchronization::primitive::ReaderWriterLatch:
|
||||
resource->initialize(ResourceInterface::SynchronizationType::SharedWrite);
|
||||
break;
|
||||
case synchronization::primitive::OLFIT:
|
||||
case synchronization::primitive::ScheduleWriter:
|
||||
resource->initialize(ResourceInterface::SynchronizationType::OLFIT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const auto resource_information = information{mapped_worker_id, synchronization_method};
|
||||
return ptr{resource, resource_information};
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds data resourced from an existing pointer.
|
||||
* The hint defines the synchronization
|
||||
* requirements and affects scheduling.
|
||||
* @param object
|
||||
* @param annotation Hint for scheduling and synchronization.
|
||||
* @return Tagged pointer holding the synchronization, assigned channel and pointer.
|
||||
*/
|
||||
template <typename T> ptr build(T *object, annotation &&annotation) noexcept
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (annotation != synchronization::isolation_level::None &&
|
||||
(annotation != synchronization::isolation_level::Exclusive ||
|
||||
annotation != synchronization::protocol::Queue) &&
|
||||
(annotation != synchronization::isolation_level::Exclusive &&
|
||||
annotation != synchronization::protocol::Batched))
|
||||
{
|
||||
if constexpr (std::is_base_of<ResourceInterface, T>::value == false)
|
||||
{
|
||||
assert(false && "Type must be inherited from mx::resource::ResourceInterface");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto synchronization_method = Builder::isolation_level_to_synchronization_primitive(annotation);
|
||||
const auto [worker_id, _] = schedule(annotation);
|
||||
|
||||
return ptr{object, information{worker_id, synchronization_method}};
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the given data object.
|
||||
* @param calling_worker_id Worker calling destroy for local free.
|
||||
* @param resource Tagged pointer to the data object.
|
||||
*/
|
||||
template <typename T> void destroy(const std::uint16_t calling_worker_id, const ptr resource)
|
||||
{
|
||||
// TODO: Revoke usage prediction?
|
||||
if (resource != nullptr)
|
||||
{
|
||||
if constexpr (tasking::config::memory_reclamation() != tasking::config::None)
|
||||
{
|
||||
if (synchronization::is_optimistic(resource.synchronization_primitive()))
|
||||
{
|
||||
_scheduler.epoch_manager().add_to_garbage_collection(resource.get<ResourceInterface>(),
|
||||
resource.worker_id());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No need to reclaim memory.
|
||||
resource.get<T>()->~T();
|
||||
_allocator.free(calling_worker_id, resource.get<void>());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Internal allocator for dynamic sized allocation.
|
||||
memory::dynamic::local::Allocator &_allocator;
|
||||
|
||||
// Scheduler of MxTasking to get access to channels.
|
||||
tasking::Scheduler &_scheduler;
|
||||
|
||||
// Next channel id for round-robin scheduling.
|
||||
alignas(64) std::atomic_uint16_t _round_robin_worker_id{0U};
|
||||
|
||||
/**
|
||||
* Schedules the resource to a channel, affected by the given hint.
|
||||
*
|
||||
* @param annotation Hint for scheduling.
|
||||
* @return Pair of Channel and NUMA node IDs.
|
||||
*/
|
||||
std::pair<std::uint16_t, std::uint8_t> schedule(const annotation &annotation);
|
||||
|
||||
/**
|
||||
* Determines the best synchronization method based on
|
||||
* synchronization requirement.
|
||||
*
|
||||
* @param annotation Hint for choosing the primitive.
|
||||
* @return Chosen synchronization method.
|
||||
*/
|
||||
static synchronization::primitive isolation_level_to_synchronization_primitive(
|
||||
const annotation &annotation) noexcept;
|
||||
};
|
||||
} // namespace mx::resource
|
||||
99
repos/ealanos/src/lib/mx/resource/ptr.h
Normal file
99
repos/ealanos/src/lib/mx/resource/ptr.h
Normal file
@@ -0,0 +1,99 @@
|
||||
#pragma once
|
||||
|
||||
#include "resource_interface.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <mx/memory/alignment_helper.h>
|
||||
#include <mx/memory/tagged_ptr.h>
|
||||
#include <mx/synchronization/synchronization.h>
|
||||
#include <mx/util/random.h>
|
||||
#include <new>
|
||||
|
||||
namespace mx::resource {
|
||||
/**
|
||||
* Information of a resource, stored within
|
||||
* the pointer to the resource.
|
||||
*/
|
||||
class information
|
||||
{
|
||||
public:
|
||||
constexpr information() noexcept = default;
|
||||
explicit information(const std::uint16_t worker_id,
|
||||
const synchronization::primitive synchronization_primitive) noexcept
|
||||
: _worker_id(worker_id), _synchronization_primitive(static_cast<std::uint16_t>(synchronization_primitive))
|
||||
{
|
||||
}
|
||||
|
||||
~information() = default;
|
||||
|
||||
[[nodiscard]] std::uint16_t worker_id() const noexcept { return _worker_id; }
|
||||
[[nodiscard]] synchronization::primitive synchronization_primitive() const noexcept
|
||||
{
|
||||
return static_cast<synchronization::primitive>(_synchronization_primitive);
|
||||
}
|
||||
|
||||
void worker_id(const std::uint16_t worker_id) noexcept { _worker_id = worker_id; }
|
||||
void synchronization_primitive(const synchronization::primitive primitive) noexcept
|
||||
{
|
||||
_synchronization_primitive = static_cast<std::uint16_t>(primitive);
|
||||
}
|
||||
|
||||
information &operator=(const information &other) = default;
|
||||
|
||||
private:
|
||||
std::uint16_t _worker_id : 12 {0U};
|
||||
std::uint16_t _synchronization_primitive : 4 {0U};
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* Pointer to a resource, stores information about
|
||||
* that resource.
|
||||
*/
|
||||
class ptr final : public memory::tagged_ptr<void, information>
|
||||
{
|
||||
public:
|
||||
constexpr ptr() noexcept = default;
|
||||
constexpr ptr(const std::nullptr_t /*nullptr*/) noexcept : memory::tagged_ptr<void, information>(nullptr) {}
|
||||
constexpr explicit ptr(void *ptr_, const information info = {}) noexcept
|
||||
: memory::tagged_ptr<void, information>(ptr_, info)
|
||||
{
|
||||
}
|
||||
~ptr() = default;
|
||||
|
||||
ptr &operator=(const ptr &other) noexcept = default;
|
||||
ptr &operator=(std::nullptr_t) noexcept
|
||||
{
|
||||
reset(nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint16_t worker_id() const noexcept { return info().worker_id(); }
|
||||
[[nodiscard]] synchronization::primitive synchronization_primitive() const noexcept
|
||||
{
|
||||
return info().synchronization_primitive();
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* Casts the internal pointer of the resource pointer
|
||||
* to a pointer typed by the given template parameter.
|
||||
*
|
||||
* @param resource Resource to cast.
|
||||
* @return Pointer to the requested type.
|
||||
*/
|
||||
template <typename S> static auto *ptr_cast(const ptr resource) noexcept
|
||||
{
|
||||
return resource.template get<S>();
|
||||
}
|
||||
|
||||
} // namespace mx::resource
|
||||
|
||||
namespace std {
|
||||
template <> struct hash<mx::resource::ptr>
|
||||
{
|
||||
std::size_t operator()(const mx::resource::ptr ptr) const noexcept
|
||||
{
|
||||
return std::hash<void *>().operator()(ptr.get());
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
187
repos/ealanos/src/lib/mx/resource/resource_interface.h
Normal file
187
repos/ealanos/src/lib/mx/resource/resource_interface.h
Normal file
@@ -0,0 +1,187 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <mx/memory/reclamation/epoch_t.h>
|
||||
#include <mx/synchronization/memory_transaction.h>
|
||||
#include <mx/synchronization/optimistic_lock.h>
|
||||
#include <mx/synchronization/rw_spinlock.h>
|
||||
#include <mx/synchronization/spinlock.h>
|
||||
|
||||
namespace mx::resource {
|
||||
/**
|
||||
* The resource interface represents resources that
|
||||
* needs to be synchronized by the tasking engine.
|
||||
* Supported synchronizations are:
|
||||
* - Latches (Spinlock, R/W-lock)
|
||||
* - Optimistic latches + memory reclamation
|
||||
*/
|
||||
class ResourceInterface
|
||||
{
|
||||
public:
|
||||
enum SynchronizationType : std::uint8_t
|
||||
{
|
||||
Exclusive,
|
||||
SharedRead,
|
||||
SharedWrite,
|
||||
Optimistic,
|
||||
OLFIT,
|
||||
RestrictedTransactionalMemory,
|
||||
};
|
||||
|
||||
constexpr ResourceInterface() noexcept = default;
|
||||
ResourceInterface(const ResourceInterface &) = delete;
|
||||
ResourceInterface(ResourceInterface &&) = delete;
|
||||
virtual ~ResourceInterface() = default;
|
||||
|
||||
void initialize(const SynchronizationType type) noexcept
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Exclusive:
|
||||
case RestrictedTransactionalMemory:
|
||||
_exclusive_latch.unlock();
|
||||
break;
|
||||
case SharedRead:
|
||||
case SharedWrite:
|
||||
_rw_latch.initialize();
|
||||
break;
|
||||
case Optimistic:
|
||||
case OLFIT:
|
||||
_optimistic_latch.initialize();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the epoch manager on safe reclaiming this resource.
|
||||
*/
|
||||
virtual void on_reclaim() = 0;
|
||||
|
||||
/**
|
||||
* Set the next resource in garbage list.
|
||||
* @param next Next resource in garbage list.
|
||||
*/
|
||||
void next(ResourceInterface *next) noexcept { _next_garbage = next; }
|
||||
|
||||
/**
|
||||
* @return Next resource in garbage list.
|
||||
*/
|
||||
[[nodiscard]] ResourceInterface *next() const noexcept { return _next_garbage; }
|
||||
|
||||
/**
|
||||
* @return The current version of the resource.
|
||||
*/
|
||||
[[nodiscard]] synchronization::OptimisticLock::version_t version() const noexcept
|
||||
{
|
||||
return _optimistic_latch.read_valid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given version is still valid.
|
||||
*
|
||||
* @param version Version to check.
|
||||
* @return True, when the version is valid.
|
||||
*/
|
||||
[[nodiscard]] bool is_version_valid(const synchronization::OptimisticLock::version_t version) const noexcept
|
||||
{
|
||||
return _optimistic_latch.is_valid(version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to acquire the optimistic latch.
|
||||
* @return True, when latch was acquired.
|
||||
*/
|
||||
[[nodiscard]] bool try_acquire_optimistic_latch() noexcept { return _optimistic_latch.try_lock(); }
|
||||
|
||||
/**
|
||||
* Set the epoch-timestamp this resource was removed.
|
||||
* @param epoch Epoch where this resource was removed.
|
||||
*/
|
||||
void remove_epoch(const memory::reclamation::epoch_t epoch) noexcept { _remove_epoch = epoch; }
|
||||
|
||||
/**
|
||||
* @return The epoch this resource was removed.
|
||||
*/
|
||||
[[nodiscard]] memory::reclamation::epoch_t remove_epoch() const noexcept { return _remove_epoch; }
|
||||
|
||||
template <SynchronizationType T> class scoped_latch
|
||||
{
|
||||
public:
|
||||
constexpr inline explicit scoped_latch(ResourceInterface *resource) noexcept : _resource(resource)
|
||||
{
|
||||
if constexpr (T == SynchronizationType::Exclusive)
|
||||
{
|
||||
_resource->_exclusive_latch.lock();
|
||||
}
|
||||
else if constexpr (T == SynchronizationType::SharedRead)
|
||||
{
|
||||
_resource->_rw_latch.lock_shared();
|
||||
}
|
||||
else if constexpr (T == SynchronizationType::SharedWrite)
|
||||
{
|
||||
_resource->_rw_latch.lock();
|
||||
}
|
||||
else if constexpr (T == SynchronizationType::Optimistic)
|
||||
{
|
||||
_resource->_optimistic_latch.lock<true>();
|
||||
}
|
||||
else if constexpr (T == SynchronizationType::OLFIT)
|
||||
{
|
||||
_resource->_optimistic_latch.lock<false>();
|
||||
}
|
||||
else if constexpr (T == SynchronizationType::RestrictedTransactionalMemory)
|
||||
{
|
||||
_is_transaction_used_latch = synchronization::MemoryTransaction::begin(_resource->_exclusive_latch);
|
||||
}
|
||||
}
|
||||
|
||||
inline ~scoped_latch() noexcept
|
||||
{
|
||||
if constexpr (T == SynchronizationType::Exclusive)
|
||||
{
|
||||
_resource->_exclusive_latch.unlock();
|
||||
}
|
||||
else if constexpr (T == SynchronizationType::SharedRead)
|
||||
{
|
||||
_resource->_rw_latch.unlock_shared();
|
||||
}
|
||||
else if constexpr (T == SynchronizationType::SharedWrite)
|
||||
{
|
||||
_resource->_rw_latch.unlock();
|
||||
}
|
||||
else if constexpr (T == SynchronizationType::Optimistic || T == SynchronizationType::OLFIT)
|
||||
{
|
||||
_resource->_optimistic_latch.unlock();
|
||||
}
|
||||
else if constexpr (T == SynchronizationType::RestrictedTransactionalMemory)
|
||||
{
|
||||
synchronization::MemoryTransaction::end(_resource->_exclusive_latch, _is_transaction_used_latch);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ResourceInterface *_resource;
|
||||
bool _is_transaction_used_latch;
|
||||
};
|
||||
|
||||
using scoped_exclusive_latch = scoped_latch<SynchronizationType::Exclusive>;
|
||||
using scoped_optimistic_latch = scoped_latch<SynchronizationType::Optimistic>;
|
||||
using scoped_olfit_latch = scoped_latch<SynchronizationType::OLFIT>;
|
||||
template <bool WRITER>
|
||||
using scoped_rw_latch = scoped_latch<WRITER ? SynchronizationType::SharedWrite : SynchronizationType::SharedRead>;
|
||||
using scoped_transaction = scoped_latch<SynchronizationType::RestrictedTransactionalMemory>;
|
||||
|
||||
private:
|
||||
// Encapsulated synchronization primitives.
|
||||
union {
|
||||
synchronization::Spinlock _exclusive_latch;
|
||||
synchronization::RWSpinLock _rw_latch;
|
||||
synchronization::OptimisticLock _optimistic_latch;
|
||||
};
|
||||
|
||||
// Epoch and Garbage management.
|
||||
memory::reclamation::epoch_t _remove_epoch{0U};
|
||||
ResourceInterface *_next_garbage{nullptr};
|
||||
};
|
||||
} // namespace mx::resource
|
||||
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
#include "spinlock.h"
|
||||
#ifdef USE_RTM
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
namespace mx::synchronization {
|
||||
class MemoryTransaction
|
||||
{
|
||||
private:
|
||||
[[nodiscard]] static constexpr auto max_tries() { return 10U; }
|
||||
[[nodiscard]] static constexpr auto abort_because_locked_code() { return 0xFF; }
|
||||
|
||||
public:
|
||||
[[nodiscard]] static bool begin(Spinlock &latch) noexcept
|
||||
{
|
||||
#ifdef USE_RTM
|
||||
auto retries = 0U;
|
||||
|
||||
do
|
||||
{
|
||||
const auto status = _xbegin();
|
||||
if (status == _XBEGIN_STARTED)
|
||||
{
|
||||
if (latch.is_locked() == false)
|
||||
{
|
||||
/// Transaction was started successfully
|
||||
/// and the latch was not acquired by another thread.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Transaction was started, but lock was acquired from another thread.
|
||||
_xabort(abort_because_locked_code());
|
||||
}
|
||||
else if (status & _XABORT_EXPLICIT)
|
||||
{
|
||||
if (_XABORT_CODE(status) == abort_because_locked_code() && (status & _XABORT_NESTED) == false)
|
||||
{
|
||||
/// The transaction was aborted because another thread
|
||||
/// holds the lock. Wait until the thread releases
|
||||
/// the lock.
|
||||
while (latch.is_locked())
|
||||
{
|
||||
mx::system::builtin::pause();
|
||||
}
|
||||
}
|
||||
else if ((status & _XABORT_RETRY) == false)
|
||||
{
|
||||
/// The system tells us, that we should not retry.
|
||||
/// Hence, acquire the latch.
|
||||
goto acquire_fallback_lock;
|
||||
}
|
||||
}
|
||||
} while (++retries <= max_tries());
|
||||
|
||||
acquire_fallback_lock:
|
||||
latch.lock();
|
||||
return true;
|
||||
#else
|
||||
latch.lock();
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void end(Spinlock &latch, [[maybe_unused]] const bool has_locked) noexcept
|
||||
{
|
||||
#ifdef USE_RTM
|
||||
if (has_locked == false)
|
||||
{
|
||||
_xend();
|
||||
}
|
||||
else
|
||||
{
|
||||
latch.unlock();
|
||||
}
|
||||
#else
|
||||
latch.unlock();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
} // namespace mx::synchronization
|
||||
92
repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h
Normal file
92
repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h
Normal file
@@ -0,0 +1,92 @@
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <mx/system/builtin.h>
|
||||
#include <mx/tasking/config.h>
|
||||
|
||||
namespace mx::synchronization {
|
||||
class OptimisticLock
|
||||
{
|
||||
public:
|
||||
using version_t = std::uint32_t;
|
||||
|
||||
constexpr OptimisticLock() = default;
|
||||
~OptimisticLock() = default;
|
||||
|
||||
void initialize() { _version = 0b100; }
|
||||
|
||||
/**
|
||||
* Guarantees to read a valid version by blocking until
|
||||
* the version is not locked.
|
||||
* @return The current version.
|
||||
*/
|
||||
[[nodiscard]] version_t read_valid() const noexcept
|
||||
{
|
||||
auto version = __atomic_load_n(&_version, __ATOMIC_SEQ_CST);
|
||||
while (OptimisticLock::is_locked(version))
|
||||
{
|
||||
system::builtin::pause();
|
||||
version = __atomic_load_n(&_version, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the version.
|
||||
*
|
||||
* @param version The version to validate.
|
||||
* @return True, if the version is valid.
|
||||
*/
|
||||
[[nodiscard]] bool is_valid(const version_t version) const noexcept
|
||||
{
|
||||
return version == __atomic_load_n(&_version, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to acquire the lock.
|
||||
* @return True, when lock was acquired.
|
||||
*/
|
||||
[[nodiscard]] bool try_lock() noexcept
|
||||
{
|
||||
auto version = read_valid();
|
||||
|
||||
return __atomic_compare_exchange_n(&_version, &version, version + 0b10, false, __ATOMIC_SEQ_CST,
|
||||
__ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until the lock is successfully acquired.
|
||||
*/
|
||||
template <bool SINGLE_WRITER> void lock() noexcept
|
||||
{
|
||||
if constexpr (SINGLE_WRITER)
|
||||
{
|
||||
__atomic_fetch_add(&_version, 0b10, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tries = std::uint64_t{1U};
|
||||
while (this->try_lock() == false)
|
||||
{
|
||||
const auto wait = tries++;
|
||||
for (auto i = 0U; i < wait * 32U; ++i)
|
||||
{
|
||||
system::builtin::pause();
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks the version lock.
|
||||
*/
|
||||
void unlock() noexcept { __atomic_fetch_add(&_version, 0b10, __ATOMIC_SEQ_CST); }
|
||||
|
||||
private:
|
||||
version_t _version;
|
||||
|
||||
[[nodiscard]] static bool is_locked(const version_t version) noexcept { return (version & 0b10) == 0b10; }
|
||||
};
|
||||
} // namespace mx::synchronization
|
||||
68
repos/ealanos/src/lib/mx/synchronization/primitive_matrix.h
Normal file
68
repos/ealanos/src/lib/mx/synchronization/primitive_matrix.h
Normal file
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
#include "synchronization.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <mx/resource/ptr.h>
|
||||
|
||||
namespace mx::synchronization {
|
||||
class PrimitiveMatrix
|
||||
{
|
||||
public:
|
||||
static primitive select_primitive(const isolation_level isolation_level,
|
||||
const resource::expected_access_frequency access_frequency,
|
||||
const resource::expected_read_write_ratio read_write_ratio) noexcept
|
||||
{
|
||||
return isolation_level != isolation_level::None
|
||||
? matrix()[static_cast<std::uint8_t>(isolation_level)][static_cast<std::uint8_t>(read_write_ratio)]
|
||||
[static_cast<std::uint8_t>(access_frequency)]
|
||||
: primitive::None;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr static std::array<std::array<std::array<primitive, 4>, 5>, 2> matrix() noexcept
|
||||
{
|
||||
return {{// For isolation_level::ExclusiveWriter
|
||||
{{
|
||||
// For predicted_read_write_ratio::heavy_read
|
||||
{{primitive::ScheduleWriter, primitive::ScheduleWriter, primitive::ScheduleWriter,
|
||||
primitive::ScheduleWriter}},
|
||||
|
||||
// For predicted_read_write_ratio::mostly_read
|
||||
{{primitive::ScheduleWriter, primitive::ScheduleWriter, primitive::OLFIT, primitive::OLFIT}},
|
||||
|
||||
// For predicted_read_write_ratio::balanced
|
||||
{{primitive::OLFIT, primitive::OLFIT, primitive::OLFIT, primitive::OLFIT}},
|
||||
|
||||
// For predicted_read_write_ratio::mostly_written
|
||||
{{primitive::OLFIT, primitive::OLFIT, primitive::ReaderWriterLatch, primitive::ReaderWriterLatch}},
|
||||
|
||||
// For predicted_read_write_ratio::heavy_written
|
||||
{{primitive::ScheduleAll, primitive::ScheduleAll, primitive::ReaderWriterLatch,
|
||||
primitive::ReaderWriterLatch}},
|
||||
}},
|
||||
|
||||
// For isolation_level::Exclusive
|
||||
{{
|
||||
// For predicted_read_write_ratio::heavy_read
|
||||
{{primitive::ScheduleAll, primitive::ScheduleAll, primitive::ExclusiveLatch,
|
||||
primitive::ExclusiveLatch}},
|
||||
|
||||
// For predicted_read_write_ratio::mostly_read
|
||||
{{primitive::ScheduleAll, primitive::ScheduleAll, primitive::ExclusiveLatch,
|
||||
primitive::ExclusiveLatch}},
|
||||
|
||||
// For predicted_read_write_ratio::balanced
|
||||
{{primitive::ScheduleAll, primitive::ScheduleAll, primitive::ExclusiveLatch,
|
||||
primitive::ExclusiveLatch}},
|
||||
|
||||
// For predicted_read_write_ratio::mostly_written
|
||||
{{primitive::ScheduleAll, primitive::ScheduleAll, primitive::ExclusiveLatch,
|
||||
primitive::ExclusiveLatch}},
|
||||
|
||||
// For predicted_read_write_ratio::heavy_written
|
||||
{{primitive::ScheduleAll, primitive::ScheduleAll, primitive::ExclusiveLatch,
|
||||
primitive::ExclusiveLatch}},
|
||||
}}}};
|
||||
}
|
||||
};
|
||||
} // namespace mx::synchronization
|
||||
294
repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h
Normal file
294
repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* N.B. You most likely do _not_ want to use RWSpinLock or any other
|
||||
* kind of spinlock. Use SharedMutex instead.
|
||||
*
|
||||
* In short, spinlocks in preemptive multi-tasking operating systems
|
||||
* have serious problems and fast mutexes like SharedMutex are almost
|
||||
* certainly the better choice, because letting the OS scheduler put a
|
||||
* thread to sleep is better for system responsiveness and throughput
|
||||
* than wasting a timeslice repeatedly querying a lock held by a
|
||||
* thread that's blocked, and you can't prevent userspace
|
||||
* programs blocking.
|
||||
*
|
||||
* Spinlocks in an operating system kernel make much more sense than
|
||||
* they do in userspace.
|
||||
*
|
||||
* -------------------------------------------------------------------
|
||||
*
|
||||
* Two Read-Write spin lock implementations.
|
||||
*
|
||||
* Ref: http://locklessinc.com/articles/locks
|
||||
*
|
||||
* Both locks here are faster than pthread_rwlock and have very low
|
||||
* overhead (usually 20-30ns). They don't use any system mutexes and
|
||||
* are very compact (4/8 bytes), so are suitable for per-instance
|
||||
* based locking, particularly when contention is not expected.
|
||||
*
|
||||
* For a spinlock, RWSpinLock is a reasonable choice. (See the note
|
||||
* about for why a spin lock is frequently a bad idea generally.)
|
||||
* RWSpinLock has minimal overhead, and comparable contention
|
||||
* performance when the number of competing threads is less than or
|
||||
* equal to the number of logical CPUs. Even as the number of
|
||||
* threads gets larger, RWSpinLock can still be very competitive in
|
||||
* READ, although it is slower on WRITE, and also inherently unfair
|
||||
* to writers.
|
||||
*
|
||||
* RWTicketSpinLock shows more balanced READ/WRITE performance. If
|
||||
* your application really needs a lot more threads, and a
|
||||
* higher-priority writer, prefer one of the RWTicketSpinLock locks.
|
||||
*
|
||||
* Caveats:
|
||||
*
|
||||
* RWTicketSpinLock locks can only be used with GCC on x86/x86-64
|
||||
* based systems.
|
||||
*
|
||||
* RWTicketSpinLock<32> only allows up to 2^8 - 1 concurrent
|
||||
* readers and writers.
|
||||
*
|
||||
* RWTicketSpinLock<64> only allows up to 2^16 - 1 concurrent
|
||||
* readers and writers.
|
||||
*
|
||||
* RWTicketSpinLock<..., true> (kFavorWriter = true, that is, strict
|
||||
* writer priority) is NOT reentrant, even for lock_shared().
|
||||
*
|
||||
* The lock will not grant any new shared (read) accesses while a thread
|
||||
* attempting to acquire the lock in write mode is blocked. (That is,
|
||||
* if the lock is held in shared mode by N threads, and a thread attempts
|
||||
* to acquire it in write mode, no one else can acquire it in shared mode
|
||||
* until these N threads release the lock and then the blocked thread
|
||||
* acquires and releases the exclusive lock.) This also applies for
|
||||
* attempts to reacquire the lock in shared mode by threads that already
|
||||
* hold it in shared mode, making the lock non-reentrant.
|
||||
*
|
||||
* RWSpinLock handles 2^30 - 1 concurrent readers.
|
||||
*
|
||||
* @author Xin Liu <xliux@fb.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
Benchmark on (Intel(R) Xeon(R) CPU L5630 @ 2.13GHz) 8 cores(16 HTs)
|
||||
========================================================================
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
1. Single thread benchmark (read/write lock + unlock overhead)
|
||||
Benchmark Iters Total t t/iter iter/sec
|
||||
-------------------------------------------------------------------------------
|
||||
* BM_RWSpinLockRead 100000 1.786 ms 17.86 ns 53.4M
|
||||
+30.5% BM_RWSpinLockWrite 100000 2.331 ms 23.31 ns 40.91M
|
||||
+85.7% BM_RWTicketSpinLock32Read 100000 3.317 ms 33.17 ns 28.75M
|
||||
+96.0% BM_RWTicketSpinLock32Write 100000 3.5 ms 35 ns 27.25M
|
||||
+85.6% BM_RWTicketSpinLock64Read 100000 3.315 ms 33.15 ns 28.77M
|
||||
+96.0% BM_RWTicketSpinLock64Write 100000 3.5 ms 35 ns 27.25M
|
||||
+85.7% BM_RWTicketSpinLock32FavorWriterRead 100000 3.317 ms 33.17 ns 28.75M
|
||||
+29.7% BM_RWTicketSpinLock32FavorWriterWrite 100000 2.316 ms 23.16 ns 41.18M
|
||||
+85.3% BM_RWTicketSpinLock64FavorWriterRead 100000 3.309 ms 33.09 ns 28.82M
|
||||
+30.2% BM_RWTicketSpinLock64FavorWriterWrite 100000 2.325 ms 23.25 ns 41.02M
|
||||
+ 175% BM_PThreadRWMutexRead 100000 4.917 ms 49.17 ns 19.4M
|
||||
+ 166% BM_PThreadRWMutexWrite 100000 4.757 ms 47.57 ns 20.05M
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
2. Contention Benchmark 90% read 10% write
|
||||
Benchmark hits average min max sigma
|
||||
------------------------------------------------------------------------------
|
||||
---------- 8 threads ------------
|
||||
RWSpinLock Write 142666 220ns 78ns 40.8us 269ns
|
||||
RWSpinLock Read 1282297 222ns 80ns 37.7us 248ns
|
||||
RWTicketSpinLock Write 85692 209ns 71ns 17.9us 252ns
|
||||
RWTicketSpinLock Read 769571 215ns 78ns 33.4us 251ns
|
||||
pthread_rwlock_t Write 84248 2.48us 99ns 269us 8.19us
|
||||
pthread_rwlock_t Read 761646 933ns 101ns 374us 3.25us
|
||||
|
||||
---------- 16 threads ------------
|
||||
RWSpinLock Write 124236 237ns 78ns 261us 801ns
|
||||
RWSpinLock Read 1115807 236ns 78ns 2.27ms 2.17us
|
||||
RWTicketSpinLock Write 81781 231ns 71ns 31.4us 351ns
|
||||
RWTicketSpinLock Read 734518 238ns 78ns 73.6us 379ns
|
||||
pthread_rwlock_t Write 83363 7.12us 99ns 785us 28.1us
|
||||
pthread_rwlock_t Read 754978 2.18us 101ns 1.02ms 14.3us
|
||||
|
||||
---------- 50 threads ------------
|
||||
RWSpinLock Write 131142 1.37us 82ns 7.53ms 68.2us
|
||||
RWSpinLock Read 1181240 262ns 78ns 6.62ms 12.7us
|
||||
RWTicketSpinLock Write 83045 397ns 73ns 7.01ms 31.5us
|
||||
RWTicketSpinLock Read 744133 386ns 78ns 11ms 31.4us
|
||||
pthread_rwlock_t Write 80849 112us 103ns 4.52ms 263us
|
||||
pthread_rwlock_t Read 728698 24us 101ns 7.28ms 194us
|
||||
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <mx/system/builtin.h>
|
||||
#include <thread>
|
||||
|
||||
namespace mx::synchronization {
|
||||
|
||||
/*
|
||||
* A simple, small (4-bytes), but unfair rwlock. Use it when you want
|
||||
* a nice writer and don't expect a lot of write/read contention, or
|
||||
* when you need small rwlocks since you are creating a large number
|
||||
* of them.
|
||||
*
|
||||
* Note that the unfairness here is extreme: if the lock is
|
||||
* continually accessed for read, writers will never get a chance. If
|
||||
* the lock can be that highly contended this class is probably not an
|
||||
* ideal choice anyway.
|
||||
*
|
||||
* It currently implements most of the Lockable, SharedLockable and
|
||||
* UpgradeLockable concepts except the TimedLockable related locking/unlocking
|
||||
* interfaces.
|
||||
*/
|
||||
class RWSpinLock
|
||||
{
|
||||
enum : int32_t
|
||||
{
|
||||
READER = 4,
|
||||
UPGRADED = 2,
|
||||
WRITER = 1
|
||||
};
|
||||
|
||||
public:
|
||||
constexpr RWSpinLock() noexcept = default;
|
||||
|
||||
RWSpinLock(RWSpinLock const &) = delete;
|
||||
RWSpinLock &operator=(RWSpinLock const &) = delete;
|
||||
|
||||
void initialize() { _bits = 0; }
|
||||
|
||||
// Lockable Concept
|
||||
void lock() noexcept
|
||||
{
|
||||
while (!try_lock())
|
||||
{
|
||||
mx::system::builtin::pause();
|
||||
}
|
||||
}
|
||||
|
||||
// Writer is responsible for clearing up both the UPGRADED and WRITER bits.
|
||||
void unlock() noexcept
|
||||
{
|
||||
static_assert(READER > WRITER + UPGRADED, "wrong bits!");
|
||||
__atomic_fetch_and(&_bits, ~(WRITER | UPGRADED), __ATOMIC_RELEASE);
|
||||
}
|
||||
|
||||
// SharedLockable Concept
|
||||
void lock_shared() noexcept
|
||||
{
|
||||
while (!try_lock_shared())
|
||||
{
|
||||
mx::system::builtin::pause();
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_shared() noexcept { __atomic_fetch_add(&_bits, -READER, __ATOMIC_RELEASE); }
|
||||
|
||||
// Downgrade the lock from writer status to reader status.
|
||||
void unlock_and_lock_shared() noexcept
|
||||
{
|
||||
__atomic_fetch_add(&_bits, READER, __ATOMIC_ACQUIRE);
|
||||
unlock();
|
||||
}
|
||||
|
||||
// UpgradeLockable Concept
|
||||
void lock_upgrade() noexcept
|
||||
{
|
||||
while (!try_lock_upgrade())
|
||||
{
|
||||
system::builtin::pause();
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_upgrade() noexcept { __atomic_fetch_add(&_bits, -UPGRADED, __ATOMIC_ACQ_REL); }
|
||||
|
||||
// unlock upgrade and try to acquire write lock
|
||||
void unlock_upgrade_and_lock() noexcept
|
||||
{
|
||||
while (!try_unlock_upgrade_and_lock())
|
||||
{
|
||||
system::builtin::pause();
|
||||
}
|
||||
}
|
||||
|
||||
// unlock upgrade and read lock atomically
|
||||
void unlock_upgrade_and_lock_shared() noexcept { __atomic_fetch_add(&_bits, READER - UPGRADED, __ATOMIC_ACQ_REL); }
|
||||
|
||||
// write unlock and upgrade lock atomically
|
||||
void unlock_and_lock_upgrade() noexcept
|
||||
{
|
||||
// need to do it in two steps here -- as the UPGRADED bit might be OR-ed at
|
||||
// the same time when other threads are trying do try_lock_upgrade().
|
||||
__atomic_fetch_or(&_bits, UPGRADED, __ATOMIC_ACQUIRE);
|
||||
__atomic_fetch_add(&_bits, -WRITER, __ATOMIC_RELEASE);
|
||||
}
|
||||
|
||||
// Attempt to acquire writer permission. Return false if we didn't get it.
|
||||
bool try_lock() noexcept
|
||||
{
|
||||
auto expect = std::int32_t{0};
|
||||
return __atomic_compare_exchange_n(&_bits, &expect, WRITER, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQ_REL);
|
||||
}
|
||||
|
||||
// Try to get reader permission on the lock. This can fail if we
|
||||
// find out someone is a writer or upgrader.
|
||||
// Setting the UPGRADED bit would allow a writer-to-be to indicate
|
||||
// its intention to write and block any new readers while waiting
|
||||
// for existing readers to finish and release their read locks. This
|
||||
// helps avoid starving writers (promoted from upgraders).
|
||||
bool try_lock_shared() noexcept
|
||||
{
|
||||
// fetch_add is considerably (100%) faster than compare_exchange,
|
||||
// so here we are optimizing for the common (lock success) case.
|
||||
const auto value = __atomic_fetch_add(&_bits, READER, __ATOMIC_ACQUIRE);
|
||||
if (static_cast<bool>(value & (WRITER | UPGRADED)))
|
||||
{
|
||||
__atomic_fetch_add(&_bits, -READER, __ATOMIC_RELEASE);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// try to unlock upgrade and write lock atomically
|
||||
bool try_unlock_upgrade_and_lock() noexcept
|
||||
{
|
||||
auto expect = std::int32_t{UPGRADED};
|
||||
return __atomic_compare_exchange_n(&_bits, &expect, WRITER, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQ_REL);
|
||||
}
|
||||
|
||||
// try to acquire an upgradable lock.
|
||||
bool try_lock_upgrade() noexcept
|
||||
{
|
||||
const auto value = __atomic_fetch_or(&_bits, UPGRADED, __ATOMIC_ACQUIRE);
|
||||
|
||||
// Note: when failed, we cannot flip the UPGRADED bit back,
|
||||
// as in this case there is either another upgrade lock or a write lock.
|
||||
// If it's a write lock, the bit will get cleared up when that lock's done
|
||||
// with unlock().
|
||||
return ((value & (UPGRADED | WRITER)) == 0);
|
||||
}
|
||||
|
||||
// mainly for debugging purposes.
|
||||
[[nodiscard]] int32_t bits() const noexcept { return __atomic_load_n(&_bits, __ATOMIC_ACQUIRE); }
|
||||
|
||||
private:
|
||||
std::int32_t _bits;
|
||||
};
|
||||
} // namespace mx::synchronization
|
||||
59
repos/ealanos/src/lib/mx/synchronization/spinlock.h
Normal file
59
repos/ealanos/src/lib/mx/synchronization/spinlock.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <mx/system/builtin.h>
|
||||
|
||||
namespace mx::synchronization {
|
||||
/**
|
||||
* Simple spinlock for mutual exclusion.
|
||||
*/
|
||||
class Spinlock
|
||||
{
|
||||
public:
|
||||
constexpr Spinlock() noexcept = default;
|
||||
~Spinlock() = default;
|
||||
|
||||
/**
|
||||
* Locks the spinlock by spinning until it is lockable.
|
||||
*/
|
||||
void lock() noexcept
|
||||
{
|
||||
do
|
||||
{
|
||||
while (_flag)
|
||||
{
|
||||
system::builtin::pause();
|
||||
}
|
||||
|
||||
if (try_lock())
|
||||
{
|
||||
return;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to lock the lock.
|
||||
* @return True, when successfully locked.
|
||||
*/
|
||||
bool try_lock() noexcept
|
||||
{
|
||||
bool expected = false;
|
||||
return __atomic_compare_exchange_n(&_flag, &expected, true, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks the spinlock.
|
||||
*/
|
||||
void unlock() noexcept { __atomic_store_n(&_flag, false, __ATOMIC_SEQ_CST); }
|
||||
|
||||
/**
|
||||
* @return True, if the lock is in use.
|
||||
*/
|
||||
[[nodiscard]] bool is_locked() const noexcept { return __atomic_load_n(&_flag, __ATOMIC_RELAXED); }
|
||||
|
||||
private:
|
||||
bool _flag;
|
||||
};
|
||||
} // namespace mx::synchronization
|
||||
60
repos/ealanos/src/lib/mx/synchronization/synchronization.h
Normal file
60
repos/ealanos/src/lib/mx/synchronization/synchronization.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace mx::synchronization {
|
||||
/**
|
||||
* Desired isolation level of a resource.
|
||||
*/
|
||||
enum class isolation_level : std::uint8_t
|
||||
{
|
||||
ExclusiveWriter = 0U, // Reads can be parallel, writes will be synchronized
|
||||
Exclusive = 1U, // All accesses will be synchronized
|
||||
None = 2U, // Nothing will be synchronized
|
||||
};
|
||||
|
||||
/**
|
||||
* Desired protocol of synchronization.
|
||||
*/
|
||||
enum class protocol : std::uint8_t
|
||||
{
|
||||
None = 0U, // System is free to choose
|
||||
Queue = 1U, // Choose primitive with queues with respect to isolation level
|
||||
Latch = 2U, // Choose primitive with latches with respect to isolation level
|
||||
OLFIT = 3U, // Try to choose olfit
|
||||
RestrictedTransactionalMemory = 4U, // Try to choose transactional memory
|
||||
Batched = 5U, // Tasks are batched
|
||||
};
|
||||
|
||||
/**
|
||||
* Real method, based on the isolation level
|
||||
* and decision by the tasking layer.
|
||||
*
|
||||
* Attention: Even if the primitive is 8bit long,
|
||||
* it is stored within the tagged_ptr as
|
||||
* using only 4bit! Therefore, the max.
|
||||
* value can be 15.
|
||||
*/
|
||||
enum class primitive : std::uint8_t
|
||||
{
|
||||
None = 0U, // Nothing will be synchronized
|
||||
ExclusiveLatch = 1U, // All accesses will use a spinlock
|
||||
ScheduleAll = 2U, // All accesses will be scheduled to the mapped channel
|
||||
ReaderWriterLatch = 3U, // Use a reader/writer latch to enable parallel reads
|
||||
ScheduleWriter = 4U, // Reads can perform anywhere, writes are scheduled to the mapped channel
|
||||
OLFIT = 5U, // Read/write anywhere but use a latch for writers
|
||||
RestrictedTransactionalMemory = 6U, /// Read/write transactional
|
||||
Batched = 7U // Tasks are batched by using task squads
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether the given primitive is kind of optimistic synchronization
|
||||
* or not.
|
||||
* @param primitive_ Primitive to check.
|
||||
* @return True, if the given primitive is optimistic.
|
||||
*/
|
||||
static inline bool is_optimistic(const primitive primitive_) noexcept
|
||||
{
|
||||
return primitive_ == primitive::ScheduleWriter || primitive_ == primitive::OLFIT;
|
||||
}
|
||||
|
||||
} // namespace mx::synchronization
|
||||
28
repos/ealanos/src/lib/mx/system/builtin.h
Normal file
28
repos/ealanos/src/lib/mx/system/builtin.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
|
||||
namespace mx::system {
|
||||
/**
|
||||
* Encapsulates compiler builtins.
|
||||
*/
|
||||
class builtin
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Generates a pause/yield cpu instruction, independently
|
||||
* of the hardware.
|
||||
*/
|
||||
static void pause() noexcept
|
||||
{
|
||||
#if defined(__x86_64__) || defined(__amd64__)
|
||||
__builtin_ia32_pause();
|
||||
#elif defined(__arm__)
|
||||
asm("YIELD");
|
||||
#endif
|
||||
}
|
||||
|
||||
[[nodiscard]] static std::uint32_t clz(const std::uint32_t number) noexcept { return __builtin_clz(number); }
|
||||
[[nodiscard]] static std::uint64_t clz(const std::uint64_t number) noexcept { return __builtin_clzll(number); }
|
||||
};
|
||||
} // namespace mx::system
|
||||
203
repos/ealanos/src/lib/mx/system/cache.h
Normal file
203
repos/ealanos/src/lib/mx/system/cache.h
Normal file
@@ -0,0 +1,203 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace mx::system {
|
||||
/**
|
||||
* Encapsulates cache operations like prefetching.
|
||||
*
|
||||
* Further documentation on Intel: https://www.felixcloutier.com/x86/prefetchh
|
||||
*/
|
||||
class cache
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] static constexpr auto line_size() noexcept { return 64U; }
|
||||
|
||||
enum level : std::uint8_t
|
||||
{
|
||||
L1 = 3U,
|
||||
ALL = 3U,
|
||||
L2 = 2U,
|
||||
L3 = 1U,
|
||||
NTA = 0U
|
||||
};
|
||||
enum access : std::uint8_t
|
||||
{
|
||||
read = 0U,
|
||||
write = 1U
|
||||
};
|
||||
|
||||
/**
|
||||
* Prefetches a single cache line into a given prefetch level.
|
||||
*
|
||||
* @tparam L Wanted cache level.
|
||||
* @tparam A Access to the cache line whether read or write.
|
||||
* @param address Address of the memory which should be prefetched.
|
||||
*/
|
||||
template <level L, access A = access::read, std::uint8_t C>
|
||||
static void prefetch(const std::int64_t *address) noexcept
|
||||
{
|
||||
constexpr auto items_per_cacheline = line_size() / sizeof(std::int64_t);
|
||||
for (auto i = 0U; i < C * items_per_cacheline; i += items_per_cacheline)
|
||||
{
|
||||
__builtin_prefetch(&address[i], static_cast<std::uint8_t>(A), static_cast<std::uint8_t>(L));
|
||||
}
|
||||
}
|
||||
|
||||
template <level L> [[nodiscard]] static std::uint64_t size()
|
||||
{
|
||||
/* TODO: Get cache sizes, maybe with CPUID? */
|
||||
if constexpr (L == level::L1)
|
||||
{
|
||||
if (_cache_size_cache[0U] == 0U)
|
||||
{
|
||||
//_cache_size_cache[0U] = sysconf(_SC_LEVEL1_DCACHE_SIZE);
|
||||
}
|
||||
return _cache_size_cache[0U];
|
||||
}
|
||||
else if constexpr (L == level::L2)
|
||||
{
|
||||
if (_cache_size_cache[1U] == 0U)
|
||||
{
|
||||
//_cache_size_cache[1U] = sysconf(_SC_LEVEL2_CACHE_SIZE);
|
||||
}
|
||||
return _cache_size_cache[1U];
|
||||
}
|
||||
else if constexpr (L == level::L3)
|
||||
{
|
||||
if (_cache_size_cache[2U] == 0U)
|
||||
{
|
||||
//_cache_size_cache[2U] = sysconf(_SC_LEVEL3_CACHE_SIZE);
|
||||
}
|
||||
return _cache_size_cache[2U];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
|
||||
template <level L, access A = access::read, std::uint32_t S>
|
||||
static void prefetch_range(const std::int64_t *address) noexcept
|
||||
{
|
||||
if constexpr (S <= 64U)
|
||||
{
|
||||
prefetch<L, A, 1U>(address);
|
||||
}
|
||||
else if constexpr (S == 128U)
|
||||
{
|
||||
prefetch<L, A, 2U>(address);
|
||||
}
|
||||
else if constexpr (S == 192U)
|
||||
{
|
||||
prefetch<L, A, 3U>(address);
|
||||
}
|
||||
else if constexpr (S == 256U)
|
||||
{
|
||||
prefetch<L, A, 4U>(address);
|
||||
}
|
||||
else if constexpr (S == 256U)
|
||||
{
|
||||
prefetch<L, A, 4U>(address);
|
||||
}
|
||||
else if constexpr (S == 320U)
|
||||
{
|
||||
prefetch<L, A, 5U>(address);
|
||||
}
|
||||
else if constexpr (S == 384U)
|
||||
{
|
||||
prefetch<L, A, 6U>(address);
|
||||
}
|
||||
else if constexpr (S == 448U)
|
||||
{
|
||||
prefetch<L, A, 7U>(address);
|
||||
}
|
||||
else if constexpr (S == 512U)
|
||||
{
|
||||
prefetch<L, A, 8U>(address);
|
||||
}
|
||||
else if constexpr (S == 1024U)
|
||||
{
|
||||
prefetch<L, A, 16U>(address);
|
||||
}
|
||||
else
|
||||
{
|
||||
prefetch_range<L, A>(address, S);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetches a range of cache lines into the given cache level.
|
||||
*
|
||||
* @tparam L Wanted cache level.
|
||||
* @tparam A Access to the cache line whether read or write.
|
||||
* @param address Address of the memory which should be prefetched.
|
||||
* @param size Size of the accessed memory.
|
||||
*/
|
||||
template <level L, access A = access::read>
|
||||
static void prefetch_range(const std::int64_t *address, const std::uint32_t size) noexcept
|
||||
{
|
||||
const auto cache_lines_to_prefetch = size / cache::line_size();
|
||||
switch (cache_lines_to_prefetch)
|
||||
{
|
||||
case 4:
|
||||
prefetch<L, A, 4U>(address);
|
||||
break;
|
||||
case 2:
|
||||
prefetch<L, A, 2U>(address);
|
||||
break;
|
||||
case 1:
|
||||
prefetch<L, A, 1U>(address);
|
||||
break;
|
||||
case 8:
|
||||
prefetch<L, A, 8U>(address);
|
||||
break;
|
||||
case 3:
|
||||
prefetch<L, A, 3U>(address);
|
||||
break;
|
||||
case 12:
|
||||
prefetch<L, A, 12U>(address);
|
||||
break;
|
||||
case 16:
|
||||
prefetch<L, A, 16U>(address);
|
||||
break;
|
||||
case 5:
|
||||
prefetch<L, A, 5U>(address);
|
||||
break;
|
||||
case 6:
|
||||
prefetch<L, A, 6U>(address);
|
||||
break;
|
||||
case 7:
|
||||
prefetch<L, A, 7U>(address);
|
||||
break;
|
||||
case 9:
|
||||
prefetch<L, A, 9U>(address);
|
||||
break;
|
||||
case 10:
|
||||
prefetch<L, A, 10U>(address);
|
||||
break;
|
||||
case 11:
|
||||
prefetch<L, A, 11U>(address);
|
||||
break;
|
||||
case 13:
|
||||
prefetch<L, A, 13U>(address);
|
||||
break;
|
||||
case 14:
|
||||
prefetch<L, A, 14U>(address);
|
||||
break;
|
||||
case 15:
|
||||
prefetch<L, A, 15U>(address);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static inline std::array<std::uint64_t, 3U> _cache_size_cache{{0U, 0U, 0U}};
|
||||
};
|
||||
} // namespace mx::system
|
||||
51
repos/ealanos/src/lib/mx/system/cpu.h
Normal file
51
repos/ealanos/src/lib/mx/system/cpu.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <mx/tasking/config.h>
|
||||
#include <unordered_map>
|
||||
#include <tukija/syscall-generic.h>
|
||||
|
||||
namespace mx::system {
|
||||
/**
|
||||
* Encapsulates methods for retrieving information
|
||||
* about the hardware landscape.
|
||||
*/
|
||||
class cpu
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @return Core where the caller is running.
|
||||
*/
|
||||
[[nodiscard]] static std::uint16_t core_id() { return Tukija::Cip::cip()->get_cpu_index(); }
|
||||
|
||||
/**
|
||||
* Reads the NUMA region identifier of the given core.
|
||||
*
|
||||
* @param core_id Id of the core.
|
||||
* @return Id of the NUMA region the core stays in.
|
||||
*/
|
||||
[[nodiscard]] static std::uint8_t node_id(const std::uint16_t core_id)
|
||||
{
|
||||
return Tukija::Tip::tip()->domain_of_idx(core_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the NUMA region identifier of the current core.
|
||||
*
|
||||
* @return Id of the NUMA region the core stays in.
|
||||
*/
|
||||
[[nodiscard]] static std::uint8_t node_id() { return Tukija::Tip::tip()->domain_of_loc(Genode::Thread::myself()->affinity()); }
|
||||
|
||||
/**
|
||||
* @return The greatest NUMA region identifier.
|
||||
*/
|
||||
[[nodiscard]] static std::uint8_t max_node_id() { return Tukija::Tip::tip()->num_domains(); }
|
||||
|
||||
/**
|
||||
* @return Number of available cores.
|
||||
*/
|
||||
[[nodiscard]] static std::uint16_t count_cores() { return std::uint16_t(Tukija::Cip::cip()->habitat_affinity.total()); }
|
||||
private:
|
||||
};
|
||||
} // namespace mx::system
|
||||
27
repos/ealanos/src/lib/mx/system/cpuid.h
Normal file
27
repos/ealanos/src/lib/mx/system/cpuid.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace mx::system {
|
||||
/**
|
||||
* Encapsulates methods for checking features
|
||||
* of the system by calling cpuid instruction.
|
||||
*/
|
||||
class cpuid
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @return True, when restricted transactional memory
|
||||
* is enabled.
|
||||
*/
|
||||
static bool is_rtm_provided()
|
||||
{
|
||||
std::uint32_t eax = 0x7;
|
||||
std::uint32_t ebx;
|
||||
std::uint32_t ecx = 0x0;
|
||||
asm volatile("cpuid" : "=b"(ebx) : "a"(eax), "c"(ecx));
|
||||
|
||||
return ebx & 0b100000000000;
|
||||
}
|
||||
};
|
||||
} // namespace mx::system
|
||||
38
repos/ealanos/src/lib/mx/system/environment.h
Normal file
38
repos/ealanos/src/lib/mx/system/environment.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace mx::system {
|
||||
/**
|
||||
* Encapsulates functionality of the (Linux) system.
|
||||
*/
|
||||
class Environment
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @return True, if NUMA balancing is enabled by the system.
|
||||
*/
|
||||
static bool is_numa_balancing_enabled()
|
||||
{
|
||||
return false; /* EalánOS has no NUMA balancing, yet.*/
|
||||
}
|
||||
|
||||
static constexpr auto is_sse2()
|
||||
{
|
||||
#ifdef USE_SSE2
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif // USE_SSE2
|
||||
}
|
||||
|
||||
static constexpr auto is_debug()
|
||||
{
|
||||
#ifdef NDEBUG
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif // NDEBUG
|
||||
}
|
||||
};
|
||||
} // namespace mx::system
|
||||
35
repos/ealanos/src/lib/mx/system/rdtscp.h
Normal file
35
repos/ealanos/src/lib/mx/system/rdtscp.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace mx::system {
|
||||
class RDTSCP
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] inline static std::uint64_t begin() noexcept
|
||||
{
|
||||
std::uint32_t high, low;
|
||||
|
||||
asm volatile("CPUID\n\t"
|
||||
"RDTSC\n\t"
|
||||
"mov %%edx, %0\n\t"
|
||||
"mov %%eax, %1\n\t"
|
||||
: "=r"(high), "=r"(low)::"%rax", "%rbx", "%rcx", "%rdx");
|
||||
|
||||
return (std::uint64_t(high) << 32) | low;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline static std::uint64_t end() noexcept
|
||||
{
|
||||
std::uint32_t high, low;
|
||||
|
||||
asm volatile("RDTSCP\n\t"
|
||||
"mov %%edx, %0\n\t"
|
||||
"mov %%eax, %1\n\t"
|
||||
"CPUID\n\t"
|
||||
: "=r"(high), "=r"(low)::"%rax", "%rbx", "%rcx", "%rdx");
|
||||
|
||||
return (std::uint64_t(high) << 32) | low;
|
||||
}
|
||||
};
|
||||
} // namespace mx::system
|
||||
18
repos/ealanos/src/lib/mx/system/thread.h
Normal file
18
repos/ealanos/src/lib/mx/system/thread.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <pthread.h>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
namespace mx::system {
|
||||
/**
|
||||
* Encapsulates methods for thread access.
|
||||
*/
|
||||
class thread
|
||||
{
|
||||
public:
|
||||
|
||||
};
|
||||
} // namespace mx::system
|
||||
43
repos/ealanos/src/lib/mx/tasking/README.md
Normal file
43
repos/ealanos/src/lib/mx/tasking/README.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Tasking
|
||||
|
||||
## Task
|
||||
Each task has to implement the [task interface](task.h) which inherits annotation to subclasses.
|
||||
|
||||
#### Annotation
|
||||
Annotations provide the possibility to express runtime information about the behavior of a task to the scheduling and execution layer.
|
||||
Such information include
|
||||
* the [priority](priority.h) a task should run with,
|
||||
* the target (a specific worker id, a [resource](../resource/resource_interface.h) that needs synchronized access, `local` or `anywhere`) the task should execute on,
|
||||
* and the [resource](../resource/ptr.h) a task is accessing that could be load from memory into cache before the task executes.
|
||||
|
||||
## Worker
|
||||
Upon start, *MxTasking* will launch one [worker](worker.h) thread on each (specified) logical hardware thread.
|
||||
The worker will fetch tasks from the task pool and executes them.
|
||||
|
||||
#### Task Pool
|
||||
Every worker has its own [task pool](task_pool.h) which has different backend-queues (a queue for normal priority and local dispatches, a queue for normal priority and remote dispatches from the same numa region, a queue for normal priority and dispatches from remote numa regions, a queue for low priority ...).
|
||||
Tasks will be fetched from the task pool and stored in a buffer before executed.
|
||||
|
||||
#### Task Buffer
|
||||
The [task buffer](task_buffer.h) is a buffer for a specific amount of tasks (i.e., `64` tasks).
|
||||
Whenever the buffer becomes empty, the worker will contact the task pool and fill up the buffer with tasks from the pool.
|
||||
The main reason for using a buffer is to get a precise view of future-tasks.
|
||||
Tasks in the pool are stored in linked lists which are very costly to iterate whereas the buffer can be accessed like an array.
|
||||
This is important to *prefetch* tasks that will be executed in the near future.
|
||||
|
||||
#### Task Stack
|
||||
The [task stack](task_stack.h) is used to persist the state of a task before executing the task optimistically.
|
||||
Executing a task optimistically may fail and the state of the task has to be reset to the state before executing (to execute again at a later time).
|
||||
|
||||
## Scheduler
|
||||
The [scheduler](scheduler.h) dispatches tasks to task pools on different worker threads.
|
||||
|
||||
## Configuration
|
||||
The configuration is specified by a [config file](config.h).
|
||||
* `max_cores`: Specifies the maximal number of cores the tasking will spawn worker threads on.
|
||||
* `task_size`: The size that will be allocated for every task.
|
||||
* `task_buffer_size`: The size allocated in the worker-local [task buffer](task_buffer.h) which is filled by the task pools.
|
||||
* `is_use_task_counter`: If enabled, *MxTasking* will collect information about the number of executed and disptached tasks. *Should be disabled for measurements.*
|
||||
* `is_collect_task_traces`: If enabled, *MxTasking* will collect information about which task executed at what times at which worker thread. *Should be disabled for measurements.*
|
||||
* `memory_reclamation`: Specifies if reclamation should be done periodically, after every task execution, or never.
|
||||
* `worker_mode`: When running in `PowerSave` mode, every worker will sleep for a small amount of time to reduce power. *Should be `Performance` for measurements.*
|
||||
139
repos/ealanos/src/lib/mx/tasking/annotation.h
Normal file
139
repos/ealanos/src/lib/mx/tasking/annotation.h
Normal file
@@ -0,0 +1,139 @@
|
||||
#pragma once
|
||||
|
||||
#include "prefetch_descriptor.h"
|
||||
#include "priority.h"
|
||||
#include <cstdint>
|
||||
#include <mx/resource/ptr.h>
|
||||
#include <variant>
|
||||
|
||||
namespace mx::tasking {
|
||||
|
||||
class TaskSquad;
|
||||
|
||||
/**
|
||||
* Container for metadata that can be annotated to every task.
|
||||
* The execution engine will use the annotation for scheduling
|
||||
* and synchronization of concurrent accesses to the same data
|
||||
* object, done by tasks.
|
||||
*/
|
||||
class annotation
|
||||
{
|
||||
public:
|
||||
enum execution_destination : std::uint8_t
|
||||
{
|
||||
anywhere = 0U,
|
||||
local = 1U
|
||||
};
|
||||
enum access_intention : bool
|
||||
{
|
||||
readonly = true,
|
||||
write = false
|
||||
};
|
||||
enum resource_boundness : std::uint8_t
|
||||
{
|
||||
memory = 0U,
|
||||
compute = 1U,
|
||||
mixed = 2U
|
||||
};
|
||||
|
||||
constexpr annotation() noexcept = default;
|
||||
explicit constexpr annotation(const std::uint16_t worker_id) noexcept : _destination(worker_id) {}
|
||||
explicit constexpr annotation(const execution_destination destination) noexcept : _destination(destination) {}
|
||||
constexpr annotation(const enum access_intention access_intention, const resource::ptr resource) noexcept
|
||||
: _access_intention(access_intention), _destination(resource)
|
||||
{
|
||||
}
|
||||
constexpr annotation(const enum access_intention access_intention, const resource::ptr resource,
|
||||
const PrefetchDescriptor prefetch_descriptor) noexcept
|
||||
: _access_intention(access_intention), _destination(resource),
|
||||
_prefetch_hint(PrefetchHint{prefetch_descriptor, resource})
|
||||
{
|
||||
}
|
||||
constexpr annotation(const annotation &) noexcept = default;
|
||||
constexpr annotation(annotation &&) noexcept = default;
|
||||
~annotation() = default;
|
||||
|
||||
annotation &operator=(const annotation &) noexcept = default;
|
||||
annotation &operator=(annotation &&) noexcept = default;
|
||||
|
||||
[[nodiscard]] bool is_readonly() const noexcept { return _access_intention == access_intention::readonly; }
|
||||
[[nodiscard]] priority priority() const noexcept { return _priority; }
|
||||
[[nodiscard]] enum resource_boundness resource_boundness() const noexcept { return _resource_boundness; }
|
||||
[[nodiscard]] std::uint16_t worker_id() const noexcept { return std::get<std::uint16_t>(_destination); }
|
||||
[[nodiscard]] std::uint8_t numa_node_id() const noexcept { return std::get<std::uint8_t>(_destination); }
|
||||
[[nodiscard]] resource::ptr resource() const noexcept { return std::get<resource::ptr>(_destination); }
|
||||
[[nodiscard]] bool has_worker_id() const noexcept { return std::holds_alternative<std::uint16_t>(_destination); }
|
||||
[[nodiscard]] bool has_numa_node_id() const noexcept { return std::holds_alternative<std::uint8_t>(_destination); }
|
||||
[[nodiscard]] bool has_resource() const noexcept { return std::holds_alternative<resource::ptr>(_destination); }
|
||||
[[nodiscard]] bool is_locally() const noexcept
|
||||
{
|
||||
return std::holds_alternative<enum execution_destination>(_destination) &&
|
||||
std::get<enum execution_destination>(_destination) == execution_destination::local;
|
||||
}
|
||||
[[nodiscard]] bool is_anywhere() const noexcept
|
||||
{
|
||||
return std::holds_alternative<enum execution_destination>(_destination) &&
|
||||
std::get<enum execution_destination>(_destination) == execution_destination::anywhere;
|
||||
}
|
||||
[[nodiscard]] bool has_prefetch_hint() const noexcept { return _prefetch_hint.empty() == false; }
|
||||
[[nodiscard]] PrefetchHint prefetch_hint() const noexcept { return _prefetch_hint; }
|
||||
[[nodiscard]] PrefetchHint &prefetch_hint() noexcept { return _prefetch_hint; }
|
||||
[[nodiscard]] std::uint16_t cycles() const noexcept { return _cycles; }
|
||||
|
||||
void set(const enum access_intention access_intention) noexcept { _access_intention = access_intention; }
|
||||
void set(const enum priority priority) noexcept { _priority = priority; }
|
||||
void set(const enum resource_boundness resource_boundness) noexcept { _resource_boundness = resource_boundness; }
|
||||
void set(const std::uint16_t worker_id) noexcept { _destination = worker_id; }
|
||||
void set(const std::uint8_t numa_id) noexcept { _destination = numa_id; }
|
||||
void set(const resource::ptr resource) noexcept { _destination = resource; }
|
||||
void set(const enum execution_destination execution_destination) noexcept { _destination = execution_destination; }
|
||||
void set(const PrefetchDescriptor prefetch_descriptor, const resource::ptr object) noexcept
|
||||
{
|
||||
_prefetch_hint = PrefetchHint{prefetch_descriptor, object};
|
||||
}
|
||||
void set(const PrefetchHint prefetch_hint) noexcept { _prefetch_hint = prefetch_hint; }
|
||||
void cycles(const std::uint16_t cycles) noexcept { _cycles = cycles; }
|
||||
|
||||
bool operator==(const annotation &other) const noexcept
|
||||
{
|
||||
return _access_intention == other._access_intention && _priority == other._priority &&
|
||||
_destination == other._destination && _prefetch_hint == other._prefetch_hint;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Access intention: Reading or writing the object?
|
||||
/// Per default, a task is annotated as a "writer".
|
||||
enum access_intention _access_intention
|
||||
{
|
||||
access_intention::write
|
||||
};
|
||||
|
||||
/// Priority of a task. Low priority tasks will only be
|
||||
/// executed, whenever a worker has no higher-priorized
|
||||
/// tasks in his pool.
|
||||
enum priority _priority
|
||||
{
|
||||
priority::normal
|
||||
};
|
||||
|
||||
enum resource_boundness _resource_boundness
|
||||
{
|
||||
resource_boundness::mixed
|
||||
};
|
||||
|
||||
/// Cycles used for execution of this task.
|
||||
std::uint16_t _cycles{500U};
|
||||
|
||||
/// Target the task will run on.
|
||||
/// The target can be a specific worker id, a NUMA node id,
|
||||
/// a specific data object (that may have a worker_id) or
|
||||
/// a hint like "local" or "anywhere".
|
||||
std::variant<std::uint16_t, std::uint8_t, resource::ptr, execution_destination> _destination{
|
||||
execution_destination::local};
|
||||
|
||||
/// The prefetch hint is a data object that will be accessed
|
||||
/// by the task and a mask that identifies the cache lines,
|
||||
/// which should be prefetched.
|
||||
PrefetchHint _prefetch_hint{};
|
||||
} __attribute__((packed));
|
||||
} // namespace mx::tasking
|
||||
73
repos/ealanos/src/lib/mx/tasking/config.h
Normal file
73
repos/ealanos/src/lib/mx/tasking/config.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
namespace mx::tasking {
|
||||
class config
|
||||
{
|
||||
public:
|
||||
enum queue_backend
|
||||
{
|
||||
Single, /// Each worker has a single queue.
|
||||
NUMALocal, /// Each worker has a queue for each NUMA domain and a local queue.
|
||||
WorkerLocal /// Each worker has a queue for each worker.
|
||||
};
|
||||
|
||||
enum memory_reclamation_scheme
|
||||
{
|
||||
None = 0U, /// No memory reclamation at all.
|
||||
UpdateEpochOnRead = 1U, /// End the epoch after every reading task.
|
||||
UpdateEpochPeriodically = 2U /// End the epoch after a static amount of time.
|
||||
};
|
||||
|
||||
enum worker_mode
|
||||
{
|
||||
Performance = 0U, /// The worker contact the task pool when no task was found.
|
||||
PowerSave = 1U /// The worker will sleep a static amount of time when no task was found.
|
||||
};
|
||||
|
||||
/// Maximal number of supported cores.
|
||||
static constexpr auto max_cores() { return 64U; }
|
||||
|
||||
/// Backend of the queues.
|
||||
static constexpr auto queue() { return queue_backend::NUMALocal; }
|
||||
|
||||
/// Maximal number of supported simultaneous multithreading threads.
|
||||
static constexpr auto max_smt_threads() { return 2U; }
|
||||
|
||||
/// Maximal size for a single task, will be used for task allocation.
|
||||
static constexpr auto task_size() { return 128U; }
|
||||
|
||||
/// The task buffer will hold a set of tasks, fetched from
|
||||
/// queues. This is the size of the buffer.
|
||||
static constexpr auto task_buffer_size() { return 64U; }
|
||||
|
||||
/// If enabled, the worker will sample task cycles during execution
|
||||
/// and use that stats for approximating the prefetch distance for each
|
||||
/// task.
|
||||
/// If disabled, automatic prefetching will fall back to task annotations.
|
||||
static constexpr auto is_monitor_task_cycles_for_prefetching() { return false; }
|
||||
|
||||
/// If enabled, will record the number of execute tasks,
|
||||
/// scheduled tasks, reader and writer per core and more.
|
||||
static constexpr auto is_use_task_counter() { return false; }
|
||||
|
||||
/// If enabled, the runtime of each task will be recorded.
|
||||
static constexpr auto is_collect_task_traces() { return false; }
|
||||
|
||||
/// If enabled, the dataflow graph will collect statistics which node
|
||||
/// emitted which amount of data.
|
||||
static constexpr auto is_count_graph_emits() { return false; }
|
||||
|
||||
/// If enabled, the dataflow graph will collect start times of
|
||||
/// pipelines and finish times of nodes.
|
||||
static constexpr auto is_record_graph_times() { return false; }
|
||||
|
||||
/// If enabled, memory will be reclaimed while using optimistic
|
||||
/// synchronization by epoch-based reclamation. Otherwise, freeing
|
||||
/// memory is unsafe.
|
||||
static constexpr auto memory_reclamation() { return memory_reclamation_scheme::None; }
|
||||
|
||||
/// Switch between performance and power saving mode.
|
||||
/// Set to 'worker_mode::Performance' for measurements.
|
||||
static constexpr auto worker_mode() { return worker_mode::Performance; }
|
||||
};
|
||||
} // namespace mx::tasking
|
||||
97
repos/ealanos/src/lib/mx/tasking/dataflow/annotation.h
Normal file
97
repos/ealanos/src/lib/mx/tasking/dataflow/annotation.h
Normal file
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
#include "token.h"
|
||||
#include "token_generator.h"
|
||||
#include <cstdint>
|
||||
#include <mx/tasking/annotation.h>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace mx::tasking::dataflow {
|
||||
template <typename T> class annotation
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
enum FinalizationType : std::uint8_t
|
||||
{
|
||||
sequential,
|
||||
parallel,
|
||||
reduce,
|
||||
none
|
||||
};
|
||||
|
||||
class CompletionCallbackInterface
|
||||
{
|
||||
public:
|
||||
constexpr CompletionCallbackInterface() noexcept = default;
|
||||
constexpr virtual ~CompletionCallbackInterface() noexcept = default;
|
||||
|
||||
[[nodiscard]] virtual bool is_complete() noexcept = 0;
|
||||
};
|
||||
|
||||
annotation() noexcept = default;
|
||||
annotation(annotation &&) noexcept = default;
|
||||
~annotation() noexcept = default;
|
||||
|
||||
annotation &operator=(annotation &&) noexcept = default;
|
||||
|
||||
void is_parallel(const bool is_parallel) noexcept { _is_parallel = is_parallel; }
|
||||
|
||||
void produces(std::unique_ptr<TokenGenerator<T>> &&generator) noexcept { _token_generator = std::move(generator); }
|
||||
|
||||
void resource_boundness(const enum tasking::annotation::resource_boundness resource_boundness) noexcept
|
||||
{
|
||||
_resource_boundness = resource_boundness;
|
||||
}
|
||||
|
||||
void finalization_type(const FinalizationType type) noexcept { _finalization_type = type; }
|
||||
void finalizes(std::vector<mx::resource::ptr> &&data) { _finalized_data = std::move(data); }
|
||||
|
||||
void is_finalizes_pipeline(const bool is_finalizes_pipeline) noexcept
|
||||
{
|
||||
_is_finalizes_pipeline = is_finalizes_pipeline;
|
||||
}
|
||||
|
||||
void completion_callback(std::unique_ptr<CompletionCallbackInterface> &&callback) noexcept
|
||||
{
|
||||
_complection_callback = std::move(callback);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_parallel() const noexcept { return _is_parallel; }
|
||||
[[nodiscard]] std::unique_ptr<TokenGenerator<T>> &token_generator() noexcept { return _token_generator; }
|
||||
[[nodiscard]] enum tasking::annotation::resource_boundness resource_boundness() const noexcept
|
||||
{
|
||||
return _resource_boundness;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_producing() const noexcept { return _token_generator != nullptr; }
|
||||
|
||||
[[nodiscard]] FinalizationType finalization_type() const noexcept { return _finalization_type; }
|
||||
[[nodiscard]] const std::vector<mx::resource::ptr> &finalize_sequence() const noexcept { return _finalized_data; }
|
||||
[[nodiscard]] bool is_finalizes_pipeline() const noexcept { return _is_finalizes_pipeline; }
|
||||
|
||||
[[nodiscard]] const std::unique_ptr<CompletionCallbackInterface> &completion_callback() const noexcept
|
||||
{
|
||||
return _complection_callback;
|
||||
}
|
||||
[[nodiscard]] bool has_completion_callback() const noexcept { return _complection_callback != nullptr; }
|
||||
|
||||
private:
|
||||
bool _is_parallel{false};
|
||||
std::unique_ptr<TokenGenerator<T>> _token_generator;
|
||||
|
||||
enum tasking::annotation::resource_boundness _resource_boundness{tasking::annotation::resource_boundness::mixed};
|
||||
|
||||
FinalizationType _finalization_type{FinalizationType::sequential};
|
||||
std::vector<mx::resource::ptr> _finalized_data;
|
||||
|
||||
/// Pipelines are finalized, when the last node is finished.
|
||||
/// However, a node may finalize the pipeline premature.
|
||||
bool _is_finalizes_pipeline{false};
|
||||
|
||||
/// Callback that evalutes if a node is "completed".
|
||||
/// Some nodes may spawn further tasks during finalization.
|
||||
/// They will complete only after executing those tasks.
|
||||
std::unique_ptr<CompletionCallbackInterface> _complection_callback{nullptr};
|
||||
};
|
||||
} // namespace mx::tasking::dataflow
|
||||
44
repos/ealanos/src/lib/mx/tasking/dataflow/barrier_task.h
Normal file
44
repos/ealanos/src/lib/mx/tasking/dataflow/barrier_task.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "node.h"
|
||||
#include "producer.h"
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <mx/tasking/runtime.h>
|
||||
#include <mx/tasking/task.h>
|
||||
|
||||
namespace mx::tasking::dataflow {
|
||||
/**
|
||||
* The finalization barrier is spawned on every channel that executed
|
||||
* at least one task of the TaskNode.
|
||||
* After the last finalization barrier was hit, the graph will finalize the node.
|
||||
*/
|
||||
template <class T> class FinalizationBarrierTask final : public TaskInterface
|
||||
{
|
||||
public:
|
||||
FinalizationBarrierTask(std::atomic_int16_t &counter, EmitterInterface<T> &graph, NodeInterface<T> *node) noexcept
|
||||
: _count_pending_workers(counter), _graph(graph), _node(node)
|
||||
{
|
||||
}
|
||||
|
||||
~FinalizationBarrierTask() override = default;
|
||||
|
||||
TaskResult execute(const std::uint16_t worker_id) override
|
||||
{
|
||||
const auto pending_workers = _count_pending_workers.fetch_sub(1);
|
||||
if (pending_workers == 0)
|
||||
{
|
||||
_graph.finalize(worker_id, _node);
|
||||
}
|
||||
|
||||
return TaskResult::make_remove();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint64_t trace_id() const noexcept override { return _node->trace_id(); }
|
||||
|
||||
private:
|
||||
std::atomic_int16_t &_count_pending_workers;
|
||||
EmitterInterface<T> &_graph;
|
||||
NodeInterface<T> *_node;
|
||||
};
|
||||
} // namespace mx::tasking::dataflow
|
||||
40
repos/ealanos/src/lib/mx/tasking/dataflow/finalize_counter.h
Normal file
40
repos/ealanos/src/lib/mx/tasking/dataflow/finalize_counter.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
namespace mx::tasking::dataflow {
|
||||
class ParallelProducingFinalizeCounter
|
||||
{
|
||||
public:
|
||||
ParallelProducingFinalizeCounter(std::atomic_uint16_t *worker_counter, std::atomic_uint64_t *task_counter) noexcept
|
||||
: _task_counter(task_counter), _worker_counter(worker_counter)
|
||||
{
|
||||
}
|
||||
|
||||
ParallelProducingFinalizeCounter(const ParallelProducingFinalizeCounter &) noexcept = default;
|
||||
ParallelProducingFinalizeCounter(ParallelProducingFinalizeCounter &&) noexcept = default;
|
||||
|
||||
~ParallelProducingFinalizeCounter() noexcept = default;
|
||||
|
||||
[[nodiscard]] bool tick() noexcept
|
||||
{
|
||||
if (_task_counter->fetch_sub(1U) == 1U)
|
||||
{
|
||||
std::free(_task_counter);
|
||||
|
||||
if (_worker_counter->fetch_sub(1U) == 1U)
|
||||
{
|
||||
std::free(_worker_counter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_uint64_t *_task_counter;
|
||||
|
||||
std::atomic_uint16_t *_worker_counter;
|
||||
};
|
||||
} // namespace mx::tasking::dataflow
|
||||
994
repos/ealanos/src/lib/mx/tasking/dataflow/graph.h
Normal file
994
repos/ealanos/src/lib/mx/tasking/dataflow/graph.h
Normal file
@@ -0,0 +1,994 @@
|
||||
#pragma once
|
||||
|
||||
#include "barrier_task.h"
|
||||
#include "finalize_counter.h"
|
||||
#include "node.h"
|
||||
#include "pipeline.h"
|
||||
#include "producer.h"
|
||||
#include <bitset>
|
||||
#include <chrono>
|
||||
#include <mx/memory/global_heap.h>
|
||||
#include <mx/synchronization/spinlock.h>
|
||||
#include <mx/tasking/runtime.h>
|
||||
#include <mx/tasking/task.h>
|
||||
#include <ranges>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace mx::tasking::dataflow {
|
||||
|
||||
template <typename T> class Graph;
|
||||
|
||||
/**
|
||||
* The SequentialProducingTask takes a graph node and calls the nodes produce()
|
||||
* method for an annotated amount or until the produce() call returns false.
|
||||
* The task will only spawned once; produced will be called in a loop.
|
||||
*/
|
||||
template <typename T> class SequentialProducingTask final : public TaskInterface
|
||||
{
|
||||
public:
|
||||
SequentialProducingTask(Graph<T> *graph, NodeInterface<T> *node) noexcept : _graph(graph), _node(node) {}
|
||||
~SequentialProducingTask() noexcept override = default;
|
||||
|
||||
TaskResult execute(std::uint16_t worker_id) override;
|
||||
|
||||
[[nodiscard]] std::uint64_t trace_id() const noexcept override { return _node->trace_id(); }
|
||||
|
||||
private:
|
||||
Graph<T> *_graph;
|
||||
NodeInterface<T> *_node;
|
||||
};
|
||||
|
||||
/**
|
||||
* The ParallelProducingTask takes a node that is annotated to produce data
|
||||
* in parallel. The node has to provide a set of resource annotations that
|
||||
* are used to produce data or a annotated number how often the node should
|
||||
* produce().
|
||||
* For each sequence, one ParallelProducingTask will be spawned.
|
||||
*/
|
||||
template <typename T> class ParallelProducingTask final : public TaskInterface
|
||||
{
|
||||
public:
|
||||
ParallelProducingTask(Graph<T> *graph, NodeInterface<T> *node, T &&data,
|
||||
ParallelProducingFinalizeCounter finalize_counter) noexcept
|
||||
: _graph(graph), _node(node), _data(std::move(data)), _finalize_counter(finalize_counter)
|
||||
{
|
||||
}
|
||||
~ParallelProducingTask() noexcept override = default;
|
||||
|
||||
TaskResult execute(std::uint16_t worker_id) override;
|
||||
|
||||
[[nodiscard]] std::uint64_t trace_id() const noexcept override { return _node->trace_id(); }
|
||||
|
||||
private:
|
||||
Graph<T> *_graph;
|
||||
NodeInterface<T> *_node;
|
||||
T _data;
|
||||
ParallelProducingFinalizeCounter _finalize_counter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Since the produced data may become very large, a single task that spawns
|
||||
* all parallel producing tasks may block a worker for a long time.
|
||||
* The SpawnParallelProducingTask will be spawned on every worker and spawn
|
||||
* parallel producing tasks for a partition of the data.
|
||||
*/
|
||||
template <typename T> class SpawnParallelProducingTask final : public TaskInterface
|
||||
{
|
||||
public:
|
||||
SpawnParallelProducingTask(Graph<T> *graph, NodeInterface<T> *node,
|
||||
std::atomic_uint16_t *spawned_worker_counter) noexcept
|
||||
: _graph(graph), _node(node), _spawned_worker_counter(spawned_worker_counter)
|
||||
{
|
||||
}
|
||||
~SpawnParallelProducingTask() noexcept override = default;
|
||||
|
||||
TaskResult execute(const std::uint16_t worker_id) override
|
||||
{
|
||||
auto &generator = _node->annotation().token_generator();
|
||||
if (generator != nullptr) [[likely]]
|
||||
{
|
||||
/// Data spawned for this worker by this task.
|
||||
auto data = generator->generate(worker_id);
|
||||
|
||||
if (data.empty() == false) [[likely]]
|
||||
{
|
||||
/// Counter of tasks spawned by this worker.
|
||||
/// Hopefully, they will be spawned at the same core.
|
||||
auto *finalize_counter =
|
||||
new (std::aligned_alloc(system::cache::line_size(), sizeof(std::atomic_uint64_t)))
|
||||
std::atomic_uint64_t(data.size());
|
||||
|
||||
for (auto &&token : data)
|
||||
{
|
||||
/// Spawn producing tasks with
|
||||
auto *source_task = runtime::new_task<ParallelProducingTask<T>>(
|
||||
worker_id, _graph, _node, std::move(token.data()),
|
||||
ParallelProducingFinalizeCounter{_spawned_worker_counter, finalize_counter});
|
||||
|
||||
source_task->annotate(token.annotation());
|
||||
runtime::spawn(*source_task, worker_id);
|
||||
}
|
||||
}
|
||||
|
||||
/// It may happen, that a worker has no data. In this case,
|
||||
/// we may finalize the graph if all other tasks have
|
||||
/// already executed.
|
||||
else if (_spawned_worker_counter->fetch_sub(1U) == 1U)
|
||||
{
|
||||
_graph->finalize(worker_id, _node);
|
||||
}
|
||||
}
|
||||
|
||||
return TaskResult::make_remove();
|
||||
}
|
||||
|
||||
private:
|
||||
Graph<T> *_graph;
|
||||
NodeInterface<T> *_node;
|
||||
std::atomic_uint16_t *_spawned_worker_counter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Since there are multiple ways to finalize a node (sequential, parallel, reduce),
|
||||
* we need different sort of finalize tasks. This is the abstract finalize task
|
||||
* that implements a function that calls the in_complete of the following node
|
||||
* and starts pipelines of the graph if needed.
|
||||
*/
|
||||
template <typename T> class AbstractFinalizeTask;
|
||||
|
||||
/**
|
||||
* The graph is a set of nodes that produce and consume data.
|
||||
* Every time, a node emits data to the graph, the graph makes sure
|
||||
* that the nodes successor will consume the data.
|
||||
*
|
||||
* Further, the nodes are arranged in pipelines to solve dependencies
|
||||
* between nodes. Everytime a pipeline finishes, the graph will start
|
||||
* depending pipelines.
|
||||
*
|
||||
* After executing the last node of the graph, all nodes and pipelines
|
||||
* will be removed.
|
||||
*/
|
||||
template <typename T> class Graph : public EmitterInterface<T>
|
||||
{
|
||||
public:
|
||||
friend class AbstractFinalizeTask<T>;
|
||||
|
||||
Graph(const bool is_record_times = false) : _is_record_times(is_record_times)
|
||||
{
|
||||
_pipelines.reserve(1U << 3U);
|
||||
_node_pipelines.reserve(1U << 6U);
|
||||
_pipeline_dependencies.reserve(1U << 3U);
|
||||
_pipeline_dependencies_lock.unlock();
|
||||
|
||||
if constexpr (config::is_record_graph_times())
|
||||
{
|
||||
if (_is_record_times)
|
||||
{
|
||||
_pipeline_start_times.reserve(_pipelines.capacity());
|
||||
_node_finish_times.reserve(1U << 6U);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~Graph() override
|
||||
{
|
||||
std::for_each(_pipelines.begin(), _pipelines.end(), [](auto *pipeline) {
|
||||
pipeline->~Pipeline();
|
||||
std::free(pipeline);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return All pipelines of the graph.
|
||||
*/
|
||||
[[nodiscard]] const std::vector<Pipeline<T> *> &pipelines() const noexcept { return _pipelines; }
|
||||
|
||||
/**
|
||||
* @return A list of node pairs (A,B) where A depends on B. A will be started when B finishes.
|
||||
*/
|
||||
[[nodiscard]] const std::vector<std::pair<NodeInterface<T> *, NodeInterface<T> *>> &node_dependencies()
|
||||
const noexcept
|
||||
{
|
||||
return _node_dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit data to the graph. The data will be consumed by the successor of the given node.
|
||||
*
|
||||
* @param worker_id Worker where emit() is called.
|
||||
* @param node The node emitting data.
|
||||
* @param data The emitted data.
|
||||
*/
|
||||
void emit(const std::uint16_t worker_id, NodeInterface<T> *node, Token<T> &&data) override
|
||||
{
|
||||
if (_is_active) [[likely]]
|
||||
{
|
||||
node->out()->consume(worker_id, *this, std::move(data));
|
||||
|
||||
if constexpr (config::is_count_graph_emits())
|
||||
{
|
||||
++this->_emit_counter.at(node)[worker_id].value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizes a given node. When a node with dependencies finalizes,
|
||||
* the graph will start depending pipelines.
|
||||
* When the last node of the graph finalizes, the graph will be freed
|
||||
* from memory.
|
||||
*
|
||||
* @param worker_id Worker where the node finalizes.
|
||||
* @param node Node that finalizes.
|
||||
*/
|
||||
void finalize(std::uint16_t worker_id, NodeInterface<T> *node) override;
|
||||
|
||||
void for_each_node(std::function<void(NodeInterface<T> *)> &&callback) const override
|
||||
{
|
||||
for (auto *pipeline : _pipelines)
|
||||
{
|
||||
for (auto *node : pipeline->nodes())
|
||||
{
|
||||
callback(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a single node to the graph.
|
||||
*
|
||||
* @param node Node to add.
|
||||
*/
|
||||
void add(NodeInterface<T> *node)
|
||||
{
|
||||
auto *pipeline = make_pipeline();
|
||||
pipeline->emplace(node);
|
||||
|
||||
_node_pipelines.template insert(std::make_pair(node, pipeline));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two nodes to the graph (if not added, yet) and
|
||||
* creates an edge between the nodes. Whenever the from node
|
||||
* emits data to the graph, to will consume this data.
|
||||
*
|
||||
* @param from Node that will produce data.
|
||||
* @param to Node that will consume the data emitted by from.
|
||||
*/
|
||||
void make_edge(NodeInterface<T> *from_node, NodeInterface<T> *to_node)
|
||||
{
|
||||
if (_node_pipelines.contains(from_node) == false && _node_pipelines.contains(to_node) == false)
|
||||
{
|
||||
/// Both nodes will be in the same pipeline
|
||||
auto *pipeline = make_pipeline();
|
||||
pipeline->emplace(from_node);
|
||||
pipeline->emplace(to_node);
|
||||
|
||||
_node_pipelines.template insert(std::make_pair(from_node, pipeline));
|
||||
_node_pipelines.template insert(std::make_pair(to_node, _node_pipelines.at(from_node)));
|
||||
}
|
||||
else if (_node_pipelines.contains(to_node) == false)
|
||||
{
|
||||
/// From is already part of a pipeline. Add "to" to the same.
|
||||
auto *pipeline = _node_pipelines.at(from_node);
|
||||
_node_pipelines.template insert(std::make_pair(to_node, pipeline));
|
||||
pipeline->emplace(to_node);
|
||||
}
|
||||
else if (_node_pipelines.contains(from_node) == false)
|
||||
{
|
||||
/// To is already part of a pipeline. Add "from" to the same.
|
||||
auto *pipeline = _node_pipelines.at(to_node);
|
||||
_node_pipelines.template insert(std::make_pair(from_node, pipeline));
|
||||
pipeline->emplace(from_node);
|
||||
}
|
||||
|
||||
from_node->out(to_node);
|
||||
to_node->add_in(from_node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a dependency between the node pair (A,B) where A will be
|
||||
* started only when B finishes.
|
||||
*
|
||||
* @param node Node with dependency.
|
||||
* @param node_to_wait_for Node that has to finish.
|
||||
*/
|
||||
void make_dependency(NodeInterface<T> *node, NodeInterface<T> *node_to_wait_for)
|
||||
{
|
||||
_node_dependencies.template emplace_back(std::make_pair(node, node_to_wait_for));
|
||||
|
||||
auto *node_pipeline = _node_pipelines.at(node);
|
||||
auto *wait_for_pipeline = _node_pipelines.at(node_to_wait_for);
|
||||
|
||||
if (node_pipeline == wait_for_pipeline)
|
||||
{
|
||||
auto *new_pipeline = make_pipeline();
|
||||
change_pipeline(node_to_wait_for, node_pipeline, new_pipeline);
|
||||
_pipeline_dependencies.at(node_pipeline).template emplace_back(new_pipeline);
|
||||
}
|
||||
else
|
||||
{
|
||||
_pipeline_dependencies.at(node_pipeline).template emplace_back(wait_for_pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the graph by spawning tasks that call produce() for all
|
||||
* nodes assigned to a pipeline without dependencies.
|
||||
*
|
||||
* @param worker_id Worker where the graph is started.
|
||||
*/
|
||||
void start(const std::uint16_t worker_id)
|
||||
{
|
||||
if constexpr (config::is_count_graph_emits())
|
||||
{
|
||||
this->for_each_node([&emits = this->_emit_counter](auto *node) {
|
||||
emits.insert(std::make_pair(node, std::array<util::aligned_t<std::uint64_t>, config::max_cores()>{}));
|
||||
emits.at(node).fill(util::aligned_t<std::uint64_t>{0U});
|
||||
});
|
||||
}
|
||||
|
||||
/// Start all tasks for preparatory work.
|
||||
for (auto *task : _preparatory_tasks)
|
||||
{
|
||||
runtime::spawn(*task, worker_id);
|
||||
}
|
||||
_preparatory_tasks.clear();
|
||||
|
||||
/// Collect pipelines without dependencies and start them.
|
||||
auto pipelines_to_start = std::vector<Pipeline<T> *>{};
|
||||
for (auto &[pipeline, dependencies] : _pipeline_dependencies)
|
||||
{
|
||||
if (dependencies.empty())
|
||||
{
|
||||
pipelines_to_start.emplace_back(pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto *pipeline : pipelines_to_start)
|
||||
{
|
||||
_pipeline_dependencies.erase(pipeline);
|
||||
start(worker_id, pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
void interrupt() override { _is_active = false; }
|
||||
|
||||
void add(std::vector<TaskInterface *> &&preparatory_tasks)
|
||||
{
|
||||
std::move(preparatory_tasks.begin(), preparatory_tasks.end(), std::back_inserter(_preparatory_tasks));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint64_t count_emitted(NodeInterface<T> *node) const noexcept
|
||||
{
|
||||
if constexpr (config::is_count_graph_emits())
|
||||
{
|
||||
const auto &iterator = this->_emit_counter.at(node);
|
||||
return std::accumulate(iterator.begin(), iterator.end(), 0U,
|
||||
[](const auto sum, const auto count) { return sum + count.value(); });
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<std::chrono::system_clock::time_point> start_time(Pipeline<T> *pipeline) const noexcept
|
||||
{
|
||||
if (auto iterator = _pipeline_start_times.find(pipeline); iterator != _pipeline_start_times.end())
|
||||
{
|
||||
return std::make_optional(iterator->second);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<std::chrono::system_clock::time_point> finish_time(
|
||||
NodeInterface<T> *node) const noexcept
|
||||
{
|
||||
if (auto iterator = _node_finish_times.find(node); iterator != _node_finish_times.end())
|
||||
{
|
||||
return std::make_optional(iterator->second);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::pair<NodeInterface<T> *, std::chrono::nanoseconds>> node_times() const
|
||||
{
|
||||
auto times = std::vector<std::pair<NodeInterface<T> *, std::chrono::nanoseconds>>{};
|
||||
|
||||
for (auto *pipeline : _pipelines)
|
||||
{
|
||||
if (auto pipeline_iterator = _pipeline_start_times.find(pipeline);
|
||||
pipeline_iterator != _pipeline_start_times.end())
|
||||
{
|
||||
auto last_start = pipeline_iterator->second;
|
||||
|
||||
for (auto *node : pipeline->nodes())
|
||||
{
|
||||
if (auto node_iterator = _node_finish_times.find(node); node_iterator != _node_finish_times.end())
|
||||
{
|
||||
auto node_finish = node_iterator->second;
|
||||
times.template emplace_back(std::make_pair(
|
||||
node, std::chrono::duration_cast<std::chrono::nanoseconds>(node_finish - last_start)));
|
||||
last_start = node_finish;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return times;
|
||||
}
|
||||
|
||||
private:
|
||||
/// All pipelines of the graph.
|
||||
std::vector<Pipeline<T> *> _pipelines;
|
||||
|
||||
/// Map to assign each node a specific pipeline.
|
||||
std::unordered_map<NodeInterface<T> *, Pipeline<T> *> _node_pipelines;
|
||||
|
||||
/// Dependencies between pipelines. Each pipeline might have multiple dependencies.
|
||||
std::unordered_map<Pipeline<T> *, std::vector<Pipeline<T> *>> _pipeline_dependencies;
|
||||
|
||||
/// List of node pairs (A,B) where A has to wait until B finishes.
|
||||
std::vector<std::pair<NodeInterface<T> *, NodeInterface<T> *>> _node_dependencies;
|
||||
|
||||
/// Tasks that should be executed before executing the graph to set up i.e. data structures.
|
||||
std::vector<TaskInterface *> _preparatory_tasks;
|
||||
|
||||
/// Record execution times?
|
||||
bool _is_record_times;
|
||||
|
||||
/// Start time of each pipeline.
|
||||
std::unordered_map<Pipeline<T> *, std::chrono::system_clock::time_point> _pipeline_start_times;
|
||||
|
||||
/// End time of each node.
|
||||
std::unordered_map<NodeInterface<T> *, std::chrono::system_clock::time_point> _node_finish_times;
|
||||
|
||||
/// Lock for pipeline dependencies. Will be locked whenever a pipeline finishes.
|
||||
alignas(64) synchronization::Spinlock _pipeline_dependencies_lock;
|
||||
std::atomic_uint32_t _finished_pipelines{0U};
|
||||
|
||||
alignas(64) bool _is_active{true};
|
||||
|
||||
alignas(64) std::unordered_map<NodeInterface<T> *,
|
||||
std::array<util::aligned_t<std::uint64_t>, config::max_cores()>> _emit_counter;
|
||||
|
||||
[[nodiscard]] bool complete(std::uint16_t worker_id, NodeInterface<T> *node);
|
||||
|
||||
/**
|
||||
* @return A new pipeline.
|
||||
*/
|
||||
Pipeline<T> *make_pipeline()
|
||||
{
|
||||
auto *pipeline = _pipelines.template emplace_back(
|
||||
new (memory::GlobalHeap::allocate_cache_line_aligned(sizeof(Pipeline<T>))) Pipeline<T>());
|
||||
_pipeline_dependencies.insert(std::make_pair(pipeline, std::vector<Pipeline<T> *>{}));
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a given node from a pipeline to another one.
|
||||
* All predecessors will be moved, too.
|
||||
*
|
||||
* @param node Node to move from one to another pipeline.
|
||||
* @param original_pipeline The original pipeline of the node.
|
||||
* @param new_pipeline The new pipeline of the node and its predecessors.
|
||||
*/
|
||||
void change_pipeline(NodeInterface<T> *node, Pipeline<T> *original_pipeline, Pipeline<T> *new_pipeline)
|
||||
{
|
||||
if (_node_pipelines.at(node) == original_pipeline)
|
||||
{
|
||||
_node_pipelines.at(node) = new_pipeline;
|
||||
|
||||
for (auto *node_in : node->in())
|
||||
{
|
||||
change_pipeline(node_in, original_pipeline, new_pipeline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a given pipeline. This will spawn the produce tasks for the first node of the pipeline.
|
||||
*
|
||||
* @param worker_id Worker where start() is called.
|
||||
* @param pipeline Pipeline to start.
|
||||
*/
|
||||
void start(const std::uint16_t worker_id, Pipeline<T> *pipeline)
|
||||
{
|
||||
auto *node = pipeline->nodes().front();
|
||||
|
||||
if constexpr (config::is_record_graph_times())
|
||||
{
|
||||
if (this->_is_record_times)
|
||||
{
|
||||
this->_pipeline_start_times.insert(std::make_pair(pipeline, std::chrono::system_clock::now()));
|
||||
}
|
||||
}
|
||||
|
||||
if (node->annotation().is_parallel() && node->annotation().is_producing())
|
||||
{
|
||||
const auto count_workers = runtime::workers();
|
||||
|
||||
auto *spawned_worker_counter =
|
||||
new (std::aligned_alloc(system::cache::line_size(), sizeof(std::atomic_uint16_t)))
|
||||
std::atomic_uint16_t(count_workers);
|
||||
|
||||
for (auto target_worker_id = std::uint16_t(0U); target_worker_id < count_workers; ++target_worker_id)
|
||||
{
|
||||
auto *spawn_task =
|
||||
runtime::new_task<SpawnParallelProducingTask<T>>(worker_id, this, node, spawned_worker_counter);
|
||||
|
||||
spawn_task->annotate(std::uint16_t(target_worker_id));
|
||||
runtime::spawn(*spawn_task, worker_id);
|
||||
}
|
||||
}
|
||||
else if (node->annotation().is_producing()) /// Produce sequential.
|
||||
{
|
||||
auto *source_task = runtime::new_task<SequentialProducingTask<T>>(worker_id, this, node);
|
||||
runtime::spawn(*source_task, worker_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->finalize(worker_id, node);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> class AbstractFinalizeTask : public TaskInterface
|
||||
{
|
||||
public:
|
||||
constexpr AbstractFinalizeTask(Graph<T> *graph, NodeInterface<T> *node) noexcept : _graph(graph), _node(node) {}
|
||||
|
||||
~AbstractFinalizeTask() noexcept override = default;
|
||||
|
||||
void complete(const std::uint16_t worker_id)
|
||||
{
|
||||
if (_graph->complete(worker_id, _node))
|
||||
{
|
||||
_graph = nullptr;
|
||||
_node = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint64_t trace_id() const noexcept override
|
||||
{
|
||||
if (_node != nullptr) [[likely]]
|
||||
{
|
||||
return _node->trace_id();
|
||||
}
|
||||
|
||||
return TaskInterface::trace_id();
|
||||
}
|
||||
|
||||
protected:
|
||||
Graph<T> *_graph;
|
||||
NodeInterface<T> *_node;
|
||||
};
|
||||
|
||||
/**
|
||||
* The sequentual finalize task will call "finalize" of a node once.
|
||||
*/
|
||||
template <typename T> class SequentialFinalizeTask final : public AbstractFinalizeTask<T>
|
||||
{
|
||||
public:
|
||||
constexpr SequentialFinalizeTask(Graph<T> *graph, NodeInterface<T> *node) noexcept
|
||||
: AbstractFinalizeTask<T>(graph, node)
|
||||
{
|
||||
}
|
||||
~SequentialFinalizeTask() noexcept override = default;
|
||||
|
||||
TaskResult execute(const std::uint16_t worker_id) override
|
||||
{
|
||||
const auto ressource = this->annotation().has_resource() ? this->annotation().resource() : nullptr;
|
||||
|
||||
AbstractFinalizeTask<T>::_node->finalize(worker_id, *AbstractFinalizeTask<T>::_graph, true, ressource, nullptr);
|
||||
AbstractFinalizeTask<T>::complete(worker_id);
|
||||
|
||||
return TaskResult::make_remove();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> class ParallelCompletionTask final : public AbstractFinalizeTask<T>
|
||||
{
|
||||
public:
|
||||
ParallelCompletionTask(Graph<T> *graph, NodeInterface<T> *node,
|
||||
std::atomic_uint16_t *count_finalized_cores) noexcept
|
||||
: AbstractFinalizeTask<T>(graph, node), _count_finalized_workers(count_finalized_cores)
|
||||
{
|
||||
}
|
||||
|
||||
~ParallelCompletionTask() noexcept override = default;
|
||||
|
||||
TaskResult execute(const std::uint16_t worker_id) override
|
||||
{
|
||||
const auto is_last = _count_finalized_workers->fetch_sub(1U) == 1U;
|
||||
if (is_last)
|
||||
{
|
||||
const auto is_completed = this->_node->annotation().completion_callback()->is_complete();
|
||||
if (is_completed)
|
||||
{
|
||||
std::free(_count_finalized_workers);
|
||||
AbstractFinalizeTask<T>::complete(worker_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_count_finalized_workers->store(this->_node->annotation().finalize_sequence().size());
|
||||
for (const auto finalize_data : this->_node->annotation().finalize_sequence())
|
||||
{
|
||||
const auto target_worker_id = finalize_data.worker_id();
|
||||
auto *completion_task = mx::tasking::runtime::new_task<ParallelCompletionTask<T>>(
|
||||
worker_id, this->_graph, this->_node, _count_finalized_workers);
|
||||
completion_task->annotate(target_worker_id);
|
||||
mx::tasking::runtime::spawn(*completion_task, worker_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TaskResult::make_remove();
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_uint16_t *_count_finalized_workers{nullptr};
|
||||
};
|
||||
|
||||
/**
|
||||
* The parallel finalize task will be spawned on every worker and call
|
||||
* the finalize of a node in parallel. Only the last executed finalize task
|
||||
* will call the in_complete of the follow-up node, keeping track by a atomic
|
||||
* counter.
|
||||
*/
|
||||
template <typename T> class ParallelFinalizeTask final : public AbstractFinalizeTask<T>
|
||||
{
|
||||
public:
|
||||
constexpr ParallelFinalizeTask(Graph<T> *graph, NodeInterface<T> *node,
|
||||
std::atomic_uint16_t *count_finalized_cores) noexcept
|
||||
: AbstractFinalizeTask<T>(graph, node), _count_finalized_workers(count_finalized_cores)
|
||||
{
|
||||
}
|
||||
|
||||
~ParallelFinalizeTask() noexcept override = default;
|
||||
|
||||
TaskResult execute(const std::uint16_t worker_id) override
|
||||
{
|
||||
const auto is_last = _count_finalized_workers->fetch_sub(1U) == 1U;
|
||||
|
||||
/// Let the node finalize it's results. Maybe, the node will emit some data to the graph.
|
||||
AbstractFinalizeTask<T>::_node->finalize(worker_id, *AbstractFinalizeTask<T>::_graph, is_last,
|
||||
this->annotation().resource(), nullptr);
|
||||
|
||||
if (is_last)
|
||||
{
|
||||
if (this->_node->annotation().has_completion_callback() &&
|
||||
this->_node->annotation().completion_callback()->is_complete() == false)
|
||||
{
|
||||
const auto &finalize_sequence = this->_node->annotation().finalize_sequence();
|
||||
_count_finalized_workers->store(finalize_sequence.size());
|
||||
for (const auto finalize_data : finalize_sequence)
|
||||
{
|
||||
const auto target_worker_id = finalize_data.worker_id();
|
||||
auto *completion_task = mx::tasking::runtime::new_task<ParallelCompletionTask<T>>(
|
||||
worker_id, this->_graph, this->_node, _count_finalized_workers);
|
||||
completion_task->annotate(target_worker_id);
|
||||
mx::tasking::runtime::spawn(*completion_task, worker_id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::free(_count_finalized_workers);
|
||||
AbstractFinalizeTask<T>::complete(worker_id);
|
||||
}
|
||||
}
|
||||
|
||||
return TaskResult::make_remove();
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_uint16_t *_count_finalized_workers{nullptr};
|
||||
};
|
||||
|
||||
template <typename T> class ReduceFinalizeTask final : public AbstractFinalizeTask<T>
|
||||
{
|
||||
public:
|
||||
constexpr ReduceFinalizeTask(Graph<T> *graph, NodeInterface<T> *node, const mx::resource::ptr reduced_data) noexcept
|
||||
: AbstractFinalizeTask<T>(graph, node), _reduced_data(reduced_data)
|
||||
{
|
||||
}
|
||||
|
||||
~ReduceFinalizeTask() noexcept override = default;
|
||||
|
||||
TaskResult execute(const std::uint16_t worker_id) override
|
||||
{
|
||||
AbstractFinalizeTask<T>::_node->finalize(worker_id, *AbstractFinalizeTask<T>::_graph, false,
|
||||
this->annotation().resource(), _reduced_data);
|
||||
|
||||
if (auto *next_task = dynamic_cast<ReduceFinalizeTask<T> *>(_follow_up_task))
|
||||
{
|
||||
if (next_task->_pending_preceding_counter.fetch_sub(1U) == 1U)
|
||||
{
|
||||
return TaskResult::make_succeed_and_remove(next_task);
|
||||
}
|
||||
}
|
||||
else if (auto *sequential_finalize_task = dynamic_cast<SequentialFinalizeTask<T> *>(_follow_up_task))
|
||||
{
|
||||
return TaskResult::make_succeed_and_remove(sequential_finalize_task);
|
||||
}
|
||||
|
||||
return TaskResult::make_remove();
|
||||
}
|
||||
|
||||
void follow_up_task(AbstractFinalizeTask<T> *task) noexcept { _follow_up_task = task; }
|
||||
|
||||
[[nodiscard]] resource::ptr reduced_resource() const noexcept { return _reduced_data; }
|
||||
|
||||
private:
|
||||
/// The task that will reduce next.
|
||||
AbstractFinalizeTask<T> *_follow_up_task;
|
||||
|
||||
/// The worker id that will be reduced.
|
||||
resource::ptr _reduced_data;
|
||||
|
||||
/// Counts how many reduce tasks are pending.
|
||||
std::atomic_uint8_t _pending_preceding_counter{2U};
|
||||
};
|
||||
|
||||
/**
|
||||
* Calls consume of a node for every object if the data sequentially.
|
||||
*/
|
||||
template <typename T> TaskResult SequentialProducingTask<T>::execute(const std::uint16_t worker_id)
|
||||
{
|
||||
auto sequence = 0ULL;
|
||||
|
||||
for (auto &data : this->_node->annotation().token_generator()->generate(worker_id))
|
||||
{
|
||||
this->_node->consume(worker_id, *_graph, std::move(data));
|
||||
}
|
||||
|
||||
auto *finalize_task = mx::tasking::runtime::new_task<SequentialFinalizeTask<T>>(worker_id, _graph, _node);
|
||||
finalize_task->annotate(worker_id);
|
||||
return TaskResult::make_succeed_and_remove(finalize_task);
|
||||
}
|
||||
|
||||
/**
|
||||
* For every part of the data, a single parallel producing task will be spawned.
|
||||
* Keeping track using an atomic counter, the last task will call finalize for the node.
|
||||
*/
|
||||
template <typename T> TaskResult ParallelProducingTask<T>::execute(const std::uint16_t worker_id)
|
||||
{
|
||||
_node->consume(worker_id, *_graph, Token<T>{std::move(this->_data), this->annotation()});
|
||||
if (_finalize_counter.tick())
|
||||
{
|
||||
_graph->finalize(worker_id, _node);
|
||||
}
|
||||
|
||||
return TaskResult::make_remove();
|
||||
}
|
||||
|
||||
class FinalizeReduceCalculator
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] static std::pair<std::vector<std::vector<std::pair<resource::ptr, resource::ptr>>>, resource::ptr>
|
||||
pairs(const std::vector<resource::ptr> &data)
|
||||
{
|
||||
auto pairs = std::vector<std::vector<std::pair<resource::ptr, resource::ptr>>>{};
|
||||
|
||||
auto reduced_data = data;
|
||||
while (reduced_data.size() > 1U)
|
||||
{
|
||||
reduced_data = FinalizeReduceCalculator::reduce(pairs, std::move(reduced_data));
|
||||
}
|
||||
|
||||
return std::make_pair(std::move(pairs), reduced_data.front());
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] static std::vector<mx::resource::ptr> reduce(
|
||||
std::vector<std::vector<std::pair<resource::ptr, resource::ptr>>> &reduce_passes,
|
||||
std::vector<resource::ptr> &&to_reduce)
|
||||
{
|
||||
/// Pairs to reduce.
|
||||
auto pairs = std::vector<std::pair<mx::resource::ptr, mx::resource::ptr>>{};
|
||||
pairs.reserve(to_reduce.size() / 2U);
|
||||
|
||||
/// Data that will be reduced in the next step.
|
||||
auto to_reduce_next = std::vector<resource::ptr>{};
|
||||
to_reduce_next.reserve((to_reduce.size() / 2U) + 1U);
|
||||
|
||||
const auto is_odd = to_reduce.size() % 2U != 0U;
|
||||
for (auto i = 0U; i < to_reduce.size() - static_cast<std::uint16_t>(is_odd); i += 2U)
|
||||
{
|
||||
pairs.emplace_back(std::make_pair(to_reduce[i], to_reduce[i + 1U]));
|
||||
to_reduce_next.emplace_back(to_reduce[i]);
|
||||
}
|
||||
|
||||
if (is_odd)
|
||||
{
|
||||
to_reduce_next.emplace_back(to_reduce.back());
|
||||
}
|
||||
|
||||
if (pairs.empty() == false)
|
||||
{
|
||||
reduce_passes.emplace_back(std::move(pairs));
|
||||
}
|
||||
|
||||
return to_reduce_next;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> void Graph<T>::finalize(const std::uint16_t worker_id, NodeInterface<T> *node)
|
||||
{
|
||||
const auto finalization_type = node->annotation().finalization_type();
|
||||
if (finalization_type == annotation<T>::FinalizationType::parallel)
|
||||
{
|
||||
auto *finalized_worker_counter =
|
||||
new (std::aligned_alloc(system::cache::line_size(), sizeof(std::atomic_uint16_t)))
|
||||
std::atomic_uint16_t(node->annotation().finalize_sequence().size());
|
||||
for (auto data : node->annotation().finalize_sequence())
|
||||
{
|
||||
data.reset(resource::information{data.worker_id(), synchronization::primitive::ScheduleAll});
|
||||
auto *finalize_task =
|
||||
runtime::new_task<ParallelFinalizeTask<T>>(worker_id, this, node, finalized_worker_counter);
|
||||
finalize_task->annotate(data);
|
||||
runtime::spawn(*finalize_task, worker_id);
|
||||
}
|
||||
}
|
||||
else if (finalization_type == annotation<T>::FinalizationType::reduce)
|
||||
{
|
||||
/// List of list of resource pairs to reduce.
|
||||
auto reduce_resource_pairs = FinalizeReduceCalculator::pairs(node->annotation().finalize_sequence());
|
||||
auto &pair_lists = std::get<0>(reduce_resource_pairs);
|
||||
|
||||
/// The resource with the final finalization task (that will be a sequential finalization task).
|
||||
const auto last_resource = std::get<1>(reduce_resource_pairs);
|
||||
|
||||
/// Create the last and final finalization task.
|
||||
auto *last_finalization_task = runtime::new_task<SequentialFinalizeTask<T>>(worker_id, this, node);
|
||||
last_finalization_task->annotate(last_resource);
|
||||
if (pair_lists.empty())
|
||||
{
|
||||
runtime::spawn(*last_finalization_task, worker_id);
|
||||
return;
|
||||
}
|
||||
|
||||
/// Reduce tasks, one map (main worker id -> finalization task) per "reduce stage".
|
||||
auto tasks = std::vector<std::unordered_map<resource::ptr, ReduceFinalizeTask<T> *>>{};
|
||||
tasks.reserve(pair_lists.size());
|
||||
|
||||
/// Create all reduce tasks.
|
||||
for (auto &pair_list : pair_lists)
|
||||
{
|
||||
auto task_map = std::unordered_map<resource::ptr, ReduceFinalizeTask<T> *>{};
|
||||
task_map.reserve(pair_list.size());
|
||||
|
||||
for (auto &pair : pair_list)
|
||||
{
|
||||
const auto main_resource = std::get<0>(pair);
|
||||
const auto reduced_resource = std::get<1>(pair);
|
||||
auto *reduce_task = runtime::new_task<ReduceFinalizeTask<T>>(worker_id, this, node, reduced_resource);
|
||||
reduce_task->annotate(main_resource);
|
||||
task_map.insert(std::make_pair(main_resource, reduce_task));
|
||||
}
|
||||
|
||||
tasks.template emplace_back(std::move(task_map));
|
||||
}
|
||||
|
||||
/// Setup the last reduce step.
|
||||
if (auto iterator = tasks.back().find(last_resource); iterator != tasks.back().end())
|
||||
{
|
||||
iterator->second->follow_up_task(last_finalization_task);
|
||||
}
|
||||
|
||||
/// Setup all follow up tasks.
|
||||
for (auto stage = tasks.size() - 1U; stage > 0U; --stage)
|
||||
{
|
||||
for (auto [main_resource, task] : tasks[stage])
|
||||
{
|
||||
/// The task for the main worker will be in the last stage.
|
||||
if (auto main_resource_task = tasks[stage - 1U].find(main_resource);
|
||||
main_resource_task != tasks[stage - 1U].end())
|
||||
{
|
||||
main_resource_task->second->follow_up_task(task);
|
||||
}
|
||||
|
||||
/// The task for the reduced worker may be in any stage before.
|
||||
const auto reduced_resource = task->reduced_resource();
|
||||
for (auto reduced_stage = stage - 1U; reduced_stage >= 0U; --reduced_stage)
|
||||
{
|
||||
if (auto reduced_resource_task = tasks[reduced_stage].find(reduced_resource);
|
||||
reduced_resource_task != tasks[reduced_stage].end())
|
||||
{
|
||||
reduced_resource_task->second->follow_up_task(task);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Spawn tasks of the first stage.
|
||||
for (auto [_, finalization_task] : tasks[0])
|
||||
{
|
||||
runtime::spawn(*finalization_task, worker_id);
|
||||
}
|
||||
}
|
||||
else if (finalization_type == annotation<T>::FinalizationType::none)
|
||||
{
|
||||
node->finalize(worker_id, *this, true, nullptr, nullptr);
|
||||
this->complete(worker_id, node);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto *finalize_task = runtime::new_task<SequentialFinalizeTask<T>>(worker_id, this, node);
|
||||
finalize_task->annotate(mx::tasking::annotation::local);
|
||||
runtime::spawn(*finalize_task, worker_id);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> bool Graph<T>::complete(std::uint16_t worker_id, NodeInterface<T> *node)
|
||||
{
|
||||
if constexpr (config::is_record_graph_times())
|
||||
{
|
||||
if (this->_is_record_times)
|
||||
{
|
||||
this->_node_finish_times.insert(std::make_pair(node, std::chrono::system_clock::now()));
|
||||
}
|
||||
}
|
||||
|
||||
/// Tell the next node, that this node has completed.
|
||||
Pipeline<T> *next_node_pipeline{nullptr};
|
||||
if (node->out() != nullptr)
|
||||
{
|
||||
node->out()->in_completed(worker_id, *this, *node);
|
||||
next_node_pipeline = this->_node_pipelines.at(node->out());
|
||||
}
|
||||
|
||||
/// Maybe, the node was the last one in it's pipeline.
|
||||
/// If so, we may trigger one or multiple pipelines that depended on the nodes pipeline.
|
||||
auto *node_pipeline = this->_node_pipelines.at(node);
|
||||
auto pipelines_to_start = std::vector<Pipeline<T> *>{};
|
||||
if (node_pipeline != next_node_pipeline || node->annotation().is_finalizes_pipeline())
|
||||
{
|
||||
this->_pipeline_dependencies_lock.lock();
|
||||
|
||||
/// Remove the nodes pipeline from the dependency list of all other pipelines.
|
||||
/// If, after removing the pipeline from dependencies, there are pipelines without
|
||||
/// dependency, we can start that pipelines.
|
||||
for (auto &[pipeline, dependencies] : this->_pipeline_dependencies)
|
||||
{
|
||||
auto dependency_iterator = std::find(dependencies.begin(), dependencies.end(), node_pipeline);
|
||||
if (dependency_iterator != dependencies.end())
|
||||
{
|
||||
dependencies.erase(dependency_iterator);
|
||||
}
|
||||
|
||||
if (dependencies.empty())
|
||||
{
|
||||
pipelines_to_start.emplace_back(pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
/// Start all pipelines without dependency.
|
||||
for (auto *pipeline : pipelines_to_start)
|
||||
{
|
||||
this->_pipeline_dependencies.erase(pipeline);
|
||||
this->start(worker_id, pipeline);
|
||||
}
|
||||
|
||||
this->_pipeline_dependencies_lock.unlock();
|
||||
}
|
||||
|
||||
/// If the node was has no successor and we did not start any pipeline, we finished.
|
||||
if (node->out() == nullptr)
|
||||
{
|
||||
if (this->_finished_pipelines.fetch_add(1U) == (this->_pipelines.size() - 1U))
|
||||
{
|
||||
delete this;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace mx::tasking::dataflow
|
||||
134
repos/ealanos/src/lib/mx/tasking/dataflow/node.h
Normal file
134
repos/ealanos/src/lib/mx/tasking/dataflow/node.h
Normal file
@@ -0,0 +1,134 @@
|
||||
#pragma once
|
||||
|
||||
#include "annotation.h"
|
||||
#include "producer.h"
|
||||
#include "token.h"
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace mx::tasking::dataflow {
|
||||
template <typename T> class NodeInterface
|
||||
{
|
||||
public:
|
||||
NodeInterface() = default;
|
||||
virtual ~NodeInterface() = default;
|
||||
|
||||
/**
|
||||
* Updates the successor.
|
||||
*
|
||||
* @param out New successor.
|
||||
*/
|
||||
virtual void out(NodeInterface *out) noexcept { _out = out; }
|
||||
|
||||
/**
|
||||
* @return The successor of this node.
|
||||
*/
|
||||
[[nodiscard]] NodeInterface *out() const noexcept { return _out; }
|
||||
|
||||
/**
|
||||
* Inserts the given node as a predecessor of this node.
|
||||
*
|
||||
* @param incomeing Node to insert in the predecessor list.
|
||||
*/
|
||||
virtual void add_in(NodeInterface *incomeing) noexcept { _in.emplace_back(incomeing); }
|
||||
|
||||
/**
|
||||
* @return A list of predecessors of this node.
|
||||
*/
|
||||
[[nodiscard]] const std::vector<NodeInterface *> &in() const noexcept { return _in; }
|
||||
|
||||
/**
|
||||
* Updates the annotation of this node.
|
||||
*
|
||||
* @param annotation New annotation.
|
||||
*/
|
||||
void annotate(dataflow::annotation<T> &&annotation) noexcept { _annotation = std::move(annotation); }
|
||||
|
||||
/**
|
||||
* @return The annotation of the node.
|
||||
*/
|
||||
[[nodiscard]] const dataflow::annotation<T> &annotation() const noexcept { return _annotation; }
|
||||
|
||||
/**
|
||||
* @return The annotation of the node.
|
||||
*/
|
||||
[[nodiscard]] dataflow::annotation<T> &annotation() noexcept { return _annotation; }
|
||||
|
||||
/**
|
||||
* Consumes data and may emit data to the graph. This function is called
|
||||
* by the graph when a predecessor emits data to the graph.
|
||||
*
|
||||
* @param worker_id Worker, where the data is consumed.
|
||||
* @param emitter Emitter that takes data when the node wants to emit data.
|
||||
* @param data Data that is consumed.
|
||||
*/
|
||||
virtual void consume(std::uint16_t worker_id, EmitterInterface<T> &emitter, Token<T> &&data) = 0;
|
||||
|
||||
/**
|
||||
* Callback that is called by the graph when one of the
|
||||
* incoming nodes completes its execution.
|
||||
*
|
||||
* @param worker_id Worker, where the incoming node completed.
|
||||
* @param emitter Emitter that takes data when the node wants to emit data.
|
||||
* @param in_node Node that completed.
|
||||
*/
|
||||
virtual void in_completed(std::uint16_t worker_id, EmitterInterface<T> &emitter, NodeInterface<T> &in_node) = 0;
|
||||
|
||||
/**
|
||||
* Callback that is called by the graph, when a nodes completes.
|
||||
*
|
||||
* @param worker_id Worker, where the node closes.
|
||||
* @param emitter Emitter that takes data when the node wants to emit data.
|
||||
* @param is_last True, if this is the last finalization call (may be interesting for parallel finalization).
|
||||
* @param data Data that is finalized, may be nullptr.
|
||||
* @param reduced_data Data that is reduced, may be nullptr.
|
||||
*/
|
||||
virtual void finalize(const std::uint16_t /*worker_id*/, EmitterInterface<T> & /*emitter*/, const bool /*is_last*/,
|
||||
const mx::resource::ptr /*data*/, const mx::resource::ptr /*reduced_data*/)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::string to_string() const noexcept = 0;
|
||||
|
||||
[[nodiscard]] virtual std::uint64_t trace_id() const noexcept { return 0U; }
|
||||
|
||||
private:
|
||||
/// Node where data is emitted to.
|
||||
NodeInterface<T> *_out{nullptr};
|
||||
/// Nodes from where data is consumed.
|
||||
std::vector<NodeInterface<T> *> _in;
|
||||
|
||||
/// Annotation.
|
||||
dataflow::annotation<T> _annotation;
|
||||
};
|
||||
|
||||
template <typename T> class ProducingNodeInterface : public NodeInterface<T>
|
||||
{
|
||||
public:
|
||||
ProducingNodeInterface<T>() = default;
|
||||
~ProducingNodeInterface<T>() override = default;
|
||||
|
||||
void in_completed(const std::uint16_t /*worker_id*/, EmitterInterface<T> & /*emitter*/,
|
||||
NodeInterface<T> & /*in_node*/) override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> class EmptyNode final : public NodeInterface<T>
|
||||
{
|
||||
public:
|
||||
EmptyNode<T>() = default;
|
||||
~EmptyNode<T>() override = default;
|
||||
|
||||
void consume(const std::uint16_t /*worker_id*/, EmitterInterface<T> & /*emitter*/, Token<T> && /*data*/) override {}
|
||||
|
||||
void in_completed(const std::uint16_t worker_id, EmitterInterface<T> &emitter,
|
||||
NodeInterface<T> & /*in_node*/) override
|
||||
{
|
||||
emitter.finalize(worker_id, this);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string to_string() const noexcept override { return "Empty Node"; }
|
||||
};
|
||||
} // namespace mx::tasking::dataflow
|
||||
30
repos/ealanos/src/lib/mx/tasking/dataflow/pipeline.h
Normal file
30
repos/ealanos/src/lib/mx/tasking/dataflow/pipeline.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "node.h"
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
namespace mx::tasking::dataflow {
|
||||
template <typename T> class alignas(64) Pipeline
|
||||
{
|
||||
public:
|
||||
Pipeline() { _nodes.reserve(1U << 4U); }
|
||||
|
||||
~Pipeline()
|
||||
{
|
||||
std::for_each(_nodes.begin(), _nodes.end(), [](auto node) { delete node; });
|
||||
}
|
||||
|
||||
void emplace(NodeInterface<T> *node) { _nodes.template emplace_back(node); }
|
||||
[[nodiscard]] const std::vector<NodeInterface<T> *> &nodes() const noexcept { return _nodes; }
|
||||
|
||||
[[nodiscard]] std::atomic_uint16_t &finalization_barrier_counter() noexcept
|
||||
{
|
||||
return _finalization_barrier_counter;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<NodeInterface<T> *> _nodes;
|
||||
alignas(64) std::atomic_uint16_t _finalization_barrier_counter;
|
||||
};
|
||||
} // namespace mx::tasking::dataflow
|
||||
19
repos/ealanos/src/lib/mx/tasking/dataflow/producer.h
Normal file
19
repos/ealanos/src/lib/mx/tasking/dataflow/producer.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "token.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace mx::tasking::dataflow {
|
||||
template <typename T> class NodeInterface;
|
||||
template <typename T> class EmitterInterface
|
||||
{
|
||||
public:
|
||||
constexpr EmitterInterface() noexcept = default;
|
||||
virtual ~EmitterInterface() noexcept = default;
|
||||
|
||||
virtual void emit(std::uint16_t worker_id, NodeInterface<T> *node, Token<T> &&data) = 0;
|
||||
virtual void finalize(std::uint16_t worker_id, NodeInterface<T> *node) = 0;
|
||||
virtual void interrupt() = 0;
|
||||
virtual void for_each_node(std::function<void(NodeInterface<T> *)> &&callback) const = 0;
|
||||
};
|
||||
} // namespace mx::tasking::dataflow
|
||||
149
repos/ealanos/src/lib/mx/tasking/dataflow/task_node.h
Normal file
149
repos/ealanos/src/lib/mx/tasking/dataflow/task_node.h
Normal file
@@ -0,0 +1,149 @@
|
||||
#pragma once
|
||||
|
||||
#include "barrier_task.h"
|
||||
#include "node.h"
|
||||
#include "producer.h"
|
||||
#include "token.h"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <mx/tasking/runtime.h>
|
||||
#include <mx/tasking/task.h>
|
||||
#include <mx/util/aligned_t.h>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace mx::tasking::dataflow {
|
||||
/**
|
||||
* Task that consumes and produces data in context of nodes.
|
||||
*/
|
||||
template <typename T> class DataTaskInterface
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
constexpr DataTaskInterface() noexcept = default;
|
||||
virtual ~DataTaskInterface() noexcept = default;
|
||||
|
||||
/**
|
||||
* Consumes the given data.
|
||||
* New data may be emitted to the given node.
|
||||
*
|
||||
* @param worker_id Local worker id where the task is executed.
|
||||
* @param node Node that executes that task.
|
||||
* @param emitter Emitter that can emit new data.
|
||||
* @param data Data that is consumed by that task.
|
||||
*/
|
||||
virtual void execute(std::uint16_t worker_id, NodeInterface<T> *node, EmitterInterface<T> &emitter,
|
||||
Token<T> &&data) = 0;
|
||||
};
|
||||
|
||||
enum input_cardinality
|
||||
{
|
||||
single,
|
||||
multiple
|
||||
};
|
||||
|
||||
template <class DataTask> class NodeTask;
|
||||
template <typename DataTask> class TaskNode : public NodeInterface<typename DataTask::value_type>
|
||||
{
|
||||
friend NodeTask<DataTask>;
|
||||
|
||||
public:
|
||||
using value_type = typename DataTask::value_type;
|
||||
|
||||
TaskNode() noexcept = default;
|
||||
|
||||
~TaskNode() noexcept override = default;
|
||||
|
||||
void add_in(NodeInterface<value_type> *in_node) noexcept override
|
||||
{
|
||||
_count_nodes_in.fetch_add(1);
|
||||
NodeInterface<value_type>::add_in(in_node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes the data by spawning a task of type TASK_TYPE.
|
||||
*
|
||||
* @param worker_id Worker where consume is called.
|
||||
* @param graph Graph where the node is located in.
|
||||
* @param token Data that is consumed.
|
||||
*/
|
||||
void consume(std::uint16_t worker_id, EmitterInterface<value_type> &graph, Token<value_type> &&token) override;
|
||||
|
||||
/**
|
||||
* Called whenever the succeeding node was finalized.
|
||||
*
|
||||
* @param worker_id Core where consume is called.
|
||||
* @param graph Graph where the node is located in.
|
||||
*/
|
||||
void in_completed(const std::uint16_t worker_id, EmitterInterface<value_type> &graph,
|
||||
NodeInterface<value_type> & /*in_node*/) override
|
||||
{
|
||||
if (_count_nodes_in.fetch_sub(1) == 1)
|
||||
{
|
||||
const auto count_workers = mx::tasking::runtime::workers();
|
||||
_count_pending_workers = count_workers - 1;
|
||||
for (auto target_worker_id = std::uint16_t(0U); target_worker_id < count_workers; ++target_worker_id)
|
||||
{
|
||||
auto *barrier_task = mx::tasking::runtime::new_task<FinalizationBarrierTask<value_type>>(
|
||||
worker_id, _count_pending_workers, graph, this);
|
||||
barrier_task->annotate(target_worker_id);
|
||||
mx::tasking::runtime::spawn(*barrier_task, worker_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string to_string() const noexcept override
|
||||
{
|
||||
return std::string{"Task Skeleton ["} + typeid(DataTask).name() + "]";
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_int16_t _count_nodes_in{0U};
|
||||
std::atomic_int16_t _count_pending_workers{0U};
|
||||
};
|
||||
|
||||
/**
|
||||
* The NodeTask executes ("wraps") the DataTask of the given node and executed the node logic.
|
||||
* @tparam DataTask
|
||||
*/
|
||||
template <class DataTask> class NodeTask final : public TaskInterface
|
||||
{
|
||||
public:
|
||||
NodeTask(TaskNode<DataTask> *owning_node, EmitterInterface<typename DataTask::value_type> &graph,
|
||||
Token<typename DataTask::value_type> &&token) noexcept
|
||||
: _owning_node(owning_node), _graph(graph), _token_data(std::move(token.data()))
|
||||
{
|
||||
}
|
||||
~NodeTask() noexcept override = default;
|
||||
|
||||
TaskResult execute(const std::uint16_t worker_id) override
|
||||
{
|
||||
DataTask{}.execute(worker_id, _owning_node, _graph,
|
||||
Token<typename DataTask::value_type>{std::move(_token_data), annotation()});
|
||||
|
||||
return TaskResult::make_remove();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint64_t trace_id() const noexcept override { return _owning_node->trace_id(); }
|
||||
|
||||
private:
|
||||
TaskNode<DataTask> *_owning_node;
|
||||
EmitterInterface<typename DataTask::value_type> &_graph;
|
||||
|
||||
/// Data that was consumed by the node.
|
||||
typename DataTask::value_type _token_data;
|
||||
};
|
||||
|
||||
template <typename DataTask>
|
||||
void TaskNode<DataTask>::consume(const std::uint16_t worker_id, EmitterInterface<typename DataTask::value_type> &graph,
|
||||
Token<typename DataTask::value_type> &&token)
|
||||
{
|
||||
// _task_counter.add(worker_id, 1);
|
||||
const auto annotation = token.annotation();
|
||||
auto *node_task = runtime::new_task<NodeTask<DataTask>>(worker_id, this, graph, std::move(token));
|
||||
node_task->annotate(annotation);
|
||||
|
||||
runtime::spawn(*node_task, worker_id);
|
||||
}
|
||||
} // namespace mx::tasking::dataflow
|
||||
58
repos/ealanos/src/lib/mx/tasking/dataflow/token.h
Normal file
58
repos/ealanos/src/lib/mx/tasking/dataflow/token.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include <mx/tasking/annotation.h>
|
||||
|
||||
namespace mx::tasking::dataflow {
|
||||
template <typename T> class Token
|
||||
{
|
||||
public:
|
||||
Token() noexcept = default;
|
||||
explicit Token(T &&data) noexcept : _data(std::move(data)) {}
|
||||
explicit Token(const T &data) noexcept : _data(data) {}
|
||||
Token(T &&data, tasking::annotation annotation) noexcept
|
||||
: _data(std::move(data)), _annotation(std::move(annotation))
|
||||
{
|
||||
}
|
||||
Token(const T &data, tasking::annotation annotation) noexcept : _data(data), _annotation(std::move(annotation)) {}
|
||||
Token(Token<T> &&other) noexcept : _data(std::move(other._data)), _annotation(std::move(other._annotation)) {}
|
||||
~Token() noexcept = default;
|
||||
|
||||
Token<T> &operator=(Token<T> &&other) noexcept
|
||||
{
|
||||
_data = std::move(other._data);
|
||||
_annotation = other._annotation;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] const T &data() const noexcept { return _data; }
|
||||
[[nodiscard]] T &data() noexcept { return _data; }
|
||||
[[nodiscard]] tasking::annotation annotation() const noexcept { return _annotation; }
|
||||
[[nodiscard]] tasking::annotation &annotation() noexcept { return _annotation; }
|
||||
|
||||
private:
|
||||
T _data;
|
||||
class tasking::annotation _annotation
|
||||
{
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T> static inline Token<T> make_token(T &&data) noexcept
|
||||
{
|
||||
return Token<T>{std::move(data)};
|
||||
}
|
||||
|
||||
template <typename T> static inline Token<T> make_token(const T &data) noexcept
|
||||
{
|
||||
return Token<T>{data};
|
||||
}
|
||||
|
||||
template <typename T> static inline Token<T> make_token(T &&data, tasking::annotation annotation) noexcept
|
||||
{
|
||||
return Token<T>{std::move(data), annotation};
|
||||
}
|
||||
|
||||
template <typename T> static inline Token<T> make_token(const T &data, tasking::annotation annotation) noexcept
|
||||
{
|
||||
return Token<T>{data, annotation};
|
||||
}
|
||||
} // namespace mx::tasking::dataflow
|
||||
18
repos/ealanos/src/lib/mx/tasking/dataflow/token_generator.h
Normal file
18
repos/ealanos/src/lib/mx/tasking/dataflow/token_generator.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "token.h"
|
||||
#include <cstdint>
|
||||
#include <mx/tasking/prefetch_descriptor.h>
|
||||
#include <vector>
|
||||
|
||||
namespace mx::tasking::dataflow {
|
||||
template <typename T> class TokenGenerator
|
||||
{
|
||||
public:
|
||||
constexpr TokenGenerator() noexcept = default;
|
||||
virtual ~TokenGenerator() noexcept = default;
|
||||
|
||||
[[nodiscard]] virtual std::vector<Token<T>> generate(std::uint16_t worker_id) = 0;
|
||||
[[nodiscard]] virtual std::uint64_t count() = 0;
|
||||
};
|
||||
} // namespace mx::tasking::dataflow
|
||||
26
repos/ealanos/src/lib/mx/tasking/load.h
Normal file
26
repos/ealanos/src/lib/mx/tasking/load.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include "config.h"
|
||||
#include <bitset>
|
||||
#include <cstdint>
|
||||
|
||||
namespace mx::tasking {
|
||||
/**
|
||||
* Persists the channel load for the last 64 requests.
|
||||
*/
|
||||
class Load
|
||||
{
|
||||
public:
|
||||
constexpr Load() = default;
|
||||
~Load() = default;
|
||||
|
||||
void set(const std::uint16_t count_withdrawed_task) noexcept
|
||||
{
|
||||
_load = count_withdrawed_task / float(config::task_buffer_size());
|
||||
}
|
||||
|
||||
[[nodiscard]] float get() const noexcept { return _load; }
|
||||
|
||||
private:
|
||||
float _load{0U};
|
||||
};
|
||||
} // namespace mx::tasking
|
||||
296
repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h
Normal file
296
repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h
Normal file
@@ -0,0 +1,296 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <mx/memory/alignment_helper.h>
|
||||
#include <mx/resource/ptr.h>
|
||||
#include <mx/system/builtin.h>
|
||||
#include <mx/system/environment.h>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace mx::tasking {
|
||||
|
||||
class PrefetchDescriptor
|
||||
{
|
||||
public:
|
||||
using data_t = std::uint64_t;
|
||||
|
||||
enum ExecuteType : std::uint8_t
|
||||
{
|
||||
Size = 0b01,
|
||||
Callback = 0b10,
|
||||
Mask = 0b11,
|
||||
};
|
||||
|
||||
enum PrefetchType : std::uint8_t
|
||||
{
|
||||
Temporal = 0b01,
|
||||
NonTemporal = 0b10,
|
||||
Write = 0b11,
|
||||
};
|
||||
|
||||
enum Type : std::uint8_t
|
||||
{
|
||||
None = 0b0000,
|
||||
|
||||
SizeTemporal = (ExecuteType::Size << 2U) | PrefetchType::Temporal,
|
||||
SizeNonTemporal = (ExecuteType::Size << 2U) | PrefetchType::NonTemporal,
|
||||
SizeWrite = (ExecuteType::Size << 2U) | PrefetchType::Write,
|
||||
|
||||
CallbackAny = ExecuteType::Callback << 2U,
|
||||
|
||||
MaskTemporal = (ExecuteType::Mask << 2U) | PrefetchType::Temporal,
|
||||
MaskNonTemporal = (ExecuteType::Mask << 2U) | PrefetchType::NonTemporal,
|
||||
MaskWrite = (ExecuteType::Mask << 2U) | PrefetchType::Write,
|
||||
};
|
||||
|
||||
private:
|
||||
static inline constexpr auto BITS = sizeof(data_t) * 8U;
|
||||
static inline constexpr auto RESERVED_BITS = 4U;
|
||||
static inline constexpr auto DATA_BITS = BITS - RESERVED_BITS;
|
||||
static inline constexpr auto CLEAR_TYPE_MASK = std::numeric_limits<data_t>::max() >> RESERVED_BITS;
|
||||
|
||||
public:
|
||||
[[nodiscard]] static constexpr auto capacity() { return DATA_BITS; }
|
||||
[[nodiscard]] static constexpr auto bits() { return BITS; }
|
||||
|
||||
[[nodiscard]] static PrefetchDescriptor make_size(const PrefetchType type, const data_t data) noexcept
|
||||
{
|
||||
return PrefetchDescriptor{((data_t(ExecuteType::Size << 2U) | type) << DATA_BITS) | data};
|
||||
}
|
||||
|
||||
[[nodiscard]] static PrefetchDescriptor make_mask(const PrefetchType type, const data_t data) noexcept
|
||||
{
|
||||
return PrefetchDescriptor{((data_t(ExecuteType::Mask << 2U) | type) << DATA_BITS) | data};
|
||||
}
|
||||
|
||||
[[nodiscard]] static PrefetchDescriptor make_callback(const data_t data) noexcept
|
||||
{
|
||||
return PrefetchDescriptor{(data_t(ExecuteType::Callback << 2U) << DATA_BITS) | data};
|
||||
}
|
||||
|
||||
constexpr PrefetchDescriptor() noexcept = default;
|
||||
constexpr explicit PrefetchDescriptor(const data_t data) noexcept : _data(data) {}
|
||||
~PrefetchDescriptor() noexcept = default;
|
||||
|
||||
/**
|
||||
* @return The type if the descriptor.
|
||||
*/
|
||||
[[nodiscard]] Type id() const noexcept { return static_cast<Type>(_data >> DATA_BITS); }
|
||||
|
||||
[[nodiscard]] bool empty() const noexcept { return (_data & CLEAR_TYPE_MASK) == 0U; }
|
||||
|
||||
[[nodiscard]] data_t data() const noexcept { return _data; }
|
||||
[[nodiscard]] data_t &data() noexcept { return _data; }
|
||||
[[nodiscard]] data_t data_without_descriptor_bits() const noexcept { return _data & CLEAR_TYPE_MASK; }
|
||||
|
||||
PrefetchDescriptor operator|(const PrefetchDescriptor other) const noexcept
|
||||
{
|
||||
return PrefetchDescriptor{_data | other._data};
|
||||
}
|
||||
PrefetchDescriptor &operator|=(const PrefetchDescriptor other) noexcept
|
||||
{
|
||||
_data |= other._data;
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const PrefetchDescriptor other) const noexcept { return _data == other._data; }
|
||||
|
||||
private:
|
||||
data_t _data{0U};
|
||||
};
|
||||
|
||||
class PrefetchSizeView
|
||||
{
|
||||
public:
|
||||
constexpr PrefetchSizeView(const PrefetchDescriptor::data_t data) noexcept : _data(data) {}
|
||||
PrefetchSizeView(const PrefetchDescriptor data) noexcept : _data(data.data_without_descriptor_bits()) {}
|
||||
~PrefetchSizeView() noexcept = default;
|
||||
|
||||
PrefetchSizeView &operator=(PrefetchSizeView &&) noexcept = default;
|
||||
PrefetchSizeView &operator=(const PrefetchSizeView &) noexcept = default;
|
||||
|
||||
/**
|
||||
* @return The size to prefetch.
|
||||
*/
|
||||
[[nodiscard]] std::uint64_t get() const noexcept { return _data; }
|
||||
|
||||
private:
|
||||
PrefetchDescriptor::data_t _data;
|
||||
};
|
||||
|
||||
class PrefetchMaskView
|
||||
{
|
||||
public:
|
||||
constexpr PrefetchMaskView(const PrefetchDescriptor::data_t data) noexcept : _data(data) {}
|
||||
PrefetchMaskView(const PrefetchDescriptor data) noexcept : _data(data.data_without_descriptor_bits()) {}
|
||||
~PrefetchMaskView() noexcept = default;
|
||||
|
||||
PrefetchMaskView &operator=(PrefetchMaskView &&) noexcept = default;
|
||||
PrefetchMaskView &operator=(const PrefetchMaskView &) noexcept = default;
|
||||
|
||||
/**
|
||||
* @return Number of cache lines that can be stored within the mask.
|
||||
*/
|
||||
[[nodiscard]] static constexpr auto capacity() { return PrefetchDescriptor::capacity(); }
|
||||
|
||||
/**
|
||||
* @return Number of set bits.
|
||||
*/
|
||||
[[nodiscard]] std::uint8_t count() const noexcept { return std::popcount(_data); }
|
||||
|
||||
/**
|
||||
* @return True, if the data is empty.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const noexcept { return _data == 0U; }
|
||||
|
||||
/**
|
||||
* Tests if a given index is set.
|
||||
*
|
||||
* @param index Index to test.
|
||||
* @return True, if the given index is set.
|
||||
*/
|
||||
[[nodiscard]] bool test(const std::uint8_t index) const noexcept
|
||||
{
|
||||
return static_cast<bool>(_data & (PrefetchDescriptor::data_t{1U} << index));
|
||||
}
|
||||
|
||||
private:
|
||||
PrefetchDescriptor::data_t _data;
|
||||
};
|
||||
|
||||
class PrefetchCallbackView
|
||||
{
|
||||
public:
|
||||
using callback_t = void (*)(void *);
|
||||
[[nodiscard]] static constexpr auto bits_for_size() { return 8U; }
|
||||
[[nodiscard]] static constexpr auto bits_for_pointer() { return PrefetchDescriptor::capacity() - bits_for_size(); }
|
||||
|
||||
constexpr PrefetchCallbackView(const PrefetchDescriptor::data_t data) noexcept : _data(data) {}
|
||||
PrefetchCallbackView(const PrefetchDescriptor data) noexcept : _data(data.data_without_descriptor_bits()) {}
|
||||
~PrefetchCallbackView() noexcept = default;
|
||||
|
||||
PrefetchCallbackView &operator=(PrefetchCallbackView &&) noexcept = default;
|
||||
PrefetchCallbackView &operator=(const PrefetchCallbackView &) noexcept = default;
|
||||
|
||||
/**
|
||||
* @return The number of cache lines that will be prefetched by the callback.
|
||||
*/
|
||||
[[nodiscard]] std::uint8_t size() const noexcept { return _data >> bits_for_pointer(); }
|
||||
|
||||
/**
|
||||
* @return The callback for prefetching.
|
||||
*/
|
||||
[[nodiscard]] callback_t get() const noexcept
|
||||
{
|
||||
return reinterpret_cast<callback_t>(_data & PrefetchDescriptor::data_t(std::pow(2, bits_for_pointer()) - 1));
|
||||
}
|
||||
|
||||
private:
|
||||
PrefetchDescriptor::data_t _data;
|
||||
};
|
||||
|
||||
class PrefetchSize
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] static PrefetchDescriptor make(const PrefetchDescriptor::PrefetchType type,
|
||||
const std::uint64_t size) noexcept
|
||||
{
|
||||
return PrefetchDescriptor::make_size(type, size);
|
||||
}
|
||||
};
|
||||
|
||||
class PrefetchMask
|
||||
{
|
||||
public:
|
||||
constexpr PrefetchMask() noexcept = default;
|
||||
~PrefetchMask() noexcept = default;
|
||||
|
||||
void set(const std::uint8_t index) noexcept { _data |= (1U << index); }
|
||||
|
||||
[[nodiscard]] PrefetchDescriptor make(const PrefetchDescriptor::PrefetchType type) const noexcept
|
||||
{
|
||||
return PrefetchDescriptor::make_mask(type, _data);
|
||||
}
|
||||
|
||||
[[nodiscard]] static PrefetchDescriptor make(const PrefetchDescriptor::PrefetchType type,
|
||||
PrefetchDescriptor::data_t data) noexcept
|
||||
{
|
||||
return PrefetchDescriptor::make_mask(type, data);
|
||||
}
|
||||
|
||||
private:
|
||||
PrefetchDescriptor::data_t _data{0U};
|
||||
};
|
||||
|
||||
class PrefetchCallback
|
||||
{
|
||||
public:
|
||||
constexpr PrefetchCallback() noexcept = default;
|
||||
~PrefetchCallback() noexcept = default;
|
||||
|
||||
[[nodiscard]] static PrefetchDescriptor make(const std::uint8_t size, const std::uintptr_t callback) noexcept
|
||||
{
|
||||
const auto data =
|
||||
(PrefetchDescriptor::data_t(size) << PrefetchCallbackView::bits_for_pointer()) |
|
||||
(callback & PrefetchDescriptor::data_t(std::pow(2, PrefetchCallbackView::bits_for_pointer()) - 1));
|
||||
return PrefetchDescriptor::make_callback(data);
|
||||
}
|
||||
};
|
||||
|
||||
class PrefetchHint
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] static PrefetchHint make_size(const PrefetchDescriptor::PrefetchType type, const std::uint64_t size,
|
||||
const resource::ptr resource) noexcept
|
||||
{
|
||||
return PrefetchHint{PrefetchSize::make(type, size), resource};
|
||||
}
|
||||
|
||||
[[nodiscard]] static PrefetchHint make_callback(const std::uint8_t size, const std::uintptr_t callback,
|
||||
const resource::ptr resource) noexcept
|
||||
{
|
||||
return PrefetchHint{PrefetchCallback::make(size, callback), resource};
|
||||
}
|
||||
|
||||
constexpr PrefetchHint() noexcept = default;
|
||||
constexpr PrefetchHint(const PrefetchDescriptor descriptor, const resource::ptr resource) noexcept
|
||||
: _descriptor(descriptor), _resource(resource)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr PrefetchHint(const PrefetchHint &) noexcept = default;
|
||||
constexpr PrefetchHint(PrefetchHint &&) noexcept = default;
|
||||
|
||||
~PrefetchHint() noexcept = default;
|
||||
|
||||
PrefetchHint &operator=(const PrefetchHint &) = default;
|
||||
PrefetchHint &operator=(PrefetchHint &&) = default;
|
||||
|
||||
[[nodiscard]] bool empty() const noexcept { return _descriptor.empty(); }
|
||||
[[nodiscard]] PrefetchDescriptor descriptor() const noexcept { return _descriptor; }
|
||||
[[nodiscard]] PrefetchMaskView as_mask() const noexcept
|
||||
{
|
||||
return PrefetchMaskView{_descriptor.data_without_descriptor_bits()};
|
||||
}
|
||||
|
||||
[[nodiscard]] PrefetchSizeView as_size() const noexcept
|
||||
{
|
||||
return PrefetchSizeView{_descriptor.data_without_descriptor_bits()};
|
||||
}
|
||||
|
||||
[[nodiscard]] resource::ptr resource() const noexcept { return _resource; }
|
||||
|
||||
bool operator==(const PrefetchHint &other) const noexcept
|
||||
{
|
||||
return _resource == other._resource && _descriptor == other._descriptor;
|
||||
}
|
||||
|
||||
private:
|
||||
PrefetchDescriptor _descriptor;
|
||||
resource::ptr _resource;
|
||||
};
|
||||
} // namespace mx::tasking
|
||||
39
repos/ealanos/src/lib/mx/tasking/prefetch_distance.h
Normal file
39
repos/ealanos/src/lib/mx/tasking/prefetch_distance.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace mx::tasking {
|
||||
class PrefetchDistance
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] constexpr static PrefetchDistance make_automatic() noexcept
|
||||
{
|
||||
return PrefetchDistance{std::numeric_limits<std::uint8_t>::max()};
|
||||
}
|
||||
|
||||
constexpr explicit PrefetchDistance(const std::uint8_t prefetch_distance) noexcept
|
||||
: _prefetch_distance(prefetch_distance)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr PrefetchDistance(const PrefetchDistance &) noexcept = default;
|
||||
|
||||
~PrefetchDistance() noexcept = default;
|
||||
|
||||
PrefetchDistance &operator=(PrefetchDistance &&) noexcept = default;
|
||||
|
||||
[[nodiscard]] bool is_enabled() const noexcept { return _prefetch_distance > 0U; }
|
||||
|
||||
[[nodiscard]] bool is_automatic() const noexcept
|
||||
{
|
||||
return _prefetch_distance == std::numeric_limits<std::uint8_t>::max();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_fixed() const noexcept { return is_enabled() && is_automatic() == false; }
|
||||
|
||||
[[nodiscard]] std::uint8_t fixed_distance() const noexcept { return _prefetch_distance; }
|
||||
|
||||
private:
|
||||
std::uint8_t _prefetch_distance;
|
||||
};
|
||||
} // namespace mx::tasking
|
||||
59
repos/ealanos/src/lib/mx/tasking/prefetch_slot.cpp
Normal file
59
repos/ealanos/src/lib/mx/tasking/prefetch_slot.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "prefetch_slot.h"
|
||||
#include <mx/system/cache.h>
|
||||
#include <mx/system/environment.h>
|
||||
|
||||
using namespace mx::tasking;
|
||||
|
||||
void PrefetchSlot::assign(const resource::ptr resource, const PrefetchDescriptor descriptor) noexcept
|
||||
{
|
||||
if (this->_item.has_resource() == false)
|
||||
{
|
||||
this->_item.resource(resource.get<std::int64_t>(), descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
void PrefetchSlot::prefetch() noexcept
|
||||
{
|
||||
const auto prefetch_type = this->_item.prefetch_descriptor().id();
|
||||
const auto prefetch_data = this->_item.prefetch_descriptor().data_without_descriptor_bits();
|
||||
auto *resource = this->_item.resource();
|
||||
switch (prefetch_type)
|
||||
{
|
||||
case PrefetchDescriptor::Type::SizeNonTemporal: {
|
||||
const auto size = PrefetchSizeView{prefetch_data}.get();
|
||||
system::cache::prefetch_range<system::cache::NTA, system::cache::read>(resource, size);
|
||||
break;
|
||||
}
|
||||
case PrefetchDescriptor::Type::SizeTemporal: {
|
||||
const auto size = PrefetchSizeView{prefetch_data}.get();
|
||||
system::cache::prefetch_range<system::cache::L2, system::cache::read>(resource, size);
|
||||
break;
|
||||
}
|
||||
case PrefetchDescriptor::Type::SizeWrite: {
|
||||
const auto size = PrefetchSizeView{prefetch_data}.get();
|
||||
system::cache::prefetch_range<system::cache::ALL, system::cache::write>(resource, size);
|
||||
break;
|
||||
}
|
||||
case PrefetchDescriptor::Type::CallbackAny: {
|
||||
auto *callback = PrefetchCallbackView{prefetch_data}.get();
|
||||
callback(reinterpret_cast<void *>(resource));
|
||||
break;
|
||||
}
|
||||
case PrefetchDescriptor::Type::None:
|
||||
return;
|
||||
case PrefetchDescriptor::Type::MaskTemporal: {
|
||||
PrefetchSlot::prefetch_mask<system::cache::L2, system::cache::read>(resource, prefetch_data);
|
||||
break;
|
||||
}
|
||||
case PrefetchDescriptor::Type::MaskNonTemporal: {
|
||||
PrefetchSlot::prefetch_mask<system::cache::NTA, system::cache::read>(resource, prefetch_data);
|
||||
break;
|
||||
}
|
||||
case PrefetchDescriptor::Type::MaskWrite: {
|
||||
PrefetchSlot::prefetch_mask<system::cache::ALL, system::cache::write>(resource, prefetch_data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->_item = PrefetchItem{};
|
||||
}
|
||||
197
repos/ealanos/src/lib/mx/tasking/prefetch_slot.d
Normal file
197
repos/ealanos/src/lib/mx/tasking/prefetch_slot.d
Normal file
@@ -0,0 +1,197 @@
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.o /home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.d: \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.cpp \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/ecpp/static_vector.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/compare \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/ecpp/static_vector.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/compare:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h:
|
||||
924
repos/ealanos/src/lib/mx/tasking/prefetch_slot.h
Normal file
924
repos/ealanos/src/lib/mx/tasking/prefetch_slot.h
Normal file
@@ -0,0 +1,924 @@
|
||||
#pragma once
|
||||
#include "task.h"
|
||||
#include <ealanos/util/ecpp/static_vector.h>
|
||||
#include <mx/system/cache.h>
|
||||
#include <utility>
|
||||
|
||||
namespace mx::tasking {
|
||||
class PrefetchItem
|
||||
{
|
||||
public:
|
||||
constexpr PrefetchItem() noexcept = default;
|
||||
|
||||
~PrefetchItem() noexcept = default;
|
||||
|
||||
PrefetchItem &operator=(PrefetchItem &&) noexcept = default;
|
||||
|
||||
[[nodiscard]] bool has_resource() const noexcept
|
||||
{
|
||||
return _resource != nullptr && _prefetch_descriptor.empty() == false;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::int64_t *resource() const noexcept { return _resource; }
|
||||
[[nodiscard]] PrefetchDescriptor prefetch_descriptor() const noexcept { return _prefetch_descriptor; }
|
||||
|
||||
void resource(std::int64_t *resource, PrefetchDescriptor descriptor) noexcept
|
||||
{
|
||||
_resource = resource;
|
||||
_prefetch_descriptor = descriptor;
|
||||
}
|
||||
|
||||
private:
|
||||
std::int64_t *_resource{nullptr};
|
||||
PrefetchDescriptor _prefetch_descriptor{};
|
||||
};
|
||||
|
||||
template <std::uint8_t S> class PrefetchMaskExecutor
|
||||
{
|
||||
public:
|
||||
template <std::uint8_t N> static constexpr bool is_prefetch_cl()
|
||||
{
|
||||
constexpr auto MASK = 0b1 << N;
|
||||
return (S & MASK) == MASK;
|
||||
}
|
||||
|
||||
template <system::cache::level L, system::cache::access A>
|
||||
static void execute([[maybe_unused]] const std::int64_t *address, [[maybe_unused]] const std::uint8_t word_offset)
|
||||
{
|
||||
if constexpr (is_prefetch_cl<0U>())
|
||||
{
|
||||
const auto *addr = address + (word_offset * 8U);
|
||||
system::cache::prefetch<L, A, 1U>(addr);
|
||||
}
|
||||
|
||||
if constexpr (is_prefetch_cl<1U>())
|
||||
{
|
||||
const auto *addr = address + ((word_offset + 1U) * 8U);
|
||||
system::cache::prefetch<L, A, 1U>(addr);
|
||||
}
|
||||
|
||||
if constexpr (is_prefetch_cl<2U>())
|
||||
{
|
||||
const auto *addr = address + ((word_offset + 2U) * 8U);
|
||||
system::cache::prefetch<L, A, 1U>(addr);
|
||||
}
|
||||
|
||||
if constexpr (is_prefetch_cl<3U>())
|
||||
{
|
||||
const auto *addr = address + ((word_offset + 3U) * 8U);
|
||||
system::cache::prefetch<L, A, 1U>(addr);
|
||||
}
|
||||
|
||||
if constexpr (is_prefetch_cl<4U>())
|
||||
{
|
||||
const auto *addr = address + ((word_offset + 4U) * 8U);
|
||||
system::cache::prefetch<L, A, 1U>(addr);
|
||||
}
|
||||
|
||||
if constexpr (is_prefetch_cl<5U>())
|
||||
{
|
||||
const auto *addr = address + ((word_offset + 5U) * 8U);
|
||||
system::cache::prefetch<L, A, 1U>(addr);
|
||||
}
|
||||
|
||||
if constexpr (is_prefetch_cl<6U>())
|
||||
{
|
||||
const auto *addr = address + ((word_offset + 6U) * 8U);
|
||||
system::cache::prefetch<L, A, 1U>(addr);
|
||||
}
|
||||
|
||||
if constexpr (is_prefetch_cl<7U>())
|
||||
{
|
||||
const auto *addr = address + ((word_offset + 7U) * 8U);
|
||||
system::cache::prefetch<L, A, 1U>(addr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A prefetch slot is part of the prefetch buffer used for task
|
||||
* and resource prefetching
|
||||
* A slot can contain up to one task and one resource that are
|
||||
* prefetched by the channel.
|
||||
*/
|
||||
class PrefetchSlot
|
||||
{
|
||||
public:
|
||||
constexpr PrefetchSlot() noexcept = default;
|
||||
~PrefetchSlot() = default;
|
||||
|
||||
void assign(resource::ptr resource, PrefetchDescriptor descriptor) noexcept;
|
||||
void prefetch() noexcept;
|
||||
|
||||
private:
|
||||
PrefetchItem _item;
|
||||
|
||||
template <system::cache::level L, system::cache::access A>
|
||||
static void prefetch_mask(const std::int64_t *address, const PrefetchDescriptor::data_t prefetch_mask) noexcept
|
||||
{
|
||||
PrefetchSlot::prefetch_word_at_offset<L, A, 0U>(address, prefetch_mask);
|
||||
PrefetchSlot::prefetch_word_at_offset<L, A, 1U>(address, prefetch_mask);
|
||||
PrefetchSlot::prefetch_word_at_offset<L, A, 2U>(address, prefetch_mask);
|
||||
PrefetchSlot::prefetch_word_at_offset<L, A, 3U>(address, prefetch_mask);
|
||||
PrefetchSlot::prefetch_word_at_offset<L, A, 4U>(address, prefetch_mask);
|
||||
PrefetchSlot::prefetch_word_at_offset<L, A, 5U>(address, prefetch_mask);
|
||||
PrefetchSlot::prefetch_word_at_offset<L, A, 6U>(address, prefetch_mask);
|
||||
PrefetchSlot::prefetch_word_at_offset<L, A, 7U>(address, prefetch_mask);
|
||||
}
|
||||
|
||||
template <system::cache::level L, system::cache::access A, std::uint8_t O>
|
||||
static void prefetch_word_at_offset(const std::int64_t *address, const PrefetchDescriptor::data_t mask)
|
||||
{
|
||||
if constexpr (O == 0U)
|
||||
{
|
||||
const auto prefetch_word = std::uint8_t(mask & std::numeric_limits<std::uint8_t>::max());
|
||||
PrefetchSlot::prefetch_word<L, A>(address, prefetch_word, 0U);
|
||||
}
|
||||
else
|
||||
{
|
||||
constexpr auto offset = O * 8U;
|
||||
const auto prefetch_word = std::uint8_t((mask >> offset) & std::numeric_limits<std::uint8_t>::max());
|
||||
if (prefetch_word > 0U)
|
||||
{
|
||||
PrefetchSlot::prefetch_word<L, A>(address, prefetch_word, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <system::cache::level L, system::cache::access A>
|
||||
static void prefetch_word(const std::int64_t *address, const std::uint8_t word, const std::uint8_t word_offset)
|
||||
{
|
||||
switch (word)
|
||||
{
|
||||
case 0:
|
||||
return;
|
||||
case 1:
|
||||
PrefetchMaskExecutor<1>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 2:
|
||||
PrefetchMaskExecutor<2>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 3:
|
||||
PrefetchMaskExecutor<3>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 4:
|
||||
PrefetchMaskExecutor<4>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 5:
|
||||
PrefetchMaskExecutor<5>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 6:
|
||||
PrefetchMaskExecutor<6>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 7:
|
||||
PrefetchMaskExecutor<7>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 8:
|
||||
PrefetchMaskExecutor<8>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 9:
|
||||
PrefetchMaskExecutor<9>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 10:
|
||||
PrefetchMaskExecutor<10>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 11:
|
||||
PrefetchMaskExecutor<11>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 12:
|
||||
PrefetchMaskExecutor<12>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 13:
|
||||
PrefetchMaskExecutor<13>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 14:
|
||||
PrefetchMaskExecutor<14>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 15:
|
||||
PrefetchMaskExecutor<15>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 16:
|
||||
PrefetchMaskExecutor<16>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 17:
|
||||
PrefetchMaskExecutor<17>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 18:
|
||||
PrefetchMaskExecutor<18>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 19:
|
||||
PrefetchMaskExecutor<19>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 20:
|
||||
PrefetchMaskExecutor<20>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 21:
|
||||
PrefetchMaskExecutor<21>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 22:
|
||||
PrefetchMaskExecutor<22>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 23:
|
||||
PrefetchMaskExecutor<23>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 24:
|
||||
PrefetchMaskExecutor<24>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 25:
|
||||
PrefetchMaskExecutor<25>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 26:
|
||||
PrefetchMaskExecutor<26>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 27:
|
||||
PrefetchMaskExecutor<27>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 28:
|
||||
PrefetchMaskExecutor<28>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 29:
|
||||
PrefetchMaskExecutor<29>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 30:
|
||||
PrefetchMaskExecutor<30>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 31:
|
||||
PrefetchMaskExecutor<31>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 32:
|
||||
PrefetchMaskExecutor<32>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 33:
|
||||
PrefetchMaskExecutor<33>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 34:
|
||||
PrefetchMaskExecutor<34>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 35:
|
||||
PrefetchMaskExecutor<35>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 36:
|
||||
PrefetchMaskExecutor<36>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 37:
|
||||
PrefetchMaskExecutor<37>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 38:
|
||||
PrefetchMaskExecutor<38>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 39:
|
||||
PrefetchMaskExecutor<39>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 40:
|
||||
PrefetchMaskExecutor<40>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 41:
|
||||
PrefetchMaskExecutor<41>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 42:
|
||||
PrefetchMaskExecutor<42>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 43:
|
||||
PrefetchMaskExecutor<43>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 44:
|
||||
PrefetchMaskExecutor<44>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 45:
|
||||
PrefetchMaskExecutor<45>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 46:
|
||||
PrefetchMaskExecutor<46>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 47:
|
||||
PrefetchMaskExecutor<47>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 48:
|
||||
PrefetchMaskExecutor<48>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 49:
|
||||
PrefetchMaskExecutor<49>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 50:
|
||||
PrefetchMaskExecutor<50>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 51:
|
||||
PrefetchMaskExecutor<51>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 52:
|
||||
PrefetchMaskExecutor<52>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 53:
|
||||
PrefetchMaskExecutor<53>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 54:
|
||||
PrefetchMaskExecutor<54>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 55:
|
||||
PrefetchMaskExecutor<55>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 56:
|
||||
PrefetchMaskExecutor<56>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 57:
|
||||
PrefetchMaskExecutor<57>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 58:
|
||||
PrefetchMaskExecutor<58>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 59:
|
||||
PrefetchMaskExecutor<59>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 60:
|
||||
PrefetchMaskExecutor<60>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 61:
|
||||
PrefetchMaskExecutor<61>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 62:
|
||||
PrefetchMaskExecutor<62>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 63:
|
||||
PrefetchMaskExecutor<63>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 64:
|
||||
PrefetchMaskExecutor<64>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 65:
|
||||
PrefetchMaskExecutor<65>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 66:
|
||||
PrefetchMaskExecutor<66>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 67:
|
||||
PrefetchMaskExecutor<67>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 68:
|
||||
PrefetchMaskExecutor<68>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 69:
|
||||
PrefetchMaskExecutor<69>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 70:
|
||||
PrefetchMaskExecutor<70>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 71:
|
||||
PrefetchMaskExecutor<71>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 72:
|
||||
PrefetchMaskExecutor<72>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 73:
|
||||
PrefetchMaskExecutor<73>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 74:
|
||||
PrefetchMaskExecutor<74>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 75:
|
||||
PrefetchMaskExecutor<75>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 76:
|
||||
PrefetchMaskExecutor<76>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 77:
|
||||
PrefetchMaskExecutor<77>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 78:
|
||||
PrefetchMaskExecutor<78>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 79:
|
||||
PrefetchMaskExecutor<79>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 80:
|
||||
PrefetchMaskExecutor<80>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 81:
|
||||
PrefetchMaskExecutor<81>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 82:
|
||||
PrefetchMaskExecutor<82>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 83:
|
||||
PrefetchMaskExecutor<83>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 84:
|
||||
PrefetchMaskExecutor<84>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 85:
|
||||
PrefetchMaskExecutor<85>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 86:
|
||||
PrefetchMaskExecutor<86>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 87:
|
||||
PrefetchMaskExecutor<87>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 88:
|
||||
PrefetchMaskExecutor<88>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 89:
|
||||
PrefetchMaskExecutor<89>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 90:
|
||||
PrefetchMaskExecutor<90>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 91:
|
||||
PrefetchMaskExecutor<91>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 92:
|
||||
PrefetchMaskExecutor<92>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 93:
|
||||
PrefetchMaskExecutor<93>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 94:
|
||||
PrefetchMaskExecutor<94>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 95:
|
||||
PrefetchMaskExecutor<95>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 96:
|
||||
PrefetchMaskExecutor<96>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 97:
|
||||
PrefetchMaskExecutor<97>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 98:
|
||||
PrefetchMaskExecutor<98>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 99:
|
||||
PrefetchMaskExecutor<99>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 100:
|
||||
PrefetchMaskExecutor<100>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 101:
|
||||
PrefetchMaskExecutor<101>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 102:
|
||||
PrefetchMaskExecutor<102>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 103:
|
||||
PrefetchMaskExecutor<103>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 104:
|
||||
PrefetchMaskExecutor<104>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 105:
|
||||
PrefetchMaskExecutor<105>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 106:
|
||||
PrefetchMaskExecutor<106>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 107:
|
||||
PrefetchMaskExecutor<107>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 108:
|
||||
PrefetchMaskExecutor<108>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 109:
|
||||
PrefetchMaskExecutor<109>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 110:
|
||||
PrefetchMaskExecutor<110>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 111:
|
||||
PrefetchMaskExecutor<111>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 112:
|
||||
PrefetchMaskExecutor<112>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 113:
|
||||
PrefetchMaskExecutor<113>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 114:
|
||||
PrefetchMaskExecutor<114>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 115:
|
||||
PrefetchMaskExecutor<115>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 116:
|
||||
PrefetchMaskExecutor<116>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 117:
|
||||
PrefetchMaskExecutor<117>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 118:
|
||||
PrefetchMaskExecutor<118>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 119:
|
||||
PrefetchMaskExecutor<119>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 120:
|
||||
PrefetchMaskExecutor<120>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 121:
|
||||
PrefetchMaskExecutor<121>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 122:
|
||||
PrefetchMaskExecutor<122>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 123:
|
||||
PrefetchMaskExecutor<123>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 124:
|
||||
PrefetchMaskExecutor<124>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 125:
|
||||
PrefetchMaskExecutor<125>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 126:
|
||||
PrefetchMaskExecutor<126>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 127:
|
||||
PrefetchMaskExecutor<127>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 128:
|
||||
PrefetchMaskExecutor<128>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 129:
|
||||
PrefetchMaskExecutor<129>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 130:
|
||||
PrefetchMaskExecutor<130>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 131:
|
||||
PrefetchMaskExecutor<131>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 132:
|
||||
PrefetchMaskExecutor<132>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 133:
|
||||
PrefetchMaskExecutor<133>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 134:
|
||||
PrefetchMaskExecutor<134>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 135:
|
||||
PrefetchMaskExecutor<135>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 136:
|
||||
PrefetchMaskExecutor<136>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 137:
|
||||
PrefetchMaskExecutor<137>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 138:
|
||||
PrefetchMaskExecutor<138>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 139:
|
||||
PrefetchMaskExecutor<139>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 140:
|
||||
PrefetchMaskExecutor<140>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 141:
|
||||
PrefetchMaskExecutor<141>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 142:
|
||||
PrefetchMaskExecutor<142>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 143:
|
||||
PrefetchMaskExecutor<143>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 144:
|
||||
PrefetchMaskExecutor<144>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 145:
|
||||
PrefetchMaskExecutor<145>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 146:
|
||||
PrefetchMaskExecutor<146>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 147:
|
||||
PrefetchMaskExecutor<147>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 148:
|
||||
PrefetchMaskExecutor<148>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 149:
|
||||
PrefetchMaskExecutor<149>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 150:
|
||||
PrefetchMaskExecutor<150>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 151:
|
||||
PrefetchMaskExecutor<151>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 152:
|
||||
PrefetchMaskExecutor<152>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 153:
|
||||
PrefetchMaskExecutor<153>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 154:
|
||||
PrefetchMaskExecutor<154>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 155:
|
||||
PrefetchMaskExecutor<155>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 156:
|
||||
PrefetchMaskExecutor<156>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 157:
|
||||
PrefetchMaskExecutor<157>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 158:
|
||||
PrefetchMaskExecutor<158>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 159:
|
||||
PrefetchMaskExecutor<159>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 160:
|
||||
PrefetchMaskExecutor<160>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 161:
|
||||
PrefetchMaskExecutor<161>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 162:
|
||||
PrefetchMaskExecutor<162>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 163:
|
||||
PrefetchMaskExecutor<163>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 164:
|
||||
PrefetchMaskExecutor<164>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 165:
|
||||
PrefetchMaskExecutor<165>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 166:
|
||||
PrefetchMaskExecutor<166>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 167:
|
||||
PrefetchMaskExecutor<167>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 168:
|
||||
PrefetchMaskExecutor<168>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 169:
|
||||
PrefetchMaskExecutor<169>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 170:
|
||||
PrefetchMaskExecutor<170>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 171:
|
||||
PrefetchMaskExecutor<171>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 172:
|
||||
PrefetchMaskExecutor<172>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 173:
|
||||
PrefetchMaskExecutor<173>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 174:
|
||||
PrefetchMaskExecutor<174>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 175:
|
||||
PrefetchMaskExecutor<175>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 176:
|
||||
PrefetchMaskExecutor<176>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 177:
|
||||
PrefetchMaskExecutor<177>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 178:
|
||||
PrefetchMaskExecutor<178>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 179:
|
||||
PrefetchMaskExecutor<179>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 180:
|
||||
PrefetchMaskExecutor<180>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 181:
|
||||
PrefetchMaskExecutor<181>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 182:
|
||||
PrefetchMaskExecutor<182>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 183:
|
||||
PrefetchMaskExecutor<183>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 184:
|
||||
PrefetchMaskExecutor<184>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 185:
|
||||
PrefetchMaskExecutor<185>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 186:
|
||||
PrefetchMaskExecutor<186>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 187:
|
||||
PrefetchMaskExecutor<187>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 188:
|
||||
PrefetchMaskExecutor<188>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 189:
|
||||
PrefetchMaskExecutor<189>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 190:
|
||||
PrefetchMaskExecutor<190>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 191:
|
||||
PrefetchMaskExecutor<191>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 192:
|
||||
PrefetchMaskExecutor<192>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 193:
|
||||
PrefetchMaskExecutor<193>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 194:
|
||||
PrefetchMaskExecutor<194>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 195:
|
||||
PrefetchMaskExecutor<195>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 196:
|
||||
PrefetchMaskExecutor<196>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 197:
|
||||
PrefetchMaskExecutor<197>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 198:
|
||||
PrefetchMaskExecutor<198>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 199:
|
||||
PrefetchMaskExecutor<199>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 200:
|
||||
PrefetchMaskExecutor<200>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 201:
|
||||
PrefetchMaskExecutor<201>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 202:
|
||||
PrefetchMaskExecutor<202>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 203:
|
||||
PrefetchMaskExecutor<203>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 204:
|
||||
PrefetchMaskExecutor<204>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 205:
|
||||
PrefetchMaskExecutor<205>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 206:
|
||||
PrefetchMaskExecutor<206>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 207:
|
||||
PrefetchMaskExecutor<207>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 208:
|
||||
PrefetchMaskExecutor<208>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 209:
|
||||
PrefetchMaskExecutor<209>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 210:
|
||||
PrefetchMaskExecutor<210>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 211:
|
||||
PrefetchMaskExecutor<211>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 212:
|
||||
PrefetchMaskExecutor<212>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 213:
|
||||
PrefetchMaskExecutor<213>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 214:
|
||||
PrefetchMaskExecutor<214>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 215:
|
||||
PrefetchMaskExecutor<215>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 216:
|
||||
PrefetchMaskExecutor<216>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 217:
|
||||
PrefetchMaskExecutor<217>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 218:
|
||||
PrefetchMaskExecutor<218>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 219:
|
||||
PrefetchMaskExecutor<219>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 220:
|
||||
PrefetchMaskExecutor<220>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 221:
|
||||
PrefetchMaskExecutor<221>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 222:
|
||||
PrefetchMaskExecutor<222>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 223:
|
||||
PrefetchMaskExecutor<223>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 224:
|
||||
PrefetchMaskExecutor<224>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 225:
|
||||
PrefetchMaskExecutor<225>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 226:
|
||||
PrefetchMaskExecutor<226>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 227:
|
||||
PrefetchMaskExecutor<227>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 228:
|
||||
PrefetchMaskExecutor<228>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 229:
|
||||
PrefetchMaskExecutor<229>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 230:
|
||||
PrefetchMaskExecutor<230>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 231:
|
||||
PrefetchMaskExecutor<231>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 232:
|
||||
PrefetchMaskExecutor<232>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 233:
|
||||
PrefetchMaskExecutor<233>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 234:
|
||||
PrefetchMaskExecutor<234>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 235:
|
||||
PrefetchMaskExecutor<235>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 236:
|
||||
PrefetchMaskExecutor<236>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 237:
|
||||
PrefetchMaskExecutor<237>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 238:
|
||||
PrefetchMaskExecutor<238>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 239:
|
||||
PrefetchMaskExecutor<239>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 240:
|
||||
PrefetchMaskExecutor<240>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 241:
|
||||
PrefetchMaskExecutor<241>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 242:
|
||||
PrefetchMaskExecutor<242>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 243:
|
||||
PrefetchMaskExecutor<243>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 244:
|
||||
PrefetchMaskExecutor<244>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 245:
|
||||
PrefetchMaskExecutor<245>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 246:
|
||||
PrefetchMaskExecutor<246>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 247:
|
||||
PrefetchMaskExecutor<247>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 248:
|
||||
PrefetchMaskExecutor<248>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 249:
|
||||
PrefetchMaskExecutor<249>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 250:
|
||||
PrefetchMaskExecutor<250>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 251:
|
||||
PrefetchMaskExecutor<251>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 252:
|
||||
PrefetchMaskExecutor<252>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 253:
|
||||
PrefetchMaskExecutor<253>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 254:
|
||||
PrefetchMaskExecutor<254>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
case 255:
|
||||
PrefetchMaskExecutor<255>::execute<L, A>(address, word_offset);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mx::tasking
|
||||
11
repos/ealanos/src/lib/mx/tasking/priority.h
Normal file
11
repos/ealanos/src/lib/mx/tasking/priority.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace mx::tasking {
|
||||
enum priority : std::uint8_t
|
||||
{
|
||||
low = 0U,
|
||||
normal = 1U
|
||||
};
|
||||
}
|
||||
110
repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.cpp
Normal file
110
repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#include "idle_profiler.h"
|
||||
#include <mx/memory/global_heap.h>
|
||||
#include <mx/tasking/runtime.h>
|
||||
|
||||
using namespace mx::tasking::profiling;
|
||||
|
||||
IdleProfileTask::IdleProfileTask(util::maybe_atomic<bool> &is_running) : _is_profiler_running(is_running)
|
||||
{
|
||||
_idle_ranges.reserve(1U << 16U);
|
||||
}
|
||||
|
||||
mx::tasking::TaskResult IdleProfileTask::execute(const std::uint16_t /*worker_id*/)
|
||||
{
|
||||
this->_is_task_running = true;
|
||||
|
||||
auto range = TimeRange{};
|
||||
|
||||
// while (this->_is_profiler_running && this->_channel.empty())
|
||||
// {
|
||||
// this->_channel.fill();
|
||||
// }
|
||||
|
||||
range.stop();
|
||||
|
||||
if (range.nanoseconds() > 10U)
|
||||
{
|
||||
this->_idle_ranges.emplace_back(std::move(range));
|
||||
}
|
||||
|
||||
this->_is_task_running = false;
|
||||
|
||||
if (this->_is_profiler_running)
|
||||
{
|
||||
return tasking::TaskResult::make_succeed(this);
|
||||
}
|
||||
|
||||
return tasking::TaskResult::make_null();
|
||||
}
|
||||
|
||||
IdleProfiler::~IdleProfiler()
|
||||
{
|
||||
for (auto *task : this->_tasks)
|
||||
{
|
||||
delete task;
|
||||
}
|
||||
}
|
||||
|
||||
void IdleProfiler::start() noexcept
|
||||
{
|
||||
if (this->_is_running)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto *task : this->_tasks)
|
||||
{
|
||||
delete task;
|
||||
}
|
||||
this->_tasks.clear();
|
||||
|
||||
this->_start = std::chrono::steady_clock::now();
|
||||
this->_is_running = true;
|
||||
}
|
||||
|
||||
// void IdleProfiler::start() noexcept
|
||||
//{
|
||||
//// auto *task = new (memory::GlobalHeap::allocate_cache_line_aligned(sizeof(IdleProfileTask)))
|
||||
//// IdleProfileTask(this->_is_running);
|
||||
//// task->annotate(channel.id());
|
||||
//// task->annotate(mx::tasking::priority::low);
|
||||
//// this->_tasks.push_back(task);
|
||||
//// mx::tasking::runtime::spawn(*task);
|
||||
//}
|
||||
|
||||
IdleTimes IdleProfiler::stop() noexcept
|
||||
{
|
||||
this->_is_running = false;
|
||||
const auto end = std::chrono::steady_clock::now();
|
||||
const auto start = this->_start;
|
||||
|
||||
auto idle_ranges = std::vector<std::vector<NormalizedTimeRange>>{};
|
||||
idle_ranges.reserve(mx::tasking::runtime::workers());
|
||||
|
||||
for (auto *task : this->_tasks)
|
||||
{
|
||||
if (task == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wait for the task to finish.
|
||||
// while(channel_task->is_running());
|
||||
|
||||
if (task->idle_ranges().empty() == false)
|
||||
{
|
||||
// const auto &idle_range = task->idle_ranges();
|
||||
// auto normalized_range = std::vector<NormalizedTimeRange>{};
|
||||
// std::transform(idle_range.begin(), idle_range.end(), std::back_inserter(normalized_range),
|
||||
// [start](const auto &time_range) { return time_range.normalize(start); });
|
||||
//
|
||||
// idle_ranges.emplace_back(std::move(normalized_range));
|
||||
}
|
||||
else
|
||||
{
|
||||
idle_ranges.emplace_back(std::vector<NormalizedTimeRange>{});
|
||||
}
|
||||
}
|
||||
|
||||
return IdleTimes{std::move(idle_ranges), end - start};
|
||||
}
|
||||
641
repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.d
Normal file
641
repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.d
Normal file
@@ -0,0 +1,641 @@
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.o /home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.d: \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.cpp \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646 \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/maybe_atomic.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp \
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h \
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/runtime.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_distance.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/scheduler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/shared_task_queue.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/bound_mpmc.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/priority_queue.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_squad.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/mpsc.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/worker.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/load.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_counter.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/aligned_t.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_buffer.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/ecpp/static_vector.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/compare \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_cycle_sampler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_map.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_hash.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_growth_policy.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/climits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ratio \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_execution_time_history.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool_occupancy.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/annotation.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_queues.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/core_set.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/set \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/server.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/config.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/fixed_size_allocator.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/task_allocator_interface.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/builder.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/thread.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/pthread.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/logger.h \
|
||||
/home/mml/genode-igb/repos/libports/include/libc/component.h
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/maybe_atomic.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/runtime.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_distance.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/scheduler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/shared_task_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/bound_mpmc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/priority_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_squad.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/mpsc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/worker.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/load.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_counter.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/aligned_t.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_buffer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/ecpp/static_vector.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/compare:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_cycle_sampler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_map.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_hash.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_growth_policy.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/climits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ratio:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_execution_time_history.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool_occupancy.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/annotation.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_queues.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/core_set.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/set:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/server.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/config.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/fixed_size_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/task_allocator_interface.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/builder.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/thread.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/pthread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/logger.h:
|
||||
|
||||
/home/mml/genode-igb/repos/libports/include/libc/component.h:
|
||||
71
repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.h
Normal file
71
repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include "time.h"
|
||||
#include <chrono>
|
||||
#include <mx/tasking/task.h>
|
||||
#include <mx/util/maybe_atomic.h>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace mx::tasking::profiling {
|
||||
|
||||
/**
|
||||
* Task, that is scheduled with low priority and gets CPU time,
|
||||
* whenever no other task is available.
|
||||
* Every time the task gets executed, it will record the time range,
|
||||
* until the channel has new tasks for execution.
|
||||
*/
|
||||
class IdleProfileTask final : public TaskInterface
|
||||
{
|
||||
public:
|
||||
IdleProfileTask(util::maybe_atomic<bool> &is_running);
|
||||
~IdleProfileTask() override = default;
|
||||
|
||||
TaskResult execute(std::uint16_t worker_id) override;
|
||||
|
||||
[[nodiscard]] std::vector<TimeRange> &idle_ranges() noexcept { return _idle_ranges; }
|
||||
|
||||
[[nodiscard]] bool is_running() const noexcept { return _is_task_running; }
|
||||
|
||||
private:
|
||||
util::maybe_atomic<bool> &_is_profiler_running;
|
||||
util::maybe_atomic<bool> _is_task_running{false};
|
||||
std::vector<TimeRange> _idle_ranges;
|
||||
};
|
||||
|
||||
/**
|
||||
* Schedules the idle/profiling task to every channel and
|
||||
* writes the memory to a given file.
|
||||
*/
|
||||
class IdleProfiler
|
||||
{
|
||||
public:
|
||||
IdleProfiler() noexcept = default;
|
||||
~IdleProfiler();
|
||||
|
||||
/**
|
||||
* Enable profiling and set the result file.
|
||||
* @param profiling_output_file File, where results should be written to.
|
||||
*/
|
||||
void start() noexcept;
|
||||
|
||||
/**
|
||||
* Normalizes all time ranges and writes them to the specified
|
||||
* file.
|
||||
*/
|
||||
IdleTimes stop() noexcept;
|
||||
|
||||
[[nodiscard]] bool is_running() const noexcept { return _is_running; }
|
||||
|
||||
private:
|
||||
util::maybe_atomic<bool> _is_running{false};
|
||||
|
||||
// Time point of the runtime start.
|
||||
alignas(64) std::chrono::steady_clock::time_point _start;
|
||||
|
||||
// List of all idle/profile tasks.
|
||||
std::vector<IdleProfileTask *> _tasks;
|
||||
};
|
||||
|
||||
} // namespace mx::tasking::profiling
|
||||
171
repos/ealanos/src/lib/mx/tasking/profiling/task_counter.h
Normal file
171
repos/ealanos/src/lib/mx/tasking/profiling/task_counter.h
Normal file
@@ -0,0 +1,171 @@
|
||||
#pragma once
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <mx/memory/global_heap.h>
|
||||
#include <mx/tasking/config.h>
|
||||
#include <mx/util/aligned_t.h>
|
||||
#include <numeric>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace mx::tasking::profiling {
|
||||
|
||||
class WorkerTaskCounter
|
||||
{
|
||||
public:
|
||||
WorkerTaskCounter() noexcept = default;
|
||||
|
||||
explicit WorkerTaskCounter(const std::uint16_t count_workers) noexcept { _counter.resize(count_workers, 0U); }
|
||||
|
||||
WorkerTaskCounter(WorkerTaskCounter &&) noexcept = default;
|
||||
WorkerTaskCounter(const WorkerTaskCounter &) noexcept = default;
|
||||
|
||||
~WorkerTaskCounter() noexcept = default;
|
||||
|
||||
WorkerTaskCounter &operator=(WorkerTaskCounter &&) noexcept = default;
|
||||
|
||||
std::uint64_t operator[](const std::size_t index) const noexcept { return _counter[index]; }
|
||||
std::uint64_t &operator[](const std::size_t index) noexcept { return _counter[index]; }
|
||||
|
||||
[[nodiscard]] std::uint64_t sum() const noexcept { return std::accumulate(_counter.begin(), _counter.end(), 0U); }
|
||||
|
||||
[[nodiscard]] std::uint16_t size() const noexcept { return _counter.size(); }
|
||||
|
||||
WorkerTaskCounter operator-(const WorkerTaskCounter &other) const noexcept
|
||||
{
|
||||
auto counter = this->_counter;
|
||||
|
||||
for (auto worker_id = 0U; worker_id < counter.size(); ++worker_id)
|
||||
{
|
||||
counter[worker_id] -= other[worker_id];
|
||||
}
|
||||
|
||||
return WorkerTaskCounter{std::move(counter)};
|
||||
}
|
||||
|
||||
WorkerTaskCounter &operator-=(const WorkerTaskCounter &other) noexcept
|
||||
{
|
||||
for (auto worker_id = 0U; worker_id < _counter.size(); ++worker_id)
|
||||
{
|
||||
_counter[worker_id] -= other[worker_id];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit WorkerTaskCounter(std::vector<std::uint64_t> &&counter) noexcept : _counter(std::move(counter)) {}
|
||||
|
||||
std::vector<std::uint64_t> _counter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Collector for tasking statistics (scheduled tasks, executed tasks, ...).
|
||||
*/
|
||||
class TaskCounter
|
||||
{
|
||||
public:
|
||||
using counter_line_t = util::aligned_t<std::array<std::uint64_t, 7U>>;
|
||||
|
||||
enum Counter : std::uint8_t
|
||||
{
|
||||
Dispatched,
|
||||
DispatchedLocally,
|
||||
DispatchedRemotely,
|
||||
Executed,
|
||||
ExecutedReader,
|
||||
ExecutedWriter,
|
||||
FilledBuffer
|
||||
};
|
||||
|
||||
explicit TaskCounter(const std::uint16_t count_workers) noexcept : _count_workers(count_workers)
|
||||
{
|
||||
_counter = new (memory::GlobalHeap::allocate_cache_line_aligned(sizeof(counter_line_t) * count_workers))
|
||||
counter_line_t[count_workers];
|
||||
clear();
|
||||
}
|
||||
|
||||
TaskCounter(const TaskCounter &) = delete;
|
||||
|
||||
TaskCounter(TaskCounter &&other) noexcept
|
||||
: _count_workers(other._count_workers), _counter(std::exchange(other._counter, nullptr))
|
||||
{
|
||||
}
|
||||
|
||||
~TaskCounter() noexcept { delete[] this->_counter; }
|
||||
|
||||
TaskCounter &operator=(const TaskCounter &) = delete;
|
||||
|
||||
/**
|
||||
* Clears all collected statistics.
|
||||
*/
|
||||
void clear() noexcept { std::memset(static_cast<void *>(_counter), 0, sizeof(counter_line_t) * _count_workers); }
|
||||
|
||||
/**
|
||||
* Increment the template-given counter by one for the given channel.
|
||||
* @param worker_id Worker to increment the statistics for.
|
||||
*/
|
||||
template <Counter C> void increment(const std::uint16_t worker_id) noexcept
|
||||
{
|
||||
++_counter[worker_id].value()[static_cast<std::uint8_t>(C)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the given counter for a given channel.
|
||||
* @param counter Counter to read.
|
||||
* @param worker_id Worker the counter is for.
|
||||
* @return Value of the counter.
|
||||
*/
|
||||
[[nodiscard]] std::uint64_t get(const Counter counter, const std::uint16_t worker_id) const noexcept
|
||||
{
|
||||
return _counter[worker_id].value()[static_cast<std::uint8_t>(counter)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and aggregate the counter for all channels.
|
||||
* @param counter Counter to read.
|
||||
* @return Value of the counter for all channels.
|
||||
*/
|
||||
[[nodiscard]] WorkerTaskCounter get(const Counter counter) const noexcept
|
||||
{
|
||||
auto worker_counter = WorkerTaskCounter{_count_workers};
|
||||
for (auto i = 0U; i < _count_workers; ++i)
|
||||
{
|
||||
worker_counter[i] = get(counter, i);
|
||||
}
|
||||
|
||||
return worker_counter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read counter for all channels.
|
||||
*
|
||||
* @return List of channel counter for every counter.
|
||||
*/
|
||||
[[nodiscard]] std::unordered_map<Counter, WorkerTaskCounter> get() const noexcept
|
||||
{
|
||||
auto counter = std::unordered_map<Counter, WorkerTaskCounter>{};
|
||||
counter.reserve(7U);
|
||||
|
||||
counter.insert(std::make_pair(Counter::Dispatched, get(Counter::Dispatched)));
|
||||
counter.insert(std::make_pair(Counter::DispatchedLocally, get(Counter::DispatchedLocally)));
|
||||
counter.insert(std::make_pair(Counter::DispatchedRemotely, get(Counter::DispatchedRemotely)));
|
||||
counter.insert(std::make_pair(Counter::Executed, get(Counter::Executed)));
|
||||
counter.insert(std::make_pair(Counter::ExecutedReader, get(Counter::ExecutedReader)));
|
||||
counter.insert(std::make_pair(Counter::ExecutedWriter, get(Counter::ExecutedWriter)));
|
||||
counter.insert(std::make_pair(Counter::FilledBuffer, get(Counter::FilledBuffer)));
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
private:
|
||||
// Number of channels to monitor.
|
||||
const std::uint16_t _count_workers;
|
||||
|
||||
// Memory for storing the counter.
|
||||
counter_line_t *_counter{nullptr};
|
||||
};
|
||||
|
||||
} // namespace mx::tasking::profiling
|
||||
150
repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.cpp
Normal file
150
repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
#include "task_tracer.h"
|
||||
|
||||
using namespace mx::tasking::profiling;
|
||||
|
||||
TaskTraces TaskTracer::stop()
|
||||
{
|
||||
_is_enabled = false;
|
||||
|
||||
auto traces = std::vector<std::vector<std::pair<std::uint64_t, NormalizedTimeRange>>>{};
|
||||
traces.reserve(this->_worker_task_tracers.size());
|
||||
|
||||
const auto start = this->_start;
|
||||
for (auto &channel_tracer : this->_worker_task_tracers)
|
||||
{
|
||||
/// Get list of traces from channel tracer.
|
||||
const auto &channel_traces = channel_tracer.traces();
|
||||
|
||||
/// Create a single list containing all traces from that channel.
|
||||
auto &channel_normalized_traces =
|
||||
traces.emplace_back(std::vector<std::pair<std::uint64_t, NormalizedTimeRange>>{});
|
||||
channel_normalized_traces.reserve(channel_traces.size() * WorkerTaskTracer::SIZE);
|
||||
|
||||
/// Flatten the list of lists into a normalized list.
|
||||
for (const auto &trace_list : channel_traces)
|
||||
{
|
||||
std::transform(trace_list.begin(), trace_list.end(), std::back_inserter(channel_normalized_traces),
|
||||
[start](const auto &trace) {
|
||||
return std::make_pair(std::get<0>(trace), std::get<1>(trace).normalize(start));
|
||||
});
|
||||
}
|
||||
|
||||
/// Clear the channel tracer.
|
||||
channel_tracer.clear();
|
||||
}
|
||||
|
||||
auto task_traces = TaskTraces{this->_start.time_since_epoch(), this->_task_trace_ids, std::move(traces)};
|
||||
this->_task_trace_ids.clear();
|
||||
return task_traces;
|
||||
}
|
||||
|
||||
nlohmann::json TaskTraces::to_json() const
|
||||
{
|
||||
auto task_times = std::unordered_map<std::uint64_t, std::uint64_t>{};
|
||||
|
||||
auto traces = nlohmann::json{};
|
||||
traces["start"] = this->_start_timestamp.count();
|
||||
traces["tasks"] = nlohmann::json{};
|
||||
|
||||
/// If not found, add the "unknown" tasks for all tasks without trace id.
|
||||
if (this->_names.find(0U) == this->_names.end())
|
||||
{
|
||||
traces["tasks"].emplace_back(nlohmann::json{{"id", 0U}, {"name", "Unknown"}});
|
||||
task_times.insert(std::make_pair(0U, 0U));
|
||||
}
|
||||
|
||||
/// Add the registered tasks.
|
||||
for (const auto &[task_id, name] : this->_names)
|
||||
{
|
||||
traces["tasks"].emplace_back(nlohmann::json{{"id", task_id}, {"name", name}});
|
||||
task_times.insert(std::make_pair(task_id, 0U));
|
||||
}
|
||||
|
||||
/// Calculate traces per channel.
|
||||
traces["traces"] = nlohmann::json{};
|
||||
for (const auto &worker : this->_traces)
|
||||
{
|
||||
auto channel_traces = nlohmann::json{};
|
||||
for (const auto &trace : worker)
|
||||
{
|
||||
const auto task_id = std::get<0>(trace);
|
||||
const auto start = std::get<1>(trace).start().count();
|
||||
const auto end = std::get<1>(trace).end().count();
|
||||
|
||||
auto task = nlohmann::json{};
|
||||
task["tid"] = task_id;
|
||||
task["s"] = start;
|
||||
task["e"] = end;
|
||||
channel_traces.emplace_back(std::move(task));
|
||||
|
||||
auto task_times_iterator = task_times.find(task_id);
|
||||
if (task_times_iterator != task_times.end()) [[likely]]
|
||||
{
|
||||
task_times_iterator->second += end - start;
|
||||
}
|
||||
else
|
||||
{
|
||||
task_times.insert(std::make_pair(task_id, end - start));
|
||||
}
|
||||
}
|
||||
traces["traces"].emplace_back(std::move(channel_traces));
|
||||
}
|
||||
|
||||
/// Aggregate sums for every task type.
|
||||
const auto count_worker = this->_traces.size();
|
||||
for (auto &task : traces["tasks"])
|
||||
{
|
||||
if (task.contains("id"))
|
||||
{
|
||||
const auto task_id = task["id"].get<std::uint64_t>();
|
||||
auto task_iterator = task_times.find(task_id);
|
||||
if (task_iterator != task_times.end())
|
||||
{
|
||||
const auto time_ms = double(task_iterator->second) / 1000000.0;
|
||||
task["ms"] = time_ms;
|
||||
task["ms_per_worker"] = time_ms / count_worker;
|
||||
}
|
||||
else
|
||||
{
|
||||
task["ms"] = double(0);
|
||||
task["ms_per_worker"] = double(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate idle times.
|
||||
auto min_ns = std::numeric_limits<std::uint64_t>::max();
|
||||
auto max_ns = std::numeric_limits<std::uint64_t>::min();
|
||||
for (const auto &channel : this->_traces)
|
||||
{
|
||||
if (channel.empty() == false)
|
||||
{
|
||||
min_ns = std::min<std::uint64_t>(min_ns, channel.front().second.start().count());
|
||||
max_ns = std::max<std::uint64_t>(max_ns, channel.back().second.end().count());
|
||||
}
|
||||
}
|
||||
|
||||
const auto runtime_ns = (max_ns - min_ns) * count_worker;
|
||||
const auto runtime_ms = runtime_ns / 1000000.0;
|
||||
const auto task_time_ns = std::accumulate(task_times.begin(), task_times.end(), double(0),
|
||||
[](const auto sum, const auto &time) { return sum + time.second; });
|
||||
const auto idle_ms = double(runtime_ns - task_time_ns) / 1000000.0;
|
||||
traces["ms_idle"] = idle_ms;
|
||||
traces["ms_idle_per_worker"] = idle_ms / count_worker;
|
||||
|
||||
/// Calculate task percent.
|
||||
traces["percent_idle"] = 100.0 / runtime_ms * (idle_ms / count_worker);
|
||||
for (auto &task : traces["tasks"])
|
||||
{
|
||||
if (task.contains("ms_per_worker"))
|
||||
{
|
||||
task["percent"] = 100.0 / runtime_ms * task["ms_per_worker"].get<float>();
|
||||
}
|
||||
else
|
||||
{
|
||||
task["percent"] = double(0);
|
||||
}
|
||||
}
|
||||
|
||||
return traces;
|
||||
}
|
||||
161
repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.d
Normal file
161
repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.d
Normal file
@@ -0,0 +1,161 @@
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.o /home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.d: \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.cpp \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646 \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional:
|
||||
141
repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h
Normal file
141
repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h
Normal file
@@ -0,0 +1,141 @@
|
||||
#pragma once
|
||||
|
||||
#include "time.h"
|
||||
#include <cstdlib>
|
||||
#include <mx/system/cache.h>
|
||||
#include <ealanos/util/json.hpp>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace mx::tasking::profiling {
|
||||
class alignas(system::cache::line_size()) WorkerTaskTracer
|
||||
{
|
||||
public:
|
||||
constexpr static auto inline SIZE = 1U << 16U;
|
||||
|
||||
WorkerTaskTracer() = default;
|
||||
WorkerTaskTracer(WorkerTaskTracer &&) noexcept = default;
|
||||
WorkerTaskTracer(const WorkerTaskTracer &) = delete;
|
||||
|
||||
WorkerTaskTracer &operator=(WorkerTaskTracer &&) noexcept = default;
|
||||
WorkerTaskTracer &operator=(const WorkerTaskTracer &) = delete;
|
||||
|
||||
~WorkerTaskTracer() = default;
|
||||
|
||||
void emplace_back(const std::uint64_t task_id, TimeRange &&time_range)
|
||||
{
|
||||
_traces.back().emplace_back(std::make_pair(task_id, std::move(time_range)));
|
||||
|
||||
if (_traces.back().size() >= _traces.back().capacity() - 1U) [[unlikely]]
|
||||
{
|
||||
_traces.emplace_back(std::vector<std::pair<std::uint64_t, TimeRange>>{});
|
||||
_traces.back().reserve(SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::vector<std::pair<std::uint64_t, TimeRange>>> &traces() const noexcept
|
||||
{
|
||||
return _traces;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
_traces.clear();
|
||||
_traces.reserve(1U << 5U);
|
||||
_traces.emplace_back(std::vector<std::pair<std::uint64_t, TimeRange>>{});
|
||||
_traces.back().reserve(SIZE);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::vector<std::pair<std::uint64_t, TimeRange>>> _traces;
|
||||
};
|
||||
|
||||
class TaskTraces
|
||||
{
|
||||
public:
|
||||
TaskTraces(const std::chrono::nanoseconds start_timestamp,
|
||||
const std::unordered_map<std::uint64_t, std::string> &names,
|
||||
std::vector<std::vector<std::pair<std::uint64_t, NormalizedTimeRange>>> &&traces) noexcept
|
||||
: _start_timestamp(start_timestamp), _names(names), _traces(std::move(traces))
|
||||
{
|
||||
}
|
||||
|
||||
TaskTraces() = default;
|
||||
|
||||
TaskTraces(TaskTraces &&) noexcept = default;
|
||||
|
||||
~TaskTraces() = default;
|
||||
|
||||
[[nodiscard]] const std::unordered_map<std::uint64_t, std::string> &names() const noexcept { return _names; }
|
||||
[[nodiscard]] const std::vector<std::vector<std::pair<std::uint64_t, NormalizedTimeRange>>> &traces() const noexcept
|
||||
{
|
||||
return _traces;
|
||||
}
|
||||
|
||||
[[nodiscard]] nlohmann::json to_json() const;
|
||||
|
||||
private:
|
||||
std::chrono::nanoseconds _start_timestamp;
|
||||
std::unordered_map<std::uint64_t, std::string> _names;
|
||||
std::vector<std::vector<std::pair<std::uint64_t, NormalizedTimeRange>>> _traces;
|
||||
};
|
||||
|
||||
class TaskTracer
|
||||
{
|
||||
public:
|
||||
TaskTracer(const std::uint16_t count_workers)
|
||||
{
|
||||
_worker_task_tracers.resize(count_workers);
|
||||
_task_trace_ids.reserve(1024U);
|
||||
}
|
||||
|
||||
TaskTracer(TaskTracer &&) noexcept = default;
|
||||
|
||||
~TaskTracer() = default;
|
||||
|
||||
void register_task(const std::uint64_t task_id, std::string &&name)
|
||||
{
|
||||
_task_trace_ids.insert_or_assign(task_id, std::move(name));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<std::string> get(const std::uint64_t task_id) const noexcept
|
||||
{
|
||||
if (auto iterator = _task_trace_ids.find(task_id); iterator != _task_trace_ids.end())
|
||||
{
|
||||
return iterator->second;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void emplace_back(const std::uint16_t worker_id, const std::uint64_t task_id, TimeRange &&time_range)
|
||||
{
|
||||
if (_is_enabled)
|
||||
{
|
||||
_worker_task_tracers[worker_id].emplace_back(task_id, std::move(time_range));
|
||||
}
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
_start = std::chrono::system_clock::now();
|
||||
|
||||
for (auto &worker_tracer : _worker_task_tracers)
|
||||
{
|
||||
worker_tracer.clear();
|
||||
}
|
||||
|
||||
_is_enabled = true;
|
||||
}
|
||||
|
||||
[[nodiscard]] TaskTraces stop();
|
||||
|
||||
private:
|
||||
bool _is_enabled{false};
|
||||
std::chrono::system_clock::time_point _start;
|
||||
std::vector<WorkerTaskTracer> _worker_task_tracers;
|
||||
std::unordered_map<std::uint64_t, std::string> _task_trace_ids;
|
||||
};
|
||||
} // namespace mx::tasking::profiling
|
||||
69
repos/ealanos/src/lib/mx/tasking/profiling/time.cpp
Normal file
69
repos/ealanos/src/lib/mx/tasking/profiling/time.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "time.h"
|
||||
|
||||
using namespace mx::tasking::profiling;
|
||||
|
||||
WorkerIdleFrames IdleTimes::group(const std::chrono::nanoseconds frame_size) const noexcept
|
||||
{
|
||||
const auto count_frames = std::size_t(_duration / frame_size) + 1U;
|
||||
|
||||
auto idle_frames = std::vector<std::vector<std::chrono::nanoseconds>>{};
|
||||
idle_frames.reserve(this->channels());
|
||||
|
||||
for (auto worker_id = 0U; worker_id < this->channels(); ++worker_id)
|
||||
{
|
||||
auto frames = std::vector<std::chrono::nanoseconds>{count_frames, std::chrono::nanoseconds{0U}};
|
||||
|
||||
for (const auto &time_range : this->_idle_ranges[worker_id])
|
||||
{
|
||||
const auto start_frame_id = time_range.start() / frame_size;
|
||||
const auto end_frame_id = time_range.end() / frame_size;
|
||||
if (start_frame_id == end_frame_id)
|
||||
{
|
||||
frames[start_frame_id] += time_range.duration();
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Append to start.
|
||||
const auto start_frame_end = (start_frame_id + 1U) * frame_size;
|
||||
frames[start_frame_id] += start_frame_end - time_range.start();
|
||||
|
||||
/// Append to end.
|
||||
const auto end_frame_start = end_frame_id * frame_size;
|
||||
frames[end_frame_id] += (time_range.end() - end_frame_start) + std::chrono::nanoseconds(1U);
|
||||
|
||||
/// Fill frames between.
|
||||
for (auto frame_id = start_frame_id + 1U; frame_id <= end_frame_id - 1U; ++frame_id)
|
||||
{
|
||||
frames[frame_id] += frame_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idle_frames.emplace_back(std::move(frames));
|
||||
}
|
||||
|
||||
return WorkerIdleFrames{std::move(idle_frames), this->_duration, frame_size};
|
||||
}
|
||||
|
||||
nlohmann::json WorkerIdleFrames::to_json() const noexcept
|
||||
{
|
||||
nlohmann::json idle_times;
|
||||
idle_times["duration"] = this->_duration.count();
|
||||
idle_times["frame-size"] = this->_frame_size.count();
|
||||
idle_times["count-channels"] = this->channels();
|
||||
idle_times["count-frames"] = this->_idle_frames.front().size();
|
||||
|
||||
nlohmann::json channels;
|
||||
for (const auto &channel_frames : this->_idle_frames)
|
||||
{
|
||||
nlohmann::json channel;
|
||||
for (const auto frame : channel_frames)
|
||||
{
|
||||
channel.emplace_back(frame.count());
|
||||
}
|
||||
channels.emplace_back(std::move(channel));
|
||||
}
|
||||
idle_times["channels"] = std::move(channels);
|
||||
|
||||
return idle_times;
|
||||
}
|
||||
110
repos/ealanos/src/lib/mx/tasking/profiling/time.d
Normal file
110
repos/ealanos/src/lib/mx/tasking/profiling/time.d
Normal file
@@ -0,0 +1,110 @@
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.o /home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.d: \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.cpp \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646 \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream:
|
||||
131
repos/ealanos/src/lib/mx/tasking/profiling/time.h
Normal file
131
repos/ealanos/src/lib/mx/tasking/profiling/time.h
Normal file
@@ -0,0 +1,131 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <ealanos/util/json.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace mx::tasking::profiling {
|
||||
class NormalizedTimeRange
|
||||
{
|
||||
public:
|
||||
constexpr NormalizedTimeRange(const std::chrono::nanoseconds start, const std::chrono::nanoseconds end) noexcept
|
||||
: _start(start), _end(end)
|
||||
{
|
||||
}
|
||||
|
||||
NormalizedTimeRange(NormalizedTimeRange &&) noexcept = default;
|
||||
|
||||
~NormalizedTimeRange() noexcept = default;
|
||||
|
||||
[[nodiscard]] std::chrono::nanoseconds start() const noexcept { return _start; }
|
||||
[[nodiscard]] std::chrono::nanoseconds end() const noexcept { return _end; }
|
||||
[[nodiscard]] std::chrono::nanoseconds duration() const noexcept { return _end - _start; }
|
||||
|
||||
private:
|
||||
std::chrono::nanoseconds _start;
|
||||
std::chrono::nanoseconds _end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Time range (from -- to) for idled time of a single channel.
|
||||
*/
|
||||
class TimeRange
|
||||
{
|
||||
public:
|
||||
TimeRange() noexcept : _start(std::chrono::system_clock::now()) {}
|
||||
constexpr explicit TimeRange(const std::chrono::system_clock::time_point start) noexcept : _start(start) {}
|
||||
constexpr TimeRange(const std::chrono::system_clock::time_point start,
|
||||
const std::chrono::system_clock::time_point end) noexcept
|
||||
: _start(start), _end(end)
|
||||
{
|
||||
}
|
||||
constexpr TimeRange(TimeRange &&) noexcept = default;
|
||||
~TimeRange() = default;
|
||||
|
||||
/**
|
||||
* Sets the end of the idle range to the current time.
|
||||
*/
|
||||
void stop() noexcept { _end = std::chrono::system_clock::now(); }
|
||||
|
||||
/**
|
||||
* @return Number of nanoseconds idled.
|
||||
*/
|
||||
[[nodiscard]] std::uint64_t nanoseconds() const noexcept
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(_end - _start).count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes this range with respect to a given point in time.
|
||||
* @param global_start Point in time to normalize.
|
||||
* @return Pair of (start, stop) normalized to the given time point.
|
||||
*/
|
||||
[[nodiscard]] NormalizedTimeRange normalize(const std::chrono::system_clock::time_point global_start) const noexcept
|
||||
{
|
||||
return NormalizedTimeRange{std::max(_start, global_start) - global_start, _end - global_start};
|
||||
}
|
||||
|
||||
private:
|
||||
// Start of idling.
|
||||
std::chrono::system_clock::time_point _start;
|
||||
|
||||
// End of idling.
|
||||
std::chrono::system_clock::time_point _end;
|
||||
};
|
||||
|
||||
class WorkerIdleFrames
|
||||
{
|
||||
public:
|
||||
WorkerIdleFrames(std::vector<std::vector<std::chrono::nanoseconds>> &&idle_frames,
|
||||
const std::chrono::nanoseconds duration, const std::chrono::nanoseconds frame_size) noexcept
|
||||
: _duration(duration), _frame_size(frame_size), _idle_frames(std::move(idle_frames))
|
||||
{
|
||||
}
|
||||
|
||||
WorkerIdleFrames(WorkerIdleFrames &&) noexcept = default;
|
||||
|
||||
~WorkerIdleFrames() noexcept = default;
|
||||
|
||||
[[nodiscard]] std::chrono::nanoseconds duration() const noexcept { return _duration; }
|
||||
[[nodiscard]] std::chrono::nanoseconds frame_size() const noexcept { return _frame_size; }
|
||||
[[nodiscard]] std::uint16_t channels() const noexcept { return _idle_frames.size(); }
|
||||
[[nodiscard]] const std::vector<std::vector<std::chrono::nanoseconds>> &idle_frames() const noexcept
|
||||
{
|
||||
return _idle_frames;
|
||||
}
|
||||
[[nodiscard]] nlohmann::json to_json() const noexcept;
|
||||
|
||||
private:
|
||||
const std::chrono::nanoseconds _duration;
|
||||
const std::chrono::nanoseconds _frame_size;
|
||||
std::vector<std::vector<std::chrono::nanoseconds>> _idle_frames;
|
||||
};
|
||||
|
||||
class IdleTimes
|
||||
{
|
||||
public:
|
||||
IdleTimes(std::vector<std::vector<NormalizedTimeRange>> &&idle_ranges,
|
||||
const std::chrono::nanoseconds duration) noexcept
|
||||
: _duration(duration), _idle_ranges(std::move(idle_ranges))
|
||||
{
|
||||
}
|
||||
|
||||
IdleTimes(IdleTimes &&) noexcept = default;
|
||||
|
||||
~IdleTimes() noexcept = default;
|
||||
|
||||
[[nodiscard]] std::chrono::nanoseconds duration() const noexcept { return _duration; }
|
||||
[[nodiscard]] std::uint16_t channels() const noexcept { return _idle_ranges.size(); }
|
||||
[[nodiscard]] const std::vector<std::vector<NormalizedTimeRange>> &idle_ranges() const noexcept
|
||||
{
|
||||
return _idle_ranges;
|
||||
}
|
||||
|
||||
[[nodiscard]] WorkerIdleFrames group(std::chrono::nanoseconds frame_size) const noexcept;
|
||||
|
||||
private:
|
||||
const std::chrono::nanoseconds _duration;
|
||||
std::vector<std::vector<NormalizedTimeRange>> _idle_ranges;
|
||||
};
|
||||
} // namespace mx::tasking::profiling
|
||||
567
repos/ealanos/src/lib/mx/tasking/runtime.h
Normal file
567
repos/ealanos/src/lib/mx/tasking/runtime.h
Normal file
@@ -0,0 +1,567 @@
|
||||
#pragma once
|
||||
#include "ealanos/memory/hamstraaja.h"
|
||||
#include "prefetch_distance.h"
|
||||
#include "scheduler.h"
|
||||
#include "task.h"
|
||||
#include "task_squad.h"
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mx/io/network/server.h>
|
||||
#include <mx/memory/fixed_size_allocator.h>
|
||||
#include <mx/memory/task_allocator_interface.h>
|
||||
#include <mx/memory/worker_local_dynamic_size_allocator.h>
|
||||
#include <mx/resource/annotation.h>
|
||||
#include <mx/resource/builder.h>
|
||||
#include <mx/system/environment.h>
|
||||
#include <mx/system/thread.h>
|
||||
#include <mx/util/core_set.h>
|
||||
#include <mx/util/logger.h>
|
||||
#include <utility>
|
||||
#include <libc/component.h>
|
||||
|
||||
namespace mx::tasking {
|
||||
/**
|
||||
* The runtime is the central access structure to MxTasking.
|
||||
* Here, we can initialize MxTasking, spawn and allocate tasks, allocate
|
||||
* data objects.
|
||||
*/
|
||||
class runtime
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initializes the MxTasking runtime.
|
||||
*
|
||||
* @param core_set Cores, where the runtime should execute on.
|
||||
* @param prefetch_distance Distance for prefetching.
|
||||
* @param channels_per_core Number of channels per core (more than one enables channel-stealing).
|
||||
* @param use_system_allocator Should we use the systems malloc interface or our allocator?
|
||||
* @return True, when the runtime was started successfully.
|
||||
*/
|
||||
static bool init(const util::core_set &core_set, const PrefetchDistance prefetch_distance,
|
||||
const bool use_system_allocator, Libc::Env& env)
|
||||
{
|
||||
util::Logger::info_if(system::Environment::is_debug(), "Starting MxTasking in DEBUG mode.");
|
||||
util::Logger::warn_if(system::Environment::is_debug() == false && config::is_use_task_counter(),
|
||||
"Task statistics will be collected in RELEASE build.");
|
||||
util::Logger::warn_if(system::Environment::is_debug() == false && config::is_collect_task_traces(),
|
||||
"Task traces will be collected in RELEASE build.");
|
||||
util::Logger::warn_if(system::Environment::is_debug() == false &&
|
||||
config::worker_mode() == config::worker_mode::PowerSave,
|
||||
"Power safe mode activated in RELEASE build.");
|
||||
|
||||
if (!memory::GlobalHeap::initialized()) {
|
||||
memory::GlobalHeap::init(new Ealan::Memory::Hamstraaja<memory::config::min_block_size(), memory::config::superblock_cutoff()>(env.pd(), env.rm()));
|
||||
}
|
||||
|
||||
// Are we ready to re-initialize the scheduler?
|
||||
if (_scheduler != nullptr && _scheduler->is_running())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// The starting thread operates as worker#0.
|
||||
_worker_id = 0U;
|
||||
|
||||
// Create a new resource allocator.
|
||||
if (_resource_allocator == nullptr)
|
||||
{
|
||||
/// Only called the first time.
|
||||
_resource_allocator.reset(new (memory::GlobalHeap::allocate_cache_line_aligned(
|
||||
sizeof(memory::dynamic::local::Allocator))) memory::dynamic::local::Allocator(core_set));
|
||||
}
|
||||
else if (_resource_allocator->is_free())
|
||||
{
|
||||
/// The application cleared the whole memory, but
|
||||
/// we won't re-allocate the allocator to keep references
|
||||
/// that are given to the resource builder and epoch manager
|
||||
/// since the scheduler does not change.
|
||||
_resource_allocator->reset(core_set, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
/// The application holds allocated memory.
|
||||
_resource_allocator->reset(core_set, false);
|
||||
}
|
||||
|
||||
// Create a new task allocator.
|
||||
if (use_system_allocator)
|
||||
{
|
||||
_task_allocator.reset(new (memory::GlobalHeap::allocate_cache_line_aligned(sizeof(
|
||||
memory::SystemTaskAllocator<config::task_size()>))) memory::SystemTaskAllocator<config::task_size()>());
|
||||
}
|
||||
else
|
||||
{
|
||||
_task_allocator.reset(new (
|
||||
memory::GlobalHeap::allocate_cache_line_aligned(sizeof(memory::fixed::Allocator<config::task_size()>)))
|
||||
memory::fixed::Allocator<config::task_size()>(util::core_set::build()));
|
||||
}
|
||||
|
||||
// Create a new scheduler.
|
||||
const auto need_new_scheduler = _scheduler == nullptr || *_scheduler != core_set;
|
||||
if (need_new_scheduler)
|
||||
{
|
||||
_scheduler.reset(new (memory::GlobalHeap::allocate_cache_line_aligned(sizeof(Scheduler)))
|
||||
Scheduler(core_set, prefetch_distance, *_resource_allocator));
|
||||
}
|
||||
else
|
||||
{
|
||||
_scheduler->reset();
|
||||
}
|
||||
|
||||
// Create a new resource builder.
|
||||
if (_resource_builder == nullptr || need_new_scheduler)
|
||||
{
|
||||
_resource_builder = std::make_unique<mx::resource::Builder>(*_scheduler, *_resource_allocator);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns the given task.
|
||||
*
|
||||
* @param task Task to be scheduled.
|
||||
* @param local_worker_id Worker, the spawn request came from.
|
||||
*/
|
||||
static std::uint16_t spawn(TaskInterface &task, const std::uint16_t local_worker_id) noexcept
|
||||
{
|
||||
return _scheduler->dispatch(task, local_worker_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns the given task.
|
||||
*
|
||||
* @param task Task to be scheduled.
|
||||
*/
|
||||
static void spawn(TaskInterface &task) noexcept { _scheduler->dispatch(task, _worker_id); }
|
||||
|
||||
/**
|
||||
* Spawns a list of concatenated tasks.
|
||||
*
|
||||
* @param first_task First task of the list to be scheduled.
|
||||
* @param last_task Last task of the list to be scheduled.
|
||||
* @param local_worker_id Worker, the spawn request came from.
|
||||
*/
|
||||
static void spawn(TaskInterface &first_task, TaskInterface &last_task, const std::uint16_t local_worker_id) noexcept
|
||||
{
|
||||
_scheduler->dispatch(first_task, last_task, local_worker_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns the given squad.
|
||||
*
|
||||
* @param squad Squad to be scheduled.
|
||||
* @param local_worker_id Worker, the spawn request came from.
|
||||
*/
|
||||
static std::uint16_t spawn(const mx::resource::ptr squad, const std::uint16_t local_worker_id) noexcept
|
||||
{
|
||||
return spawn(squad, annotation::resource_boundness::mixed, local_worker_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns the given squad.
|
||||
*
|
||||
* @param squad Squad to be scheduled.
|
||||
* @param boundness Boundness of the squad.
|
||||
* @param local_worker_id Worker, the spawn request came from.
|
||||
*/
|
||||
static std::uint16_t spawn(const mx::resource::ptr squad, const enum annotation::resource_boundness boundness,
|
||||
const std::uint16_t local_worker_id) noexcept
|
||||
{
|
||||
return _scheduler->dispatch(squad, boundness, local_worker_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Number of available cores.
|
||||
*/
|
||||
[[nodiscard]] static std::uint16_t workers() noexcept { return _scheduler->count_cores(); }
|
||||
|
||||
/**
|
||||
* @return Prefetch distance.
|
||||
*/
|
||||
static PrefetchDistance prefetch_distance() noexcept { return _scheduler->prefetch_distance(); }
|
||||
|
||||
/**
|
||||
* Starts the runtime and suspends the starting thread until MxTasking is stopped.
|
||||
*/
|
||||
static void start_and_wait() { _scheduler->start_and_wait(); }
|
||||
|
||||
/**
|
||||
* Instructs all worker threads to stop their work.
|
||||
* After all worker threads are stopped, the starting
|
||||
* thread will be resumed.
|
||||
*
|
||||
* @param stop_network If set to true, the network server will also be stopped.
|
||||
*/
|
||||
static void stop(const bool stop_network = true) noexcept
|
||||
{
|
||||
_scheduler->interrupt();
|
||||
if (_network_server != nullptr && stop_network)
|
||||
{
|
||||
_network_server->stop();
|
||||
_network_server_thread->join();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new task.
|
||||
*
|
||||
* @param worker_id Worker to allocate memory from.
|
||||
* @param arguments Arguments for the task.
|
||||
* @return The new task.
|
||||
*/
|
||||
template <typename T, typename... Args> static T *new_task(const std::uint16_t worker_id, Args &&...arguments)
|
||||
{
|
||||
static_assert(sizeof(T) <= config::task_size() && "Task must be <= defined task size.");
|
||||
return new (_task_allocator->allocate(worker_id)) T(std::forward<Args>(arguments)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees a given task.
|
||||
*
|
||||
* @param worker_id Worker id to return the memory to.
|
||||
* @param task Task to be freed.
|
||||
*/
|
||||
template <typename T> static void delete_task(const std::uint16_t worker_id, T *task) noexcept
|
||||
{
|
||||
task->~T();
|
||||
_task_allocator->free(worker_id, static_cast<void *>(task));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a resource.
|
||||
*
|
||||
* @param size Size of the data object.
|
||||
* @param annotation Annotation for allocation and scheduling.
|
||||
* @param arguments Arguments for the data object.
|
||||
* @return The resource pointer.
|
||||
*/
|
||||
template <typename T, typename... Args>
|
||||
static mx::resource::ptr new_resource(const std::size_t size, mx::resource::annotation &&annotation,
|
||||
Args &&...arguments) noexcept
|
||||
{
|
||||
return _resource_builder->build<T>(_worker_id, size, std::move(annotation), std::forward<Args>(arguments)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a resource from a given pointer.
|
||||
*
|
||||
* @param object Pointer to the existing object.
|
||||
* @param annotation Annotation for allocation and scheduling.
|
||||
* @return The resource pointer.
|
||||
*/
|
||||
template <typename T>
|
||||
static mx::resource::ptr to_resource(T *object, mx::resource::annotation &&annotation) noexcept
|
||||
{
|
||||
return _resource_builder->build<T>(object, annotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given data object.
|
||||
*
|
||||
* @param resource Data object to be deleted.
|
||||
*/
|
||||
template <typename T> static void delete_resource(const mx::resource::ptr resource) noexcept
|
||||
{
|
||||
_resource_builder->destroy<T>(_worker_id, resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new task squad.
|
||||
*
|
||||
* @param size Size of the task squad object.
|
||||
* @param worker_id Worker to map the squad to.
|
||||
* @param arguments Arguments for the task squad object.
|
||||
* @return A resource pointer to the squad.
|
||||
*/
|
||||
template <typename T, typename... Args>
|
||||
static mx::resource::ptr new_squad(const std::size_t size, const std::uint16_t worker_id,
|
||||
Args &&...arguments) noexcept
|
||||
{
|
||||
static_assert(std::is_base_of<TaskSquad, T>::value && "Squads needs to extend mx::tasking::TaskSquad");
|
||||
|
||||
auto annotation = resource::annotation{worker_id, synchronization::isolation_level::Exclusive,
|
||||
synchronization::protocol::Batched};
|
||||
return _resource_builder->build<T>(_worker_id, size, std::move(annotation), std::forward<Args>(arguments)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the given task squad.
|
||||
*/
|
||||
static void flush_squad(resource::ptr task_squad) noexcept { task_squad.get<TaskSquad>()->flush(); }
|
||||
|
||||
/**
|
||||
* Creates a simple task squad.
|
||||
*
|
||||
* @param worker_id Worker to map the squad to.
|
||||
* @return A resource pointer to the squad.
|
||||
*/
|
||||
static mx::resource::ptr new_squad(const std::uint16_t worker_id) noexcept
|
||||
{
|
||||
auto annotation = resource::annotation{worker_id, synchronization::isolation_level::Exclusive,
|
||||
synchronization::protocol::Batched};
|
||||
return _resource_builder->build<TaskSquad>(_worker_id, sizeof(TaskSquad), std::move(annotation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given data squad.
|
||||
*
|
||||
* @param resource Squad to be deleted.
|
||||
*/
|
||||
template <typename T> static void delete_squad(const mx::resource::ptr resource) noexcept
|
||||
{
|
||||
_resource_builder->destroy<T>(_worker_id, resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates memory from the worker-local heap.
|
||||
*
|
||||
* @param numa_node_id NUMA node id where to allocate memory from.
|
||||
* @param alignment Alighment of the allocation.
|
||||
* @param size Size to allocate.
|
||||
* @return Pointer to the allocated memory.
|
||||
*/
|
||||
static void *allocate(const std::uint8_t numa_node_id, const std::size_t alignment, const std::size_t size) noexcept
|
||||
{
|
||||
return _resource_allocator->allocate(_worker_id, numa_node_id, alignment, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees a region allocated from the worker-local heap.
|
||||
*
|
||||
* @param pointer Pointer to memory.
|
||||
*/
|
||||
static void free(void *pointer) noexcept { _resource_allocator->free(_worker_id, pointer); }
|
||||
|
||||
/**
|
||||
* Spawns a task for every worker thread to release the free memory.
|
||||
*/
|
||||
static void defragment()
|
||||
{
|
||||
const auto local_worker_id = _worker_id;
|
||||
for (auto worker_id = std::uint16_t(0U); worker_id < workers(); ++worker_id)
|
||||
{
|
||||
auto *clean_up_task =
|
||||
new_task<memory::dynamic::local::CleanUpMemoryTask>(local_worker_id, *_resource_allocator);
|
||||
clean_up_task->annotate(worker_id);
|
||||
spawn(*clean_up_task, local_worker_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the prediction of a data object.
|
||||
*
|
||||
* @param resource Data object, whose usage should be predicted.
|
||||
* @param old_prediction Prediction so far.
|
||||
* @param new_prediction New usage prediction.
|
||||
*/
|
||||
static void modify_predicted_usage(const mx::resource::ptr resource,
|
||||
const mx::resource::expected_access_frequency old_prediction,
|
||||
const mx::resource::expected_access_frequency new_prediction) noexcept
|
||||
{
|
||||
_scheduler->modify_predicted_usage(resource.worker_id(), old_prediction, new_prediction);
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the NUMA region of a worker.
|
||||
* @param worker_id Worker.
|
||||
* @return ID of the NUMA region.
|
||||
*/
|
||||
static std::uint8_t numa_node_id(const std::uint16_t worker_id) noexcept
|
||||
{
|
||||
return _scheduler->numa_node_id(worker_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start profiling of idle times.
|
||||
*/
|
||||
static void start_idle_profiler() noexcept { _scheduler->start_idle_profiler(); }
|
||||
|
||||
/**
|
||||
* Stops idle profiling.
|
||||
*
|
||||
* @return List of idle times for every channel.
|
||||
*/
|
||||
[[nodiscard]] static profiling::IdleTimes stop_idle_profiler() { return _scheduler->stop_idle_profiler(); }
|
||||
|
||||
/**
|
||||
* Reads the task statistics for a given counter and all channels.
|
||||
* @return List of all counters for every channel.
|
||||
*/
|
||||
static std::unordered_map<profiling::TaskCounter::Counter, profiling::WorkerTaskCounter> task_counter() noexcept
|
||||
{
|
||||
if constexpr (config::is_use_task_counter())
|
||||
{
|
||||
return _scheduler->task_counter()->get();
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::unordered_map<profiling::TaskCounter::Counter, profiling::WorkerTaskCounter>{};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the task statistics for a given counter and all channels.
|
||||
* @param counter Counter to be read.
|
||||
* @return Aggregated value of all channels.
|
||||
*/
|
||||
static profiling::WorkerTaskCounter task_counter(
|
||||
[[maybe_unused]] const profiling::TaskCounter::Counter counter) noexcept
|
||||
{
|
||||
if constexpr (config::is_use_task_counter())
|
||||
{
|
||||
return _scheduler->task_counter()->get(counter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return profiling::WorkerTaskCounter{_scheduler->core_set().count_cores()};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the task task_counter for a given counter on a given channel.
|
||||
* @param counter Counter to be read.
|
||||
* @param worker_id Worker.
|
||||
* @return Value of the counter of the given channel.
|
||||
*/
|
||||
static std::uint64_t task_counter([[maybe_unused]] const profiling::TaskCounter::Counter counter,
|
||||
[[maybe_unused]] const std::uint16_t worker_id) noexcept
|
||||
{
|
||||
if constexpr (config::is_use_task_counter())
|
||||
{
|
||||
return _scheduler->task_counter()->get(counter, worker_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
|
||||
static void register_task_for_trace([[maybe_unused]] const std::uint64_t task_id,
|
||||
[[maybe_unused]] std::string &&name)
|
||||
{
|
||||
_scheduler->task_tracer()->register_task(task_id, std::move(name));
|
||||
}
|
||||
|
||||
static std::string task_name([[maybe_unused]] const std::uint64_t task_id)
|
||||
{
|
||||
auto name = _scheduler->task_tracer()->get(task_id);
|
||||
return name.value_or(std::to_string(task_id));
|
||||
}
|
||||
|
||||
static void start_tracing()
|
||||
{
|
||||
if constexpr (config::is_collect_task_traces())
|
||||
{
|
||||
_scheduler->task_tracer()->start();
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static profiling::TaskTraces stop_tracing()
|
||||
{
|
||||
if constexpr (config::is_collect_task_traces())
|
||||
{
|
||||
return _scheduler->task_tracer()->stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
return profiling::TaskTraces{};
|
||||
}
|
||||
}
|
||||
|
||||
static void listen_on_port(std::unique_ptr<io::network::MessageHandler> &&message_handler, const std::uint16_t port)
|
||||
{
|
||||
_network_server =
|
||||
std::make_unique<io::network::Server>(std::move(message_handler), port, _scheduler->count_cores());
|
||||
_network_server_thread = std::make_unique<std::thread>([] { mx::tasking::runtime::_network_server->listen(); });
|
||||
}
|
||||
|
||||
static void send_message(const std::uint32_t client_id, std::string &&message)
|
||||
{
|
||||
_network_server->send(client_id, std::move(message));
|
||||
}
|
||||
|
||||
static bool is_listening()
|
||||
{
|
||||
if (_network_server == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _network_server->is_running();
|
||||
}
|
||||
|
||||
static void initialize_worker(const std::uint16_t worker_id)
|
||||
{
|
||||
_worker_id = worker_id;
|
||||
_resource_allocator->initialize_heap(worker_id, _scheduler->count_numa_nodes());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The id of the executing worker. May be costly, use it carefully.
|
||||
*/
|
||||
[[nodiscard]] static std::uint16_t worker_id() noexcept { return _worker_id; }
|
||||
|
||||
[[nodiscard]] static std::unordered_map<std::string, std::vector<std::pair<std::uintptr_t, std::uintptr_t>>>
|
||||
memory_tags()
|
||||
{
|
||||
auto tags = _scheduler->memory_tags();
|
||||
|
||||
for (auto &[name, ranges] : _task_allocator->allocated_chunks())
|
||||
{
|
||||
if (auto iterator = tags.find(name); iterator != tags.end())
|
||||
{
|
||||
std::move(ranges.begin(), ranges.end(), std::back_inserter(iterator->second));
|
||||
}
|
||||
else
|
||||
{
|
||||
tags.insert(std::make_pair(std::move(name), std::move(ranges)));
|
||||
}
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
private:
|
||||
inline static thread_local std::uint16_t _worker_id{std::numeric_limits<std::uint16_t>::max()};
|
||||
|
||||
// Scheduler to spawn tasks.
|
||||
inline static std::unique_ptr<Scheduler> _scheduler{nullptr};
|
||||
|
||||
// Allocator to allocate tasks (could be systems malloc or our Multi-level allocator).
|
||||
inline static std::unique_ptr<memory::TaskAllocatorInterface> _task_allocator{nullptr};
|
||||
|
||||
// Allocator to allocate resources.
|
||||
inline static std::unique_ptr<memory::dynamic::local::Allocator> _resource_allocator{nullptr};
|
||||
|
||||
// Allocator to allocate data objects.
|
||||
inline static std::unique_ptr<mx::resource::Builder> _resource_builder{nullptr};
|
||||
|
||||
// Optional network server.
|
||||
inline static std::unique_ptr<io::network::Server> _network_server{nullptr};
|
||||
inline static std::unique_ptr<std::thread> _network_server_thread{nullptr};
|
||||
};
|
||||
|
||||
/**
|
||||
* The runtime_guard initializes the runtime at initialization and starts
|
||||
* the runtime when the object is deleted. This allows MxTasking to execute
|
||||
* within a specific scope.
|
||||
*/
|
||||
class runtime_guard
|
||||
{
|
||||
public:
|
||||
runtime_guard(Libc::Env &env, const bool use_system_allocator, const util::core_set &core_set,
|
||||
const PrefetchDistance prefetch_distance = PrefetchDistance{0U}) noexcept
|
||||
{
|
||||
runtime::init(core_set, prefetch_distance, use_system_allocator, env);
|
||||
}
|
||||
|
||||
runtime_guard(Libc::Env &env, const util::core_set &core_set,
|
||||
const PrefetchDistance prefetch_distance = PrefetchDistance{0U}) noexcept
|
||||
: runtime_guard(env, false, core_set, prefetch_distance)
|
||||
{
|
||||
}
|
||||
|
||||
~runtime_guard() noexcept { runtime::start_and_wait(); }
|
||||
};
|
||||
} // namespace mx::tasking
|
||||
308
repos/ealanos/src/lib/mx/tasking/scheduler.cpp
Normal file
308
repos/ealanos/src/lib/mx/tasking/scheduler.cpp
Normal file
@@ -0,0 +1,308 @@
|
||||
#include "scheduler.h"
|
||||
#include "runtime.h"
|
||||
#include <mx/memory/global_heap.h>
|
||||
#include <mx/synchronization/synchronization.h>
|
||||
#include <mx/system/cpu.h>
|
||||
#include <mx/system/thread.h>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
using namespace mx::tasking;
|
||||
|
||||
Scheduler::Scheduler(const mx::util::core_set &core_set, const PrefetchDistance prefetch_distance,
|
||||
memory::dynamic::local::Allocator &resource_allocator) noexcept
|
||||
: _core_set(core_set), _prefetch_distance(prefetch_distance), _worker({nullptr}),
|
||||
_epoch_manager(core_set.count_cores(), resource_allocator, _is_running)
|
||||
{
|
||||
this->_worker_numa_node_map.fill(0U);
|
||||
|
||||
/// Set up profiling utilities.
|
||||
if constexpr (config::is_use_task_counter())
|
||||
{
|
||||
this->_task_counter.emplace(profiling::TaskCounter{this->_core_set.count_cores()});
|
||||
}
|
||||
if constexpr (config::is_collect_task_traces() || config::is_monitor_task_cycles_for_prefetching())
|
||||
{
|
||||
this->_task_tracer.emplace(profiling::TaskTracer{this->_core_set.count_cores()});
|
||||
}
|
||||
|
||||
/// Create worker.
|
||||
for (auto worker_id = std::uint16_t(0U); worker_id < this->_core_set.count_cores(); ++worker_id)
|
||||
{
|
||||
/// The core the worker is binded to.
|
||||
const auto core_id = this->_core_set[worker_id];
|
||||
|
||||
/// The corresponding NUMA Node.
|
||||
const auto numa_node_id = system::cpu::node_id(core_id);
|
||||
this->_worker_numa_node_map[worker_id] = numa_node_id;
|
||||
|
||||
this->_worker[worker_id] = new (memory::GlobalHeap::allocate(numa_node_id, sizeof(Worker)))
|
||||
Worker(this->_core_set.count_cores(), worker_id, core_id, this->_is_running, prefetch_distance,
|
||||
this->_epoch_manager[worker_id], this->_epoch_manager.global_epoch(), this->_task_counter,
|
||||
this->_task_tracer);
|
||||
}
|
||||
}
|
||||
|
||||
Scheduler::~Scheduler() noexcept
|
||||
{
|
||||
std::for_each(this->_worker.begin(), this->_worker.begin() + this->_core_set.count_cores(), [](auto *worker) {
|
||||
const auto numa_node_id = system::cpu::node_id(worker->core_id());
|
||||
worker->~Worker();
|
||||
memory::GlobalHeap::free(worker, sizeof(Worker), numa_node_id);
|
||||
});
|
||||
}
|
||||
|
||||
void Scheduler::start_and_wait()
|
||||
{
|
||||
// Create threads for worker...
|
||||
std::vector<std::thread> worker_threads(this->_core_set.count_cores() +
|
||||
static_cast<std::uint16_t>(config::memory_reclamation() != config::None));
|
||||
for (auto worker_id = 0U; worker_id < this->_core_set.count_cores(); ++worker_id)
|
||||
{
|
||||
auto *worker = this->_worker[worker_id];
|
||||
worker_threads[worker_id] = std::thread([worker] { worker->execute(); });
|
||||
|
||||
//system::thread::pin(worker_threads[worker_id], worker->core_id());
|
||||
//system::thread::name(worker_threads[worker_id], "mx::worker#" + std::to_string(worker_id));
|
||||
}
|
||||
|
||||
// ... and epoch management (if enabled).
|
||||
if constexpr (config::memory_reclamation() != config::None)
|
||||
{
|
||||
const auto memory_reclamation_thread_id = this->_core_set.count_cores();
|
||||
|
||||
// In case we enable memory reclamation: Use an additional thread.
|
||||
worker_threads[memory_reclamation_thread_id] =
|
||||
std::thread([this] { this->_epoch_manager.enter_epoch_periodically(); });
|
||||
|
||||
// Set name.
|
||||
//system::thread::name(worker_threads[memory_reclamation_thread_id], "mx::mem_reclam");
|
||||
}
|
||||
|
||||
// Turning the flag on starts all worker threads to execute tasks.
|
||||
this->_is_running = true;
|
||||
|
||||
// Wait for the worker threads to end. This will only
|
||||
// reached when the _is_running flag is set to false
|
||||
// from somewhere in the application.
|
||||
for (auto &worker_thread : worker_threads)
|
||||
{
|
||||
worker_thread.join();
|
||||
}
|
||||
|
||||
if constexpr (config::memory_reclamation() != config::None)
|
||||
{
|
||||
// At this point, no task will execute on any resource;
|
||||
// but the epoch manager has joined, too. Therefore,
|
||||
// we will reclaim all memory manually.
|
||||
this->_epoch_manager.reclaim_all();
|
||||
}
|
||||
}
|
||||
|
||||
std::uint16_t Scheduler::dispatch(TaskInterface &task, const std::uint16_t local_worker_id) noexcept
|
||||
{
|
||||
/// The "local_channel_id" (the id of the calling channel) may be "invalid" (=uint16_t::max).
|
||||
/// If it is not, we set the worker_id of the worker_id either by contacting the map (virtualization on)
|
||||
/// or just using the worker_id as worker_id (virtualization off).
|
||||
const auto has_local_worker_id = local_worker_id != std::numeric_limits<std::uint16_t>::max();
|
||||
|
||||
if constexpr (config::is_use_task_counter())
|
||||
{
|
||||
if (has_local_worker_id) [[likely]]
|
||||
{
|
||||
this->_task_counter->increment<profiling::TaskCounter::Dispatched>(local_worker_id);
|
||||
}
|
||||
}
|
||||
|
||||
const auto &annotation = task.annotation();
|
||||
|
||||
// Scheduling is based on the annotated resource of the given task.
|
||||
if (annotation.has_resource())
|
||||
{
|
||||
const auto annotated_resource = annotation.resource();
|
||||
auto resource_worker_id = annotated_resource.worker_id();
|
||||
|
||||
if (annotated_resource.synchronization_primitive() == synchronization::primitive::Batched)
|
||||
{
|
||||
// if (resource_worker_id == local_worker_id)
|
||||
// {
|
||||
// annotated_resource.get<TaskSquad>()->push_back_local(task);
|
||||
// return local_worker_id;
|
||||
// }
|
||||
|
||||
annotated_resource.get<TaskSquad>()->push_back_remote(task);
|
||||
return resource_worker_id;
|
||||
}
|
||||
|
||||
// For performance reasons, we prefer the local (not synchronized) queue
|
||||
// whenever possible to spawn the task. The decision is based on the
|
||||
// synchronization primitive and the access mode of the task (reader/writer).
|
||||
if (has_local_worker_id &&
|
||||
Scheduler::keep_task_local(annotation.is_readonly(), annotated_resource.synchronization_primitive()))
|
||||
{
|
||||
this->_worker[local_worker_id]->queues().push_back_local(&task);
|
||||
if constexpr (config::is_use_task_counter())
|
||||
{
|
||||
this->_task_counter->increment<profiling::TaskCounter::DispatchedLocally>(local_worker_id);
|
||||
}
|
||||
return resource_worker_id;
|
||||
}
|
||||
|
||||
if (has_local_worker_id) [[likely]]
|
||||
{
|
||||
this->_worker[resource_worker_id]->queues().push_back_remote(&task, this->numa_node_id(local_worker_id),
|
||||
local_worker_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_worker[resource_worker_id]->queues().push_back_remote(&task, system::cpu::node_id(),
|
||||
runtime::worker_id());
|
||||
}
|
||||
|
||||
if constexpr (config::is_use_task_counter())
|
||||
{
|
||||
if (has_local_worker_id) [[likely]]
|
||||
{
|
||||
this->_task_counter->increment<profiling::TaskCounter::DispatchedRemotely>(local_worker_id);
|
||||
}
|
||||
}
|
||||
return resource_worker_id;
|
||||
}
|
||||
|
||||
// The developer assigned a fixed channel to the task.
|
||||
if (annotation.has_worker_id())
|
||||
{
|
||||
const auto target_worker_id = annotation.worker_id();
|
||||
|
||||
if (has_local_worker_id)
|
||||
{
|
||||
// For performance reasons, we prefer the local (not synchronized) queue
|
||||
// whenever possible to spawn the task.
|
||||
if (local_worker_id == target_worker_id)
|
||||
{
|
||||
this->_worker[target_worker_id]->queues().push_back_local(&task);
|
||||
if constexpr (config::is_use_task_counter())
|
||||
{
|
||||
this->_task_counter->increment<profiling::TaskCounter::DispatchedLocally>(target_worker_id);
|
||||
}
|
||||
|
||||
return target_worker_id;
|
||||
}
|
||||
|
||||
this->_worker[target_worker_id]->queues().push_back_remote(&task, this->numa_node_id(local_worker_id),
|
||||
local_worker_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_worker[target_worker_id]->queues().push_back_remote(&task, system::cpu::node_id(),
|
||||
runtime::worker_id());
|
||||
}
|
||||
|
||||
if constexpr (config::is_use_task_counter())
|
||||
{
|
||||
if (has_local_worker_id) [[likely]]
|
||||
{
|
||||
this->_task_counter->increment<profiling::TaskCounter::DispatchedRemotely>(local_worker_id);
|
||||
}
|
||||
}
|
||||
|
||||
return target_worker_id;
|
||||
}
|
||||
|
||||
// The developer assigned a fixed NUMA region to the task.
|
||||
// if (annotation.has_numa_node_id())
|
||||
// {
|
||||
// this->_numa_node_queues[annotation.numa_node_id()].get(annotation.priority()).push_back(&task);
|
||||
// if constexpr (config::is_use_task_counter())
|
||||
// {
|
||||
// if (current_channel_id != std::numeric_limits<std::uint16_t>::max()) [[likely]]
|
||||
// {
|
||||
// this->_task_counter->increment<profiling::TaskCounter::DispatchedRemotely>(current_channel_id);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /// TODO: What to return?
|
||||
// return 0U;
|
||||
// }
|
||||
|
||||
// The task should be spawned on the local channel.
|
||||
if (annotation.is_locally())
|
||||
{
|
||||
if (has_local_worker_id) [[likely]]
|
||||
{
|
||||
this->_worker[local_worker_id]->queues().push_back_local(&task);
|
||||
if constexpr (config::is_use_task_counter())
|
||||
{
|
||||
this->_task_counter->increment<profiling::TaskCounter::DispatchedLocally>(local_worker_id);
|
||||
}
|
||||
|
||||
return local_worker_id;
|
||||
}
|
||||
|
||||
assert(false && "Spawn was expected to be 'locally' but no local channel was provided.");
|
||||
}
|
||||
|
||||
// The task can run everywhere.
|
||||
// this->_global_queue.get(annotation.priority()).push_back(&task);
|
||||
// if constexpr (config::is_use_task_counter())
|
||||
// {
|
||||
// if (current_channel_id != std::numeric_limits<std::uint16_t>::max()) [[likely]]
|
||||
// {
|
||||
// this->_task_counter->increment<profiling::TaskCounter::DispatchedRemotely>(current_channel_id);
|
||||
// }
|
||||
// }
|
||||
|
||||
/// TODO: What to return?
|
||||
return 0U;
|
||||
}
|
||||
|
||||
std::uint16_t Scheduler::dispatch(TaskInterface &first, TaskInterface &last, const uint16_t local_worker_id) noexcept
|
||||
{
|
||||
this->_worker[local_worker_id]->queues().push_back_local(&first, &last);
|
||||
return local_worker_id;
|
||||
}
|
||||
|
||||
std::uint16_t Scheduler::dispatch(const mx::resource::ptr squad, const enum annotation::resource_boundness boundness,
|
||||
const std::uint16_t local_worker_id) noexcept
|
||||
{
|
||||
auto *dispatch_task = runtime::new_task<TaskSquadSpawnTask>(local_worker_id, *squad.get<TaskSquad>());
|
||||
dispatch_task->annotate(squad.worker_id());
|
||||
return this->dispatch(*dispatch_task, local_worker_id);
|
||||
}
|
||||
|
||||
void Scheduler::reset() noexcept
|
||||
{
|
||||
if constexpr (config::is_use_task_counter())
|
||||
{
|
||||
this->_task_counter->clear();
|
||||
}
|
||||
|
||||
this->_epoch_manager.reset();
|
||||
}
|
||||
|
||||
void Scheduler::start_idle_profiler()
|
||||
{
|
||||
// TODO: Should we measure idle times?
|
||||
// this->_idle_profiler.start();
|
||||
// for (auto worker_id = 0U; worker_id < this->_core_set.count_cores(); ++worker_id)
|
||||
// {
|
||||
// this->_idle_profiler.start(this->_worker[worker_id]->channel());
|
||||
// }
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::vector<std::pair<std::uintptr_t, std::uintptr_t>>> Scheduler::memory_tags()
|
||||
{
|
||||
auto tags = std::unordered_map<std::string, std::vector<std::pair<std::uintptr_t, std::uintptr_t>>>{};
|
||||
|
||||
auto workers = std::vector<std::pair<std::uintptr_t, std::uintptr_t>>{};
|
||||
workers.reserve(this->_core_set.count_cores());
|
||||
for (auto worker_id = 0U; worker_id < this->_core_set.count_cores(); ++worker_id)
|
||||
{
|
||||
const auto begin = std::uintptr_t(this->_worker[worker_id]);
|
||||
const auto end = begin + sizeof(Worker);
|
||||
workers.emplace_back(std::make_pair(begin, end));
|
||||
}
|
||||
|
||||
tags.insert(std::make_pair("worker", std::move(workers)));
|
||||
return tags;
|
||||
}
|
||||
641
repos/ealanos/src/lib/mx/tasking/scheduler.d
Normal file
641
repos/ealanos/src/lib/mx/tasking/scheduler.d
Normal file
@@ -0,0 +1,641 @@
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/scheduler.o /home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/scheduler.d: \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/scheduler.cpp \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/scheduler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_distance.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/shared_task_queue.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/bound_mpmc.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646 \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp \
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h \
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/priority_queue.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_squad.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/mpsc.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/worker.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/load.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_counter.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/aligned_t.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_buffer.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/ecpp/static_vector.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/compare \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_cycle_sampler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_map.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_hash.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_growth_policy.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/climits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ratio \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_execution_time_history.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool_occupancy.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/annotation.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_queues.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/core_set.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/set \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/maybe_atomic.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/runtime.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/server.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/config.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/fixed_size_allocator.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/task_allocator_interface.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/builder.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/thread.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/pthread.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/logger.h \
|
||||
/home/mml/genode-igb/repos/libports/include/libc/component.h
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/scheduler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_distance.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/shared_task_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/bound_mpmc.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/priority_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_squad.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/mpsc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/worker.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/load.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_counter.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/aligned_t.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_buffer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/ecpp/static_vector.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/compare:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_cycle_sampler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_map.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_hash.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_growth_policy.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/climits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ratio:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_execution_time_history.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool_occupancy.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/annotation.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_queues.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/core_set.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/set:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/maybe_atomic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/runtime.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/server.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/config.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/fixed_size_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/task_allocator_interface.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/builder.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/thread.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/pthread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/logger.h:
|
||||
|
||||
/home/mml/genode-igb/repos/libports/include/libc/component.h:
|
||||
282
repos/ealanos/src/lib/mx/tasking/scheduler.h
Normal file
282
repos/ealanos/src/lib/mx/tasking/scheduler.h
Normal file
@@ -0,0 +1,282 @@
|
||||
#pragma once
|
||||
#include "prefetch_distance.h"
|
||||
#include "shared_task_queue.h"
|
||||
#include "task.h"
|
||||
#include "task_squad.h"
|
||||
#include "worker.h"
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mx/memory/config.h>
|
||||
#include <mx/memory/reclamation/epoch_manager.h>
|
||||
#include <mx/memory/worker_local_dynamic_size_allocator.h>
|
||||
#include <mx/resource/ptr.h>
|
||||
#include <mx/tasking/profiling/idle_profiler.h>
|
||||
#include <mx/tasking/profiling/task_counter.h>
|
||||
#include <mx/tasking/profiling/task_tracer.h>
|
||||
#include <mx/util/core_set.h>
|
||||
#include <mx/util/random.h>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace mx::tasking {
|
||||
/**
|
||||
* The scheduler is the central (but hidden by the runtime) data structure to spawn
|
||||
* tasks between worker threads.
|
||||
*/
|
||||
class Scheduler
|
||||
{
|
||||
public:
|
||||
Scheduler(const util::core_set &core_set, PrefetchDistance prefetch_distance,
|
||||
memory::dynamic::local::Allocator &resource_allocator) noexcept;
|
||||
~Scheduler() noexcept;
|
||||
|
||||
/**
|
||||
* Schedules a given task.
|
||||
*
|
||||
* @param task Task to be scheduled.
|
||||
* @param local_worker_id Worker, the request came from.
|
||||
* @return Worker ID where the task was dispatched to.
|
||||
*/
|
||||
std::uint16_t dispatch(TaskInterface &task, std::uint16_t local_worker_id) noexcept;
|
||||
|
||||
/**
|
||||
* Schedules a given list of tasks to the local worker.
|
||||
* The tasks have to be concatenated.
|
||||
*
|
||||
* @param first First task of the list.
|
||||
* @param last Last task of the list.
|
||||
* @param local_worker_id Worker, the request came from.
|
||||
* @return Worker ID where the task was dispatched to.
|
||||
*/
|
||||
std::uint16_t dispatch(TaskInterface &first, TaskInterface &last, std::uint16_t local_worker_id) noexcept;
|
||||
|
||||
/**
|
||||
* Schedules all tasks of a given squad.
|
||||
* @param squad Squad to be scheduled.
|
||||
* @param local_worker_id Channel, the request came from.
|
||||
* @return Worker ID where the task was dispatched to.
|
||||
*/
|
||||
std::uint16_t dispatch(mx::resource::ptr squad, enum annotation::resource_boundness boundness,
|
||||
std::uint16_t local_worker_id) noexcept;
|
||||
|
||||
/**
|
||||
* Starts all worker threads and waits until they finish.
|
||||
*/
|
||||
void start_and_wait();
|
||||
|
||||
/**
|
||||
* Interrupts the worker threads. They will finish after executing
|
||||
* their current tasks.
|
||||
*/
|
||||
void interrupt() noexcept
|
||||
{
|
||||
_is_running = false;
|
||||
if (this->_idle_profiler.is_running())
|
||||
{
|
||||
this->_idle_profiler.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Core set of this instance.
|
||||
*/
|
||||
[[nodiscard]] const util::core_set &core_set() const noexcept { return _core_set; }
|
||||
|
||||
/**
|
||||
* @return True, when the worker threads are not interrupted.
|
||||
*/
|
||||
[[nodiscard]] bool is_running() const noexcept { return _is_running; }
|
||||
|
||||
/**
|
||||
* @return The global epoch manager.
|
||||
*/
|
||||
[[nodiscard]] memory::reclamation::EpochManager &epoch_manager() noexcept { return _epoch_manager; }
|
||||
|
||||
/**
|
||||
* @return Number of all cores.
|
||||
*/
|
||||
[[nodiscard]] std::uint16_t count_cores() const noexcept { return _core_set.count_cores(); }
|
||||
|
||||
/**
|
||||
* @return Number of all numa regions.
|
||||
*/
|
||||
[[nodiscard]] std::uint8_t count_numa_nodes() const noexcept { return _core_set.numa_nodes(); }
|
||||
|
||||
/**
|
||||
* @return Prefetch distance.
|
||||
*/
|
||||
[[nodiscard]] PrefetchDistance prefetch_distance() const noexcept { return _prefetch_distance; }
|
||||
|
||||
/**
|
||||
* Reads the NUMA region of a given worker thread.
|
||||
* @param worker_id Worker.
|
||||
* @return NUMA region of the given worker.
|
||||
*/
|
||||
[[nodiscard]] std::uint8_t numa_node_id(const std::uint16_t worker_id) const noexcept
|
||||
{
|
||||
return _worker_numa_node_map[worker_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicts usage for a given channel.
|
||||
* @param worker_id Worker.
|
||||
* @param usage Usage to predict.
|
||||
*/
|
||||
void predict_usage(const std::uint16_t worker_id, const mx::resource::expected_access_frequency usage) noexcept
|
||||
{
|
||||
_worker[worker_id]->occupancy().predict(usage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the predicted usage of a channel.
|
||||
* @param worker_id Worker.
|
||||
* @param old_prediction So far predicted usage.
|
||||
* @param new_prediction New prediction.
|
||||
*/
|
||||
void modify_predicted_usage(const std::uint16_t worker_id,
|
||||
const mx::resource::expected_access_frequency old_prediction,
|
||||
const mx::resource::expected_access_frequency new_prediction) noexcept
|
||||
{
|
||||
_worker[worker_id]->occupancy().revoke(old_prediction);
|
||||
_worker[worker_id]->occupancy().predict(new_prediction);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param worker_id Worker.
|
||||
* @return True, when a least one usage was predicted to be "excessive" for the given channel.
|
||||
*/
|
||||
[[nodiscard]] bool has_excessive_usage_prediction(const std::uint16_t worker_id) const noexcept
|
||||
{
|
||||
return _worker[worker_id]->occupancy().has_excessive_usage_prediction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the statistics.
|
||||
*/
|
||||
void reset() noexcept;
|
||||
|
||||
/**
|
||||
* Starts profiling of idle times.
|
||||
*/
|
||||
void start_idle_profiler();
|
||||
|
||||
/**
|
||||
* Stops idle profiling.
|
||||
* @return List of idle times for each channel.
|
||||
*/
|
||||
[[nodiscard]] profiling::IdleTimes stop_idle_profiler() { return this->_idle_profiler.stop(); }
|
||||
|
||||
/**
|
||||
* @return Statistic.
|
||||
*/
|
||||
[[nodiscard]] std::optional<profiling::TaskCounter> &task_counter() noexcept { return _task_counter; }
|
||||
|
||||
/**
|
||||
* @return Task tracer.
|
||||
*/
|
||||
[[nodiscard]] std::optional<profiling::TaskTracer> &task_tracer() noexcept { return _task_tracer; }
|
||||
|
||||
[[nodiscard]] std::unordered_map<std::string, std::vector<std::pair<std::uintptr_t, std::uintptr_t>>> memory_tags();
|
||||
|
||||
bool operator==(const util::core_set &cores) const noexcept { return _core_set == cores; }
|
||||
|
||||
bool operator!=(const util::core_set &cores) const noexcept { return _core_set != cores; }
|
||||
|
||||
private:
|
||||
class PhysicalCoreResourceWorkerIds
|
||||
{
|
||||
public:
|
||||
PhysicalCoreResourceWorkerIds() noexcept
|
||||
: _worker_ids{std::numeric_limits<std::uint16_t>::max(), std::numeric_limits<std::uint16_t>::max(),
|
||||
std::numeric_limits<std::uint16_t>::max()}
|
||||
{
|
||||
}
|
||||
|
||||
explicit PhysicalCoreResourceWorkerIds(const std::uint16_t worker_id) noexcept
|
||||
: _worker_ids{worker_id, worker_id, worker_id}
|
||||
{
|
||||
}
|
||||
|
||||
PhysicalCoreResourceWorkerIds(const std::uint16_t memory_bound_worker_id,
|
||||
const std::uint16_t compute_bound_worker_id,
|
||||
const std::uint16_t mixed_worker_id) noexcept
|
||||
: _worker_ids{memory_bound_worker_id, compute_bound_worker_id, mixed_worker_id}
|
||||
{
|
||||
}
|
||||
|
||||
~PhysicalCoreResourceWorkerIds() noexcept = default;
|
||||
|
||||
PhysicalCoreResourceWorkerIds &operator=(const PhysicalCoreResourceWorkerIds &) noexcept = default;
|
||||
PhysicalCoreResourceWorkerIds &operator=(PhysicalCoreResourceWorkerIds &&) noexcept = default;
|
||||
|
||||
[[nodiscard]] std::uint16_t operator[](const enum annotation::resource_boundness boundness) const noexcept
|
||||
{
|
||||
return _worker_ids[boundness];
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint16_t &operator[](const enum annotation::resource_boundness boundness) noexcept
|
||||
{
|
||||
return _worker_ids[boundness];
|
||||
}
|
||||
|
||||
operator bool()
|
||||
{
|
||||
return _worker_ids[0U] != std::numeric_limits<std::uint16_t>::max() &&
|
||||
_worker_ids[1U] != std::numeric_limits<std::uint16_t>::max() &&
|
||||
_worker_ids[2U] != std::numeric_limits<std::uint16_t>::max();
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<std::uint16_t, 3U> _worker_ids;
|
||||
};
|
||||
|
||||
// Cores to run the worker threads on.
|
||||
const util::core_set _core_set;
|
||||
|
||||
// Number of tasks a resource will be prefetched in front of.
|
||||
const PrefetchDistance _prefetch_distance;
|
||||
|
||||
// All initialized workers.
|
||||
std::array<Worker *, config::max_cores()> _worker{nullptr};
|
||||
|
||||
// Map of worker id to NUMA region id.
|
||||
std::array<std::uint8_t, config::max_cores()> _worker_numa_node_map{0U};
|
||||
|
||||
// Flag for the worker threads. If false, the worker threads will stop.
|
||||
// This is atomic for hardware that does not guarantee atomic reads/writes of booleans.
|
||||
alignas(64) util::maybe_atomic<bool> _is_running{false};
|
||||
|
||||
// Epoch manager for memory reclamation,
|
||||
alignas(64) memory::reclamation::EpochManager _epoch_manager;
|
||||
|
||||
// Profiler for task statistics.
|
||||
alignas(64) std::optional<profiling::TaskCounter> _task_counter{std::nullopt};
|
||||
|
||||
// Profiler for idle times.
|
||||
alignas(64) profiling::IdleProfiler _idle_profiler;
|
||||
|
||||
// Recorder for tracing task run times.
|
||||
alignas(64) std::optional<profiling::TaskTracer> _task_tracer{std::nullopt};
|
||||
|
||||
/**
|
||||
* Make a decision whether a task should be scheduled to the local
|
||||
* channel or a remote.
|
||||
*
|
||||
* @param is_readonly Access mode of the task.
|
||||
* @param primitive The synchronization primitive of the task annotated resource.
|
||||
* @param resource_worker_id Worker id of the task annotated resource.
|
||||
* @param current_worker_id Worker id where the spawn() operation is called.
|
||||
* @return True, if the task should be scheduled local.
|
||||
*/
|
||||
[[nodiscard]] static inline bool keep_task_local(const bool is_readonly, const synchronization::primitive primitive)
|
||||
{
|
||||
return (is_readonly && primitive != synchronization::primitive::ScheduleAll) ||
|
||||
(primitive != synchronization::primitive::None && primitive != synchronization::primitive::ScheduleAll &&
|
||||
primitive != synchronization::primitive::ScheduleWriter);
|
||||
}
|
||||
};
|
||||
} // namespace mx::tasking
|
||||
32
repos/ealanos/src/lib/mx/tasking/shared_task_queue.h
Normal file
32
repos/ealanos/src/lib/mx/tasking/shared_task_queue.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "task.h"
|
||||
#include <cstdint>
|
||||
#include <mx/queue/bound_mpmc.h>
|
||||
#include <mx/queue/priority_queue.h>
|
||||
|
||||
namespace mx::tasking {
|
||||
template <std::size_t CAPACITY> class SharedTaskQueue
|
||||
{
|
||||
public:
|
||||
SharedTaskQueue() : _queue(CAPACITY) {}
|
||||
~SharedTaskQueue() = default;
|
||||
|
||||
void push_back(TaskInterface *task) noexcept { _queue.try_push_back(task); }
|
||||
|
||||
[[nodiscard]] TaskInterface *pop_front() noexcept
|
||||
{
|
||||
TaskInterface *task = nullptr;
|
||||
_queue.try_pop_front(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool empty() const noexcept { return _queue.empty(); }
|
||||
|
||||
private:
|
||||
queue::BoundMPMC<TaskInterface *> _queue;
|
||||
};
|
||||
|
||||
using GlobalSharedTaskQueue = queue::PriorityQueue<SharedTaskQueue<1U << 22U>, priority::low, priority::normal>;
|
||||
using NUMASharedTaskQueue = queue::PriorityQueue<SharedTaskQueue<1U << 20U>, priority::low, priority::normal>;
|
||||
} // namespace mx::tasking
|
||||
43
repos/ealanos/src/lib/mx/tasking/task.cpp
Normal file
43
repos/ealanos/src/lib/mx/tasking/task.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "task.h"
|
||||
#include "runtime.h"
|
||||
#include <mx/system/cpu.h>
|
||||
|
||||
using namespace mx::tasking;
|
||||
|
||||
TaskResult TaskResult::make_stop(const std::uint16_t worker_id, const bool stop_network) noexcept
|
||||
{
|
||||
auto *stop_task = runtime::new_task<StopTaskingTask>(worker_id, stop_network);
|
||||
stop_task->annotate(std::uint16_t{0U});
|
||||
return TaskResult::make_succeed_and_remove(stop_task);
|
||||
}
|
||||
|
||||
TaskResult TaskLine::execute(const std::uint16_t worker_id)
|
||||
{
|
||||
auto result = this->_next_task->execute(worker_id);
|
||||
if (result.is_remove())
|
||||
{
|
||||
mx::tasking::runtime::delete_task(worker_id, this->_next_task);
|
||||
}
|
||||
|
||||
if (result.has_successor())
|
||||
{
|
||||
this->_next_task = static_cast<TaskInterface *>(result);
|
||||
this->annotate(_next_task);
|
||||
return TaskResult::make_succeed(this);
|
||||
}
|
||||
|
||||
if (this->_waiting_tasks.empty() == false)
|
||||
{
|
||||
this->_next_task = this->_waiting_tasks.pop_front();
|
||||
this->annotate(_next_task);
|
||||
return TaskResult::make_succeed(this);
|
||||
}
|
||||
|
||||
return TaskResult::make_remove();
|
||||
}
|
||||
|
||||
TaskResult StopTaskingTask::execute(const std::uint16_t /*worker_id*/)
|
||||
{
|
||||
runtime::stop(this->_stop_network);
|
||||
return TaskResult::make_remove();
|
||||
}
|
||||
641
repos/ealanos/src/lib/mx/tasking/task.d
Normal file
641
repos/ealanos/src/lib/mx/tasking/task.d
Normal file
@@ -0,0 +1,641 @@
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.o /home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.d: \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.cpp \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/runtime.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h \
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp \
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h \
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h \
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h \
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h \
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h \
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h \
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h \
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h \
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_distance.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/scheduler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/shared_task_queue.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/bound_mpmc.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646 \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/priority_queue.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_squad.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/mpsc.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/worker.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/load.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_counter.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/aligned_t.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_buffer.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/ecpp/static_vector.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/compare \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_cycle_sampler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_map.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_hash.h \
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_growth_policy.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/climits \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ratio \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_execution_time_history.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool_occupancy.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/annotation.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_queues.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/core_set.h \
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/set \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/maybe_atomic.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/server.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/config.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/fixed_size_allocator.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/task_allocator_interface.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/builder.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/thread.h \
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/pthread.h \
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/logger.h \
|
||||
/home/mml/genode-igb/repos/libports/include/libc/component.h
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/annotation.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_descriptor.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/array:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/pstl/pstl_config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bit:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cmath:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdint:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/alignment_helper.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/resource_interface.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/atomic:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_t.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/memory_transaction.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/builtin.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/optimistic_lock.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/limits:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/config.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/rw_spinlock.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/algorithm:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/thread:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cassert:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/tagged_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/functional:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/synchronization/synchronization.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/random.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/new:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/environment.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/fstream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/sstream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/string:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/utility:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/priority.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/variant:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_stack.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstddef:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstring:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/bitset:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/list.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/vector:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/runtime.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/hamstraaja.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/coreheap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/memory/superblock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/bit_alloc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/bits.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/64bit/base/fixed_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/atomic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/stdint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/log.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/interface.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/buffered_output.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/mutex.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/lock.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/noncopyable.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/trace/timestamp.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ram_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/attempt.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/misc_math.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu/string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/meta.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/native_capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/exception.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/quota_guard.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/cache.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/mpsc_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/syscall-generic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base-tukija/include/tukija/spinlock.hpp:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/affinity.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/xml_node.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/token.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/blockade.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/logger.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/buffer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/cpu_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/cpu_thread/cpu_thread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/thread_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86_64/cpu/cpu_state.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/signal.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/list.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/semaphore.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/fifo.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_args.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/session_label.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/arg_string.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/pd_session.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/region_map/region_map.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/register.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/spec/x86/cpu/consts.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_ram_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/touch.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/env.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/parent/parent.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/id_space.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/avl_tree.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/root/root.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/entrypoint.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/reconstructible.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/util/construct_at.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_server.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/ipc_msgbuf.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/object_pool.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/weak_ptr.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/events.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/trace/policy.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/pd_session/capability.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/attached_dataspace.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/dataspace/client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/rpc_client.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/allocator_avl.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/tslab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/base/include/base/slab.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_distance.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/scheduler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/shared_task_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/bound_mpmc.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdlib:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/global_heap.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/config.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/chrono:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iterator:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/json.hpp:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/ciso646:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/initializer_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/iosfwd:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/memory:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/numeric:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/forward_list:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/tuple:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/type_traits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/unordered_map:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/valarray:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/exception:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/stdexcept:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/cstdio:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/istream:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/clocale:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ios:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ostream:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cache.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/cdefs.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/spec/x86_64/libc/machine/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/x86/endian.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_types.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_pthreadtypes.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_stdint.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/select.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_sigset.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_timeval.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/timespec.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/unistd.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/sys/_null.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/priority_queue.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_squad.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/queue/mpsc.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/worker.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/load.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_counter.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/aligned_t.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/task_tracer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/time.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/optional:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_buffer.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/prefetch_slot.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/ecpp/static_vector.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/compare:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_cycle_sampler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_map.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_hash.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/include/ealanos/util/tsl/robin_growth_policy.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/c_global/climits:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/ratio:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_execution_time_history.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/cpu.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_pool_occupancy.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/annotation.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/task_queues.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/reclamation/epoch_manager.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/worker_local_dynamic_size_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/core_set.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/stdcxx-4eddc2a55a80ed5d3a50fee3f5c25e7ac42afd72/include/stdcxx/std/set:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/maybe_atomic.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/tasking/profiling/idle_profiler.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/server.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/io/network/config.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/fixed_size_allocator.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/memory/task_allocator_interface.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/resource/builder.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/system/thread.h:
|
||||
|
||||
/home/mml/genode-igb/contrib/libc-ec685e91ee80735b4a067fea4582aa7f5d06c192/include/libc/pthread.h:
|
||||
|
||||
/home/mml/genode-igb/repos/ealanos/src/lib/mx/util/logger.h:
|
||||
|
||||
/home/mml/genode-igb/repos/libports/include/libc/component.h:
|
||||
330
repos/ealanos/src/lib/mx/tasking/task.h
Normal file
330
repos/ealanos/src/lib/mx/tasking/task.h
Normal file
@@ -0,0 +1,330 @@
|
||||
#pragma once
|
||||
|
||||
#include "annotation.h"
|
||||
#include "config.h"
|
||||
#include "priority.h"
|
||||
#include "task_stack.h"
|
||||
#include <bitset>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <mx/queue/list.h>
|
||||
#include <mx/resource/ptr.h>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace mx::tasking {
|
||||
|
||||
class TaskInterface;
|
||||
|
||||
/**
|
||||
* The TaskResult is returned by every task to tell the
|
||||
* runtime what happens next. Possibilities are run a
|
||||
* successor task, remove the returning task or stop
|
||||
* the entire runtime.
|
||||
*/
|
||||
class TaskResult
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Let the runtime know that the given task
|
||||
* should be run as a successor of the current
|
||||
* task. The runtime will schedule that task.
|
||||
*
|
||||
* @param successor_task Task to succeed.
|
||||
* @return A TaskResult that tells the
|
||||
* runtime to run the given task.
|
||||
*/
|
||||
static TaskResult make_succeed(TaskInterface *successor_task) noexcept { return TaskResult{successor_task, false}; }
|
||||
|
||||
/**
|
||||
* Let the runtime know that the given task
|
||||
* should be run as a successor of the current
|
||||
* task. The runtime will schedule that task.
|
||||
*
|
||||
* @param successor_task Task to succeed.
|
||||
* @return A TaskResult that tells the
|
||||
* runtime to run the given task.
|
||||
*/
|
||||
static TaskResult make_succeed(mx::resource::ptr resource) noexcept { return TaskResult{resource, false}; }
|
||||
|
||||
/**
|
||||
* Let the runtime know that the given task
|
||||
* should be removed after (successfully)
|
||||
* finishing.
|
||||
*
|
||||
* @return A TaskResult that tells the
|
||||
* runtime to remove the returning task.
|
||||
*/
|
||||
static TaskResult make_remove() noexcept { return TaskResult{nullptr, true}; }
|
||||
|
||||
/**
|
||||
* Let the runtime know that the given task
|
||||
* should be run as a successor of the current
|
||||
* task and the current task should be removed.
|
||||
*
|
||||
* @param successor_task Task to succeed.
|
||||
* @return A TaskResult that tells the runtime
|
||||
* to run the given task and remove the
|
||||
* returning task.
|
||||
*/
|
||||
static TaskResult make_succeed_and_remove(TaskInterface *successor_task) noexcept
|
||||
{
|
||||
return TaskResult{successor_task, true};
|
||||
}
|
||||
|
||||
/**
|
||||
* Nothing will happen
|
||||
*
|
||||
* @return An empty TaskResult.
|
||||
*/
|
||||
static TaskResult make_null() noexcept { return {}; }
|
||||
|
||||
/**
|
||||
* Let the runtime know to stop after
|
||||
* the returning task.
|
||||
*
|
||||
* @param worker_id Id of the current worker.
|
||||
* @param stop_network If set to true, the network server will also be stopped.
|
||||
* @return A TaskResult that tells the
|
||||
* runtime to top.
|
||||
*/
|
||||
static TaskResult make_stop(std::uint16_t worker_id, bool stop_network = true) noexcept;
|
||||
|
||||
constexpr TaskResult() = default;
|
||||
~TaskResult() = default;
|
||||
|
||||
TaskResult &operator=(const TaskResult &) = default;
|
||||
|
||||
explicit operator TaskInterface *() const noexcept { return _successor_task; }
|
||||
explicit operator mx::resource::ptr() const noexcept { return _resource; }
|
||||
|
||||
[[nodiscard]] bool is_remove() const noexcept { return _remove_task; }
|
||||
[[nodiscard]] bool has_successor() const noexcept { return _successor_task != nullptr; }
|
||||
[[nodiscard]] bool has_resource() const noexcept { return static_cast<bool>(_resource); }
|
||||
|
||||
private:
|
||||
constexpr TaskResult(TaskInterface *successor_task, const bool remove) noexcept
|
||||
: _successor_task(successor_task), _remove_task(remove)
|
||||
{
|
||||
}
|
||||
constexpr TaskResult(const mx::resource::ptr resource, const bool remove) noexcept
|
||||
: _resource(resource), _remove_task(remove)
|
||||
{
|
||||
}
|
||||
TaskInterface *_successor_task{nullptr};
|
||||
mx::resource::ptr _resource;
|
||||
bool _remove_task{false};
|
||||
};
|
||||
|
||||
/**
|
||||
* The task is the central execution unit of mxtasking.
|
||||
* Every task that should be executed has to derive
|
||||
* from this class.
|
||||
*/
|
||||
class TaskInterface
|
||||
{
|
||||
public:
|
||||
using channel = std::uint16_t;
|
||||
using node = std::uint8_t;
|
||||
|
||||
constexpr TaskInterface() = default;
|
||||
virtual ~TaskInterface() = default;
|
||||
|
||||
/**
|
||||
* Will be executed by a worker when the task gets CPU time.
|
||||
*
|
||||
* @param worker_id Worker ID the task is executed on.
|
||||
* @return Pointer to the follow up task.
|
||||
*/
|
||||
virtual TaskResult execute(std::uint16_t worker_id) = 0;
|
||||
|
||||
/**
|
||||
* @return Trace Id of the task, that will be included into recordings to assign
|
||||
* time ranges to specific tasks.
|
||||
*/
|
||||
[[nodiscard]] virtual std::uint64_t trace_id() const noexcept { return 0U; }
|
||||
|
||||
/**
|
||||
* @return The annotation of the task.
|
||||
*/
|
||||
[[nodiscard]] const annotation &annotation() const noexcept { return _annotation; }
|
||||
|
||||
/**
|
||||
* @return The annotation of the task.
|
||||
*/
|
||||
[[nodiscard]] class annotation &annotation() noexcept { return _annotation; }
|
||||
|
||||
/**
|
||||
* Annotate the task with a resource the task will work on.
|
||||
* The size identifies how many bytes will be prefetched.
|
||||
*
|
||||
* @param resource Pointer to the resource.
|
||||
* @param size Size of the resource (that will be prefetched).
|
||||
*/
|
||||
void annotate(const mx::resource::ptr resource_, const std::uint16_t size) noexcept
|
||||
{
|
||||
annotate(resource_, PrefetchSize::make(PrefetchDescriptor::PrefetchType::Temporal, size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotate the task with a resource the task will work on.
|
||||
* The object will be used for synchronization and prefetching.
|
||||
*
|
||||
* @param resource Pointer to the resource.
|
||||
* @param prefetch_hint Mask for prefetching the resource.
|
||||
*/
|
||||
void annotate(const mx::resource::ptr resource_, const PrefetchDescriptor descriptor) noexcept
|
||||
{
|
||||
annotate(resource_);
|
||||
annotate(PrefetchHint{descriptor, resource_});
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotate the task with a resource the task will work on.
|
||||
* The data object will be used for synchronization only.
|
||||
*
|
||||
* @param resource Pointer to the resource.
|
||||
*/
|
||||
void annotate(const mx::resource::ptr resource_) noexcept { _annotation.set(resource_); }
|
||||
|
||||
/**
|
||||
* Annotate the task with a prefetch hint that will be prefetched.
|
||||
*
|
||||
* @param prefetch_hint Hint for prefetching.
|
||||
*/
|
||||
void annotate(const PrefetchHint prefetch_hint) noexcept { _annotation.set(prefetch_hint); }
|
||||
|
||||
/**
|
||||
* Annotate the task with a desired channel the task should be executed on.
|
||||
*
|
||||
* @param worker_id ID of the channel.
|
||||
*/
|
||||
void annotate(const std::uint16_t worker_id) noexcept { _annotation.set(worker_id); }
|
||||
|
||||
/**
|
||||
* Annotate the task with a desired NUMA node id the task should executed on.
|
||||
*
|
||||
* @param node_id ID of the NUMA node.
|
||||
*/
|
||||
void annotate(const std::uint8_t node_id) noexcept { _annotation.set(node_id); }
|
||||
|
||||
/**
|
||||
* Annotate the task with a run priority (low, normal, high).
|
||||
*
|
||||
* @param priority_ Priority the task should run with.
|
||||
*/
|
||||
void annotate(const priority priority_) noexcept { _annotation.set(priority_); }
|
||||
|
||||
/**
|
||||
* Copy annotations from other task to this one.
|
||||
*
|
||||
* @param other Other task to copy annotations from.
|
||||
*/
|
||||
void annotate(TaskInterface *other) noexcept { _annotation = other->_annotation; }
|
||||
|
||||
/**
|
||||
* Copy annotation to this one.
|
||||
*
|
||||
* @param annotation
|
||||
*/
|
||||
void annotate(const auto &annotation) noexcept { _annotation = annotation; }
|
||||
|
||||
/**
|
||||
* Annotate the task to execute on a specific destination.
|
||||
*
|
||||
* @param execution_destination Destination to execute on.
|
||||
*/
|
||||
void annotate(const annotation::execution_destination execution_destination) noexcept
|
||||
{
|
||||
_annotation.set(execution_destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotate the task whether it is a reading or writing task.
|
||||
*
|
||||
* @param is_readonly True, when the task is read only (false by default).
|
||||
*/
|
||||
void annotate(const annotation::access_intention access_intention) noexcept { _annotation.set(access_intention); }
|
||||
|
||||
/**
|
||||
* @return Pointer to the next task in spawn queue.
|
||||
*/
|
||||
[[nodiscard]] TaskInterface *next() const noexcept { return _next; }
|
||||
|
||||
/**
|
||||
* Set the next task for scheduling.
|
||||
* @param next Task scheduled after this task.
|
||||
*/
|
||||
void next(TaskInterface *next) noexcept { _next = next; }
|
||||
|
||||
private:
|
||||
/// Pointer for next task in queue.
|
||||
TaskInterface *_next{nullptr};
|
||||
|
||||
/// Tasks annotations.
|
||||
class annotation _annotation
|
||||
{
|
||||
};
|
||||
};
|
||||
|
||||
class LambdaTask : public TaskInterface
|
||||
{
|
||||
public:
|
||||
LambdaTask(std::function<TaskResult(std::uint16_t)> &&callback) noexcept : _callback(std::move(callback)) {}
|
||||
|
||||
LambdaTask(std::function<void()> &&callback) noexcept
|
||||
: LambdaTask([callback = std::move(callback)](const std::uint16_t /*worker_id*/) {
|
||||
callback();
|
||||
return TaskResult::make_remove();
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
~LambdaTask() noexcept override = default;
|
||||
|
||||
TaskResult execute(std::uint16_t worker_id) override { return _callback(worker_id); }
|
||||
|
||||
private:
|
||||
std::function<TaskResult(std::uint16_t)> _callback;
|
||||
};
|
||||
|
||||
class TaskLine : public TaskInterface
|
||||
{
|
||||
public:
|
||||
TaskLine() noexcept = default;
|
||||
~TaskLine() noexcept override = default;
|
||||
|
||||
TaskResult execute(std::uint16_t worker_id) override;
|
||||
|
||||
void add(TaskInterface *task)
|
||||
{
|
||||
if (_next_task == nullptr)
|
||||
{
|
||||
_next_task = task;
|
||||
annotate(task);
|
||||
}
|
||||
else
|
||||
{
|
||||
_waiting_tasks.push_back(task);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool empty() const noexcept { return _next_task == nullptr; }
|
||||
|
||||
private:
|
||||
TaskInterface *_next_task;
|
||||
queue::List<TaskInterface> _waiting_tasks;
|
||||
};
|
||||
|
||||
class StopTaskingTask final : public TaskInterface
|
||||
{
|
||||
public:
|
||||
constexpr StopTaskingTask(const bool stop_network) noexcept : _stop_network(stop_network) {}
|
||||
~StopTaskingTask() override = default;
|
||||
|
||||
TaskResult execute(std::uint16_t worker_id) override;
|
||||
|
||||
private:
|
||||
const bool _stop_network;
|
||||
};
|
||||
} // namespace mx::tasking
|
||||
342
repos/ealanos/src/lib/mx/tasking/task_buffer.h
Normal file
342
repos/ealanos/src/lib/mx/tasking/task_buffer.h
Normal file
@@ -0,0 +1,342 @@
|
||||
#pragma once
|
||||
#include "load.h"
|
||||
#include "prefetch_distance.h"
|
||||
#include "prefetch_slot.h"
|
||||
#include "task.h"
|
||||
#include "task_cycle_sampler.h"
|
||||
#include "task_execution_time_history.h"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <mx/memory/config.h>
|
||||
#include <mx/system/cache.h>
|
||||
#include <mx/system/cpu.h>
|
||||
#include <utility>
|
||||
|
||||
namespace mx::tasking {
|
||||
/**
|
||||
* The task buffer holds tasks that are ready to execute.
|
||||
* The buffer is realized as a ring buffer with a fixed size.
|
||||
* All empty slots are null pointers.
|
||||
*/
|
||||
template <std::size_t S> class TaskBuffer
|
||||
{
|
||||
public:
|
||||
class Slot
|
||||
{
|
||||
public:
|
||||
constexpr Slot() noexcept = default;
|
||||
~Slot() noexcept = default;
|
||||
|
||||
/**
|
||||
* Assigns the task for execution to this slot.
|
||||
* @param task Task that should be executed when the task buffer reaches this slot.
|
||||
*/
|
||||
void task(TaskInterface *task) noexcept { _task = task; }
|
||||
|
||||
[[nodiscard]] TaskInterface *task() const noexcept { return _task; }
|
||||
|
||||
/**
|
||||
* Consumes the task of this slot and returns it.
|
||||
* @return Task that should be executed.
|
||||
*/
|
||||
[[nodiscard]] TaskInterface *get() noexcept { return std::exchange(_task, nullptr); }
|
||||
|
||||
/**
|
||||
* Executes the prefetch instructions (the task descriptor and its assigned resource).
|
||||
*/
|
||||
void prefetch() noexcept { _prefetch_slot.prefetch(); }
|
||||
|
||||
/**
|
||||
* Sets the given task for prefetching when the task buffer reaches this slot.
|
||||
* @param task Task that should be prefetched (both task descriptor and resource).
|
||||
*/
|
||||
void prefetch(const resource::ptr resource, const PrefetchDescriptor descriptor) noexcept
|
||||
{
|
||||
_prefetch_slot.assign(resource, descriptor);
|
||||
}
|
||||
|
||||
bool operator==(std::nullptr_t) const noexcept { return _task == nullptr; }
|
||||
bool operator!=(std::nullptr_t) const noexcept { return _task != nullptr; }
|
||||
|
||||
private:
|
||||
TaskInterface *_task{nullptr};
|
||||
PrefetchSlot _prefetch_slot{};
|
||||
};
|
||||
|
||||
public:
|
||||
constexpr explicit TaskBuffer(const PrefetchDistance prefetch_distance) noexcept
|
||||
: _prefetch_distance(prefetch_distance)
|
||||
{
|
||||
}
|
||||
~TaskBuffer() noexcept = default;
|
||||
|
||||
/**
|
||||
* @return True, when the buffer is empty.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const noexcept { return _buffer[_head] == nullptr; }
|
||||
|
||||
/**
|
||||
* @return Number of tasks in the buffer.
|
||||
*/
|
||||
[[nodiscard]] std::uint16_t size() const noexcept
|
||||
{
|
||||
return _tail >= _head ? (_tail - _head) : (S - (_head - _tail));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Number of maximal tasks of the buffer.
|
||||
*/
|
||||
[[nodiscard]] constexpr auto max_size() const noexcept { return S; }
|
||||
|
||||
/**
|
||||
* @return Number of free slots.
|
||||
*/
|
||||
[[nodiscard]] std::uint16_t available_slots() const noexcept { return S - size(); }
|
||||
|
||||
Slot &next() noexcept
|
||||
{
|
||||
auto &slot = this->_buffer[this->_head];
|
||||
this->_head = TaskBuffer<S>::normalize(this->_head + 1U);
|
||||
return slot;
|
||||
}
|
||||
|
||||
[[nodiscard]] TaskInterface *task(const std::uint16_t index) const noexcept
|
||||
{
|
||||
return this->_buffer[TaskBuffer<S>::normalize(this->_head + index)].task();
|
||||
}
|
||||
|
||||
[[nodiscard]] TaskInterface *head() const noexcept { return this->_buffer[this->_head].task(); }
|
||||
|
||||
/**
|
||||
* Takes out tasks from the given queue and inserts them into the buffer.
|
||||
* @param from_queue Queue to take tasks from.
|
||||
* @param count Number of maximal tasks to take out of the queue.
|
||||
* @return Number of retrieved tasks.
|
||||
*/
|
||||
template <class Q> std::uint16_t fill(Q &from_queue, std::uint16_t count) noexcept;
|
||||
|
||||
[[nodiscard]] std::uint8_t refill_treshold() const noexcept
|
||||
{
|
||||
if (this->_prefetch_distance.is_enabled())
|
||||
{
|
||||
return this->_prefetch_distance.is_automatic() ? this->_task_cycles.size()
|
||||
: this->_prefetch_distance.fixed_distance();
|
||||
}
|
||||
|
||||
return 0U;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_prefetching_enabled() const noexcept { return this->_prefetch_distance.is_enabled(); }
|
||||
|
||||
[[nodiscard]] TaskCycleSampler &sampler() noexcept { return _task_cycle_sampler; }
|
||||
|
||||
private:
|
||||
/// Prefetch distance.
|
||||
const PrefetchDistance _prefetch_distance;
|
||||
|
||||
/// Index of the first element in the buffer.
|
||||
std::uint16_t _head{0U};
|
||||
|
||||
/// Index of the last element in the buffer.
|
||||
std::uint16_t _tail{0U};
|
||||
|
||||
/// Array with task-slots.
|
||||
std::array<Slot, S> _buffer{};
|
||||
|
||||
/// History of last cycles for the last dispatched tasks.
|
||||
TaskExecutionTimeHistory _task_cycles;
|
||||
|
||||
/// Sample for monitoring task cycles.
|
||||
TaskCycleSampler _task_cycle_sampler;
|
||||
|
||||
/**
|
||||
* Normalizes the index with respect to the size.
|
||||
* @param index Index.
|
||||
* @return Normalized index.
|
||||
*/
|
||||
[[nodiscard]] static std::uint16_t normalize(const std::uint16_t index) noexcept { return index & (S - 1U); }
|
||||
|
||||
/**
|
||||
* Normalizes the index backwards with respect to the given offset.
|
||||
* @param index Index.
|
||||
* @param offset Offset to index.
|
||||
* @return Normalized index.
|
||||
*/
|
||||
[[nodiscard]] static std::uint16_t normalize_backward(const std::uint16_t index,
|
||||
const std::uint16_t offset) noexcept
|
||||
{
|
||||
const auto diff = std::int32_t(index) - std::int32_t(offset);
|
||||
return diff + (static_cast<std::uint8_t>(index < offset) * S);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of to-prefeteched cache lines from a given descriptor.
|
||||
*
|
||||
* @param descriptor Descriptor describing the prefetch.
|
||||
* @return Number of cache lines to prefetch.
|
||||
*/
|
||||
[[nodiscard]] static std::uint16_t prefetched_cache_lines(const PrefetchDescriptor descriptor) noexcept
|
||||
{
|
||||
const auto descriptor_id = descriptor.id();
|
||||
const auto data = descriptor.data_without_descriptor_bits();
|
||||
switch (descriptor_id)
|
||||
{
|
||||
case PrefetchDescriptor::SizeNonTemporal:
|
||||
case PrefetchDescriptor::SizeTemporal:
|
||||
case PrefetchDescriptor::SizeWrite:
|
||||
return (PrefetchSizeView{data}.get()) / system::cache::line_size();
|
||||
case PrefetchDescriptor::CallbackAny:
|
||||
return (PrefetchCallbackView{data}.size()) / system::cache::line_size();
|
||||
case PrefetchDescriptor::MaskNonTemporal:
|
||||
case PrefetchDescriptor::MaskTemporal:
|
||||
case PrefetchDescriptor::MaskWrite:
|
||||
return PrefetchMaskView{data}.count();
|
||||
case PrefetchDescriptor::None:
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t S>
|
||||
template <class Q>
|
||||
std::uint16_t TaskBuffer<S>::fill(Q &from_queue, std::uint16_t count) noexcept
|
||||
{
|
||||
if (count == 0U || from_queue.empty())
|
||||
{
|
||||
return 0U;
|
||||
}
|
||||
|
||||
const auto size = S - count;
|
||||
TaskInterface *task;
|
||||
|
||||
if constexpr (std::is_same<Q, mx::queue::List<TaskInterface>>::value)
|
||||
{
|
||||
std::tie(task, count) = from_queue.pop_front(count);
|
||||
}
|
||||
|
||||
/// Prefetching at all.
|
||||
if (this->_prefetch_distance.is_enabled())
|
||||
{
|
||||
/// Prefetching with automatic calculated prefetch distance
|
||||
/// based on annotated cycles.
|
||||
if (this->_prefetch_distance.is_automatic())
|
||||
{
|
||||
for (auto i = 0U; i < count; ++i)
|
||||
{
|
||||
if constexpr (std::is_same<Q, mx::queue::List<TaskInterface>>::value == false)
|
||||
{
|
||||
task = static_cast<TaskInterface *>(from_queue.pop_front());
|
||||
if (task == nullptr)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/// Location where the task will be scheduled.
|
||||
const auto task_buffer_index = this->_tail;
|
||||
|
||||
/// Schedule the task to the end of the task buffer.
|
||||
this->_buffer[task_buffer_index].task(task);
|
||||
|
||||
/// Increment tail for the next task.
|
||||
this->_tail = TaskBuffer<S>::normalize(task_buffer_index + 1U);
|
||||
|
||||
/// Schedule prefetch instruction <prefetch_distance> slots before.
|
||||
if (task->annotation().has_prefetch_hint())
|
||||
{
|
||||
const auto &hint = task->annotation().prefetch_hint();
|
||||
|
||||
/// Calculate cycles needed by the prefetch (|lines| * fixed latency).
|
||||
const auto prefetched_cache_lines = TaskBuffer::prefetched_cache_lines(hint.descriptor());
|
||||
const auto needed_cycles_latency =
|
||||
prefetched_cache_lines * memory::config::latency_per_prefetched_cache_line();
|
||||
|
||||
/// Go back (towards head) until latency is hidden by task executions.
|
||||
const auto prefetch_distance = this->_task_cycles.prefetch_distance(needed_cycles_latency);
|
||||
|
||||
/// Schedule the prefetch to tail - prefetch distance.
|
||||
this->_buffer[TaskBuffer<S>::normalize_backward(task_buffer_index, prefetch_distance)].prefetch(
|
||||
hint.resource(), hint.descriptor());
|
||||
}
|
||||
|
||||
/// Push task cycles (either monitored or annotated) to the history.
|
||||
const auto task_cycles = this->_task_cycle_sampler.cycles(task);
|
||||
this->_task_cycles.push(task_cycles);
|
||||
|
||||
if constexpr (std::is_same<Q, mx::queue::List<TaskInterface>>::value)
|
||||
{
|
||||
task = task->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Prefetching with fixed prefetch distance.
|
||||
else
|
||||
{
|
||||
auto prefetch_tail =
|
||||
TaskBuffer<S>::normalize_backward(this->_tail, this->_prefetch_distance.fixed_distance());
|
||||
|
||||
for (auto i = 0U; i < count; ++i)
|
||||
{
|
||||
if constexpr (std::is_same<Q, mx::queue::List<TaskInterface>>::value == false)
|
||||
{
|
||||
task = static_cast<TaskInterface *>(from_queue.pop_front());
|
||||
if (task == nullptr)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/// Schedule task.
|
||||
this->_buffer[this->_tail].task(task);
|
||||
|
||||
/// Increment tail.
|
||||
this->_tail = TaskBuffer<S>::normalize(this->_tail + 1U);
|
||||
|
||||
/// Schedule prefetch instruction <prefetch_distance> slots before.
|
||||
if (size + i >= this->_prefetch_distance.fixed_distance() && task->annotation().has_prefetch_hint())
|
||||
{
|
||||
const auto &hint = task->annotation().prefetch_hint();
|
||||
this->_buffer[prefetch_tail].prefetch(hint.resource(), hint.descriptor());
|
||||
}
|
||||
|
||||
/// Increment prefetch tail.
|
||||
prefetch_tail = TaskBuffer<S>::normalize(prefetch_tail + 1U);
|
||||
|
||||
if constexpr (std::is_same<Q, mx::queue::List<TaskInterface>>::value)
|
||||
{
|
||||
task = task->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/// No prefetching.
|
||||
for (auto i = 0U; i < count; ++i)
|
||||
{
|
||||
if constexpr (std::is_same<Q, mx::queue::List<TaskInterface>>::value == false)
|
||||
{
|
||||
task = static_cast<TaskInterface *>(from_queue.pop_front());
|
||||
if (task == nullptr)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/// Schedule task.
|
||||
this->_buffer[this->_tail].task(task);
|
||||
|
||||
/// Increment tail.
|
||||
this->_tail = TaskBuffer<S>::normalize(this->_tail + 1U);
|
||||
|
||||
if constexpr (std::is_same<Q, mx::queue::List<TaskInterface>>::value)
|
||||
{
|
||||
task = task->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
} // namespace mx::tasking
|
||||
127
repos/ealanos/src/lib/mx/tasking/task_cycle_sampler.h
Normal file
127
repos/ealanos/src/lib/mx/tasking/task_cycle_sampler.h
Normal file
@@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
#include "task.h"
|
||||
#include <cstdint>
|
||||
#include <tsl/robin_map.h>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace mx::tasking {
|
||||
class TaskCycleSampler
|
||||
{
|
||||
private:
|
||||
class Sample
|
||||
{
|
||||
public:
|
||||
constexpr Sample() noexcept = default;
|
||||
|
||||
explicit Sample(const std::uint64_t cycles) noexcept : _count(1U), _cycles(cycles), _average_cycles(cycles) {}
|
||||
|
||||
Sample(const std::uint32_t count, const std::uint64_t cycles) noexcept
|
||||
: _count(count), _cycles(cycles), _average_cycles(cycles / count)
|
||||
{
|
||||
}
|
||||
|
||||
~Sample() noexcept = default;
|
||||
|
||||
void add(const std::uint32_t cycles) noexcept
|
||||
{
|
||||
++_count;
|
||||
_cycles += cycles;
|
||||
_average_cycles = _cycles / _count;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint32_t average() const noexcept { return _average_cycles; }
|
||||
|
||||
[[nodiscard]] std::uint64_t count() const noexcept { return _count; }
|
||||
|
||||
[[nodiscard]] std::uint64_t cycles() const noexcept { return _cycles; }
|
||||
|
||||
private:
|
||||
/// Number of how many times this task was sampled.
|
||||
std::uint64_t _count{0U};
|
||||
|
||||
/// Number of cycles sampled for this task.
|
||||
std::uint64_t _cycles{0U};
|
||||
|
||||
/// Number of cycles in average (_count/_cycles).
|
||||
std::uint32_t _average_cycles{0U};
|
||||
};
|
||||
|
||||
public:
|
||||
TaskCycleSampler() { _task_cycles.reserve(16U); }
|
||||
|
||||
~TaskCycleSampler() = default;
|
||||
|
||||
void add(const std::uint64_t task_id, const std::uint64_t cycles)
|
||||
{
|
||||
if (task_id != 0U)
|
||||
{
|
||||
if (auto iterator = _task_cycles.find(task_id); iterator != _task_cycles.end())
|
||||
{
|
||||
iterator.value().add(cycles);
|
||||
}
|
||||
else
|
||||
{
|
||||
_task_cycles.insert(std::make_pair(task_id, Sample{cycles}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint32_t cycles(TaskInterface *task) const
|
||||
{
|
||||
if constexpr (config::is_monitor_task_cycles_for_prefetching())
|
||||
{
|
||||
const auto trace_id = task->trace_id();
|
||||
if (const auto iterator = _task_cycles.find(trace_id); iterator != _task_cycles.end())
|
||||
{
|
||||
return iterator.value().average();
|
||||
}
|
||||
}
|
||||
|
||||
return task->annotation().cycles();
|
||||
}
|
||||
|
||||
void dump()
|
||||
{
|
||||
for (const auto &task : _task_cycles)
|
||||
{
|
||||
std::cout << task.first << " = " << task.second.average() << "(" << task.second.cycles() << "/"
|
||||
<< task.second.count() << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unordered_map<std::uint64_t, Sample> get() const noexcept
|
||||
{
|
||||
auto cycles = std::unordered_map<std::uint64_t, Sample>{};
|
||||
|
||||
for (const auto &task : _task_cycles)
|
||||
{
|
||||
cycles.insert(std::make_pair(task.first, task.second));
|
||||
}
|
||||
|
||||
return cycles;
|
||||
}
|
||||
|
||||
private:
|
||||
class Hash
|
||||
{
|
||||
public:
|
||||
std::size_t operator()(std::uint64_t key) const noexcept
|
||||
{
|
||||
key ^= key >> 33U;
|
||||
key *= std::uint64_t(0xff51afd7ed558ccd);
|
||||
key ^= key >> 33U;
|
||||
|
||||
// key *= std::uint64_t(0xc4ceb9fe1a85ec53);
|
||||
// key ^= key >> 33U;
|
||||
|
||||
return static_cast<std::size_t>(key);
|
||||
}
|
||||
};
|
||||
|
||||
/// List of all tasks, (their average cycles, total number of sampled executions and total cycles during execution).
|
||||
tsl::robin_map<std::uint64_t, Sample, Hash> _task_cycles;
|
||||
};
|
||||
} // namespace mx::tasking
|
||||
@@ -0,0 +1,92 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef USE_AVX2
|
||||
#include <immintrin.h>
|
||||
#else
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#endif
|
||||
|
||||
namespace mx::tasking {
|
||||
#ifdef USE_AVX2
|
||||
class TaskExecutionTimeHistory
|
||||
{
|
||||
public:
|
||||
TaskExecutionTimeHistory() noexcept { _history = _mm256_setzero_si256(); }
|
||||
|
||||
~TaskExecutionTimeHistory() noexcept = default;
|
||||
|
||||
[[nodiscard]] constexpr std::uint8_t size() const noexcept { return 8U; }
|
||||
|
||||
[[nodiscard]] std::uint8_t prefetch_distance(const std::uint32_t needed_cycles) noexcept
|
||||
{
|
||||
const auto needed_cycles_vector = _mm256_set1_epi32(std::int32_t(needed_cycles));
|
||||
|
||||
/// Compare each item in the histry if the slot covers the needed cycles.
|
||||
const auto compared_cycles = _mm256_cmpgt_epi32(needed_cycles_vector, _history);
|
||||
|
||||
/// Count the slots needed.
|
||||
const auto mask = _mm256_movemask_epi8(compared_cycles);
|
||||
const auto pop_count = _mm_popcnt_u32(mask);
|
||||
const auto prefetch_distance = pop_count >> 2U;
|
||||
|
||||
return prefetch_distance;
|
||||
}
|
||||
|
||||
void push(const std::uint32_t cycles) noexcept
|
||||
{
|
||||
/// Shift out the last task.
|
||||
const auto shifted = _mm256_alignr_epi8(_mm256_permute2x128_si256(_history, _history, 0x81), _history, 4);
|
||||
|
||||
/// Add the task's cycles to the history.
|
||||
_history = _mm256_add_epi32(shifted, _mm256_set1_epi32(cycles));
|
||||
}
|
||||
|
||||
private:
|
||||
/// Last 8 task cycles (summed up = index(0) next task, index(1) = index(0) + next next task, etc.)
|
||||
alignas(64) __m256i _history;
|
||||
};
|
||||
#else
|
||||
class TaskExecutionTimeHistory
|
||||
{
|
||||
public:
|
||||
TaskExecutionTimeHistory() noexcept = default;
|
||||
|
||||
~TaskExecutionTimeHistory() noexcept = default;
|
||||
|
||||
[[nodiscard]] constexpr std::uint8_t size() const noexcept { return 8U; }
|
||||
|
||||
[[nodiscard]] std::uint8_t prefetch_distance(const std::uint32_t needed_cycles) noexcept
|
||||
{
|
||||
auto cycles = _history[7U];
|
||||
for (auto i = 6; i > 0; --i)
|
||||
{
|
||||
if (cycles >= needed_cycles)
|
||||
{
|
||||
return 8 - (i + 1);
|
||||
}
|
||||
|
||||
cycles += _history[i];
|
||||
}
|
||||
|
||||
return 8;
|
||||
}
|
||||
|
||||
void push(const std::uint32_t cycles) noexcept
|
||||
{
|
||||
|
||||
/// Shift out the last task.
|
||||
std::rotate(_history.begin(), _history.begin() + 1, _history.end());
|
||||
|
||||
/// Add the task's cycles to the history.
|
||||
_history[7U] = cycles;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Last 8 task cycles (summed up = index(0) next task, index(1) = index(0) + next next task, etc.)
|
||||
alignas(64) std::array<std::uint32_t, 8U> _history{0U};
|
||||
};
|
||||
#endif
|
||||
} // namespace mx::tasking
|
||||
107
repos/ealanos/src/lib/mx/tasking/task_pool.h
Normal file
107
repos/ealanos/src/lib/mx/tasking/task_pool.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
#include "task.h"
|
||||
#include "task_buffer.h"
|
||||
#include "task_pool_occupancy.h"
|
||||
#include "task_queues.h"
|
||||
#include <array>
|
||||
#include <mx/memory/config.h>
|
||||
#include <mx/queue/list.h>
|
||||
#include <mx/queue/mpsc.h>
|
||||
#include <mx/queue/priority_queue.h>
|
||||
|
||||
namespace mx::tasking {
|
||||
class alignas(64) TaskPool
|
||||
{
|
||||
public:
|
||||
explicit TaskPool(const std::uint16_t count_workers, const std::uint16_t worker_id, const std::uint8_t numa_id)
|
||||
: _queues(worker_id, numa_id, count_workers)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint64_t withdraw(TaskBuffer<config::task_buffer_size()> &task_buffer) noexcept
|
||||
{
|
||||
// Fill with normal prioritized.
|
||||
const auto size = _queues.fill<priority::normal>(task_buffer, task_buffer.available_slots());
|
||||
|
||||
// Fill with low prioritized.
|
||||
if (task_buffer.empty()) [[unlikely]]
|
||||
{
|
||||
return _queues.fill<priority::low>(task_buffer, config::task_buffer_size());
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules the task to thread-safe queue with regard to the NUMA region
|
||||
* of the producer. Producer of different NUMA regions should not share
|
||||
* a single queue.
|
||||
* @param task Task to be scheduled.
|
||||
* @param local_numa_node_id NUMA region of the producer.
|
||||
* @param local_worker_id Worker ID of the producer.
|
||||
*/
|
||||
void push_back_remote(TaskInterface *task, const std::uint8_t local_numa_node_id,
|
||||
const std::uint16_t local_worker_id) noexcept
|
||||
{
|
||||
_queues.push_back_remote(task, local_numa_node_id, local_worker_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules a task to the local queue, which is not thread-safe. Only
|
||||
* the channel owner should spawn tasks this way.
|
||||
* @param task Task to be scheduled.
|
||||
*/
|
||||
void push_back_local(TaskInterface *task) noexcept { _queues.push_back_local(task); }
|
||||
|
||||
/**
|
||||
* Schedules a task to the local queue, which is not thread-safe. Only
|
||||
* the channel owner should spawn tasks this way.
|
||||
* @param first First task to be scheduled.
|
||||
* @param last Last task of the list.
|
||||
*/
|
||||
void push_back_local(TaskInterface *first, TaskInterface *last) noexcept { _queues.push_back_local(first, last); }
|
||||
|
||||
/**
|
||||
* Adds usage prediction of a resource to this channel.
|
||||
* @param usage Predicted usage.
|
||||
*/
|
||||
void predict_usage(const mx::resource::expected_access_frequency usage) noexcept { _occupancy.predict(usage); }
|
||||
|
||||
/**
|
||||
* Updates the usage prediction of this channel.
|
||||
* @param old_prediction So far predicted usage.
|
||||
* @param new_prediction New predicted usage.
|
||||
*/
|
||||
void modify_predicted_usage(const mx::resource::expected_access_frequency old_prediction,
|
||||
const mx::resource::expected_access_frequency new_prediction) noexcept
|
||||
{
|
||||
_occupancy.revoke(old_prediction);
|
||||
_occupancy.predict(new_prediction);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Aggregated predicted usage.
|
||||
*/
|
||||
[[nodiscard]] mx::resource::expected_access_frequency predicted_usage() const noexcept
|
||||
{
|
||||
return static_cast<mx::resource::expected_access_frequency>(_occupancy);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True, whenever min. one prediction was "excessive".
|
||||
*/
|
||||
[[nodiscard]] bool has_excessive_usage_prediction() const noexcept
|
||||
{
|
||||
return _occupancy.has_excessive_usage_prediction();
|
||||
}
|
||||
|
||||
private:
|
||||
/// Backend queues.
|
||||
TaskQueues<config::queue()> _queues;
|
||||
|
||||
// Holder of resource predictions of this channel.
|
||||
alignas(64) TaskPoolOccupancy _occupancy;
|
||||
};
|
||||
} // namespace mx::tasking
|
||||
79
repos/ealanos/src/lib/mx/tasking/task_pool_occupancy.h
Normal file
79
repos/ealanos/src/lib/mx/tasking/task_pool_occupancy.h
Normal file
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <mx/resource/annotation.h>
|
||||
#include <mx/resource/ptr.h>
|
||||
|
||||
namespace mx::tasking {
|
||||
/**
|
||||
* Stores usage predictions.
|
||||
*/
|
||||
class TaskPoolOccupancy
|
||||
{
|
||||
public:
|
||||
constexpr TaskPoolOccupancy() = default;
|
||||
~TaskPoolOccupancy() = default;
|
||||
|
||||
/**
|
||||
* Adds the given predicted usage.
|
||||
* @param predicted_usage Predicted usage.
|
||||
*/
|
||||
void predict(const mx::resource::expected_access_frequency predicted_usage) noexcept
|
||||
{
|
||||
_predicted_usage_counter[static_cast<std::uint8_t>(predicted_usage)].fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts the given predicted usage.
|
||||
* @param predicted_usage Predicted usage.
|
||||
*/
|
||||
void revoke(const mx::resource::expected_access_frequency predicted_usage) noexcept
|
||||
{
|
||||
_predicted_usage_counter[static_cast<std::uint8_t>(predicted_usage)].fetch_sub(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True, when at least one prediction was "excessive".
|
||||
*/
|
||||
[[nodiscard]] bool has_excessive_usage_prediction() const noexcept
|
||||
{
|
||||
return has_at_least_one<mx::resource::expected_access_frequency::excessive>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The highest predicted usage.
|
||||
*/
|
||||
explicit operator mx::resource::expected_access_frequency() const noexcept
|
||||
{
|
||||
if (has_at_least_one<mx::resource::expected_access_frequency::excessive>())
|
||||
{
|
||||
return mx::resource::expected_access_frequency::excessive;
|
||||
}
|
||||
|
||||
if (has_at_least_one<mx::resource::expected_access_frequency::high>())
|
||||
{
|
||||
return mx::resource::expected_access_frequency::high;
|
||||
}
|
||||
|
||||
if (has_at_least_one<mx::resource::expected_access_frequency::normal>())
|
||||
{
|
||||
return mx::resource::expected_access_frequency::normal;
|
||||
}
|
||||
|
||||
return mx::resource::expected_access_frequency::unused;
|
||||
}
|
||||
|
||||
private:
|
||||
// Counter of predicted usages.
|
||||
std::array<std::atomic_uint64_t, 4U> _predicted_usage_counter{0U};
|
||||
|
||||
/**
|
||||
* @return True, when at least one usage as given by the template was predicted.
|
||||
*/
|
||||
template <mx::resource::expected_access_frequency U> [[nodiscard]] bool has_at_least_one() const noexcept
|
||||
{
|
||||
return _predicted_usage_counter[static_cast<std::uint8_t>(U)].load(std::memory_order_relaxed) > 0;
|
||||
}
|
||||
};
|
||||
} // namespace mx::tasking
|
||||
168
repos/ealanos/src/lib/mx/tasking/task_queues.h
Normal file
168
repos/ealanos/src/lib/mx/tasking/task_queues.h
Normal file
@@ -0,0 +1,168 @@
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
#include "task.h"
|
||||
#include "task_buffer.h"
|
||||
#include <mx/memory/config.h>
|
||||
#include <mx/queue/list.h>
|
||||
#include <mx/queue/mpsc.h>
|
||||
#include <mx/queue/priority_queue.h>
|
||||
|
||||
namespace mx::tasking {
|
||||
template <config::queue_backend M> class TaskQueues
|
||||
{
|
||||
};
|
||||
|
||||
template <> class TaskQueues<config::queue_backend::Single>
|
||||
{
|
||||
public:
|
||||
TaskQueues(const std::uint16_t /*worker_id*/, const std::uint8_t /*numa_node_id*/,
|
||||
const std::uint16_t /*count_workers*/)
|
||||
{
|
||||
}
|
||||
~TaskQueues() = default;
|
||||
|
||||
void push_back_remote(TaskInterface *task, const std::uint8_t /*numa_node_id*/,
|
||||
const std::uint16_t /*local_worker_id*/) noexcept
|
||||
{
|
||||
_queue.get(task->annotation().priority()).push_back(task);
|
||||
}
|
||||
|
||||
void push_back_local(TaskInterface *task) noexcept { _queue.get(task->annotation().priority()).push_back(task); }
|
||||
|
||||
void push_back_local(TaskInterface *first, TaskInterface *last) noexcept
|
||||
{
|
||||
_queue.get(first->annotation().priority()).push_back(first, last);
|
||||
}
|
||||
|
||||
template <priority P>
|
||||
[[nodiscard]] std::uint64_t fill(TaskBuffer<config::task_buffer_size()> &task_buffer,
|
||||
std::uint64_t available) noexcept
|
||||
{
|
||||
available -= task_buffer.template fill(_queue.template get<P>(), available);
|
||||
return task_buffer.max_size() - available;
|
||||
}
|
||||
|
||||
private:
|
||||
using MPSC = queue::PriorityQueue<queue::MPSC<TaskInterface>, priority::low, priority::normal>;
|
||||
|
||||
/// Single queue per worker.
|
||||
MPSC _queue;
|
||||
};
|
||||
|
||||
template <> class TaskQueues<config::queue_backend::NUMALocal>
|
||||
{
|
||||
public:
|
||||
TaskQueues(const std::uint16_t /*worker_id*/, const std::uint8_t numa_node_id,
|
||||
const std::uint16_t /*count_workers*/)
|
||||
: _numa_node_id(numa_node_id)
|
||||
{
|
||||
}
|
||||
~TaskQueues() = default;
|
||||
|
||||
void push_back_remote(TaskInterface *task, const std::uint8_t numa_node_id,
|
||||
const std::uint16_t /*local_worker_id*/) noexcept
|
||||
{
|
||||
_remote_queues[numa_node_id].get(task->annotation().priority()).push_back(task);
|
||||
}
|
||||
|
||||
void push_back_local(TaskInterface *task) noexcept
|
||||
{
|
||||
_local_queue.get(task->annotation().priority()).push_back(task);
|
||||
}
|
||||
|
||||
void push_back_local(TaskInterface *first, TaskInterface *last) noexcept
|
||||
{
|
||||
_local_queue.get(first->annotation().priority()).push_back(first, last);
|
||||
}
|
||||
|
||||
template <priority P>
|
||||
[[nodiscard]] std::uint64_t fill(TaskBuffer<config::task_buffer_size()> &task_buffer,
|
||||
std::uint64_t available) noexcept
|
||||
{
|
||||
// 1) Fill up from the local queue.
|
||||
available -= task_buffer.fill(_local_queue.get<P>(), available);
|
||||
|
||||
if (available > 0U)
|
||||
{
|
||||
// 2) Fill up from remote queues; start with the NUMA-local one.
|
||||
for (auto numa_index = 0U; numa_index < memory::config::max_numa_nodes(); ++numa_index)
|
||||
{
|
||||
static_assert((memory::config::max_numa_nodes() & (memory::config::max_numa_nodes() - 1U)) == 0U);
|
||||
|
||||
const auto numa_id = (_numa_node_id + numa_index) & (memory::config::max_numa_nodes() - 1U);
|
||||
available -= task_buffer.fill(_remote_queues[numa_id].get<P>(), available);
|
||||
}
|
||||
}
|
||||
|
||||
return task_buffer.max_size() - available;
|
||||
}
|
||||
|
||||
private:
|
||||
using List = queue::PriorityQueue<queue::List<TaskInterface>, priority::low, priority::normal>;
|
||||
using MPSC = queue::PriorityQueue<queue::MPSC<TaskInterface>, priority::low, priority::normal>;
|
||||
|
||||
const std::uint8_t _numa_node_id;
|
||||
|
||||
// Backend queues for a single producer (owning worker thread) and different priorities.
|
||||
List _local_queue;
|
||||
|
||||
// Backend queues for multiple produces in different NUMA regions and different priorities,
|
||||
alignas(64) std::array<MPSC, memory::config::max_numa_nodes()> _remote_queues;
|
||||
};
|
||||
|
||||
template <> class TaskQueues<config::queue_backend::WorkerLocal>
|
||||
{
|
||||
public:
|
||||
TaskQueues(const std::uint16_t worker_id, const std::uint8_t /*numa_node_id*/, const std::uint16_t count_workers)
|
||||
: _worker_id(worker_id), _count_workers(count_workers)
|
||||
{
|
||||
}
|
||||
~TaskQueues() = default;
|
||||
|
||||
void push_back_remote(TaskInterface *task, const std::uint8_t /*numa_node_id*/,
|
||||
const std::uint16_t local_worker_id) noexcept
|
||||
{
|
||||
_queues[local_worker_id].get(task->annotation().priority()).push_back(task);
|
||||
}
|
||||
|
||||
void push_back_local(TaskInterface *task) noexcept
|
||||
{
|
||||
_queues[_worker_id].get(task->annotation().priority()).push_back(task);
|
||||
}
|
||||
|
||||
void push_back_local(TaskInterface *first, TaskInterface *last) noexcept
|
||||
{
|
||||
_queues[_worker_id].get(first->annotation().priority()).push_back(first, last);
|
||||
}
|
||||
|
||||
template <priority P>
|
||||
[[nodiscard]] std::uint64_t fill(TaskBuffer<config::task_buffer_size()> &task_buffer,
|
||||
std::uint64_t available) noexcept
|
||||
{
|
||||
auto worker_id = _worker_id;
|
||||
for (auto i = 0U; i < _count_workers; ++i)
|
||||
{
|
||||
const auto target_worker_id = (worker_id + i) % _count_workers;
|
||||
available -= task_buffer.fill(_queues[target_worker_id].get<P>(), available);
|
||||
|
||||
if (available == 0U)
|
||||
{
|
||||
return task_buffer.max_size();
|
||||
}
|
||||
}
|
||||
|
||||
return task_buffer.max_size() - available;
|
||||
}
|
||||
|
||||
private:
|
||||
using MPSC = queue::PriorityQueue<queue::MPSC<TaskInterface>, priority::low, priority::normal>;
|
||||
|
||||
const std::uint16_t _worker_id;
|
||||
const std::uint16_t _count_workers;
|
||||
|
||||
// One queue per worker.
|
||||
std::array<MPSC, config::max_cores()> _queues;
|
||||
};
|
||||
|
||||
} // namespace mx::tasking
|
||||
42
repos/ealanos/src/lib/mx/tasking/task_squad.cpp
Normal file
42
repos/ealanos/src/lib/mx/tasking/task_squad.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "task_squad.h"
|
||||
#include "runtime.h"
|
||||
|
||||
using namespace mx::tasking;
|
||||
|
||||
void TaskSquad::flush() noexcept
|
||||
{
|
||||
auto [first, last] = this->_remote_queue.pop();
|
||||
if (first != nullptr)
|
||||
{
|
||||
if (last != nullptr)
|
||||
{
|
||||
this->_local_queue.push_back(first, last);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_local_queue.push_back(first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TaskResult TaskSquadSpawnTask::execute(std::uint16_t worker_id)
|
||||
{
|
||||
this->_task_squad.flush();
|
||||
|
||||
/// Get all tasks.
|
||||
auto [first, last] = this->_task_squad._local_queue.pop();
|
||||
if (first != nullptr)
|
||||
{
|
||||
if (last != nullptr)
|
||||
{
|
||||
runtime::spawn(*first, *last, worker_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
first->annotate(annotation::execution_destination::local);
|
||||
runtime::spawn(*first, worker_id);
|
||||
}
|
||||
}
|
||||
|
||||
return TaskResult::make_remove();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user