verilator/src/V3Scoreboard.h
Bartłomiej Chmiel ffe76717c6
Thread pool rewrite (#5161)
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
Signed-off-by: Bartłomiej Chmiel <bchmiel@antmicro.com>
Signed-off-by: Arkadiusz Kozdra <akozdra@antmicro.com>
Co-authored-by: Krzysztof Bieganski <kbieganski@antmicro.com>
Co-authored-by: Arkadiusz Kozdra <akozdra@antmicro.com>
Co-authored-by: Wilson Snyder <wsnyder@wsnyder.org>
2024-08-23 08:36:49 -04:00

146 lines
5.6 KiB
C++

// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Scoreboard for mtask coarsening
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-2024 by Wilson Snyder. This program is free software; you
// can redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
#ifndef VERILATOR_V3SCOREBOARD_H_
#define VERILATOR_V3SCOREBOARD_H_
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3PairingHeap.h"
//===============================================================================================
// V3Scoreboard is essentially a heap that can be hinted that some elements have changed keys, at
// which points those elements will be deferred as 'unknown' until the next 'rescore' call. We
// largely reuse the implementation of the slightly more generic PairingHeap, but we do rely on the
// internal structure of the PairingHeap so changing that class requires changing this.
//
// For efficiency, the elements themselves must be the heap nodes, by deriving them from
// V3Scoreboard<T_Elem, T_Key>::Node. This also means a single element can only be associated with
// a single scoreboard.
template <typename T_Elem, typename T_Key>
class V3Scoreboard final {
// TYPES
using Heap = PairingHeap<T_Key>;
public:
using Node = typename Heap::Node;
private:
using Link = typename Heap::Link;
// Note: T_Elem is incomplete here, so we cannot assert 'std::is_base_of<Node, T_Elem>::value'
// MEMBERS
Heap m_known; // The heap of entries with known scores
Link m_unknown; // List of entries with unknown scores
public:
// CONSTRUCTORS
explicit V3Scoreboard() = default;
~V3Scoreboard() = default;
private:
VL_UNCOPYABLE(V3Scoreboard);
// METHODSs
void addUnknown(T_Elem* nodep) {
// Just prepend it to the list of unknown entries
nodep->m_next.link(m_unknown.unlink());
m_unknown.linkNonNull(nodep);
// We mark nodes on the unknown list by making their child pointer point to themselves
nodep->m_kids.m_ptr = nodep;
}
public:
// Returns true if the element is present in the scoreboard, false otherwise. Every other
// method that takes a T_Elem* (except for 'add') has undefined behavior if the element is not
// in this scoreboard. Furthermore, this method is only valid if the element can only possibly
// be in this scoreboard. That is: if the element might be in another scoreboard, the behaviour
// of this method is undefined.
static bool contains(const T_Elem* nodep) { return nodep->m_ownerpp; }
// Add an element to the scoreboard. This will not be returned before the next 'rescore' call.
void add(T_Elem* nodep) {
#if VL_DEBUG
UASSERT(!contains(nodep), "Adding element to scoreboard that was already in a scoreboard");
#endif
addUnknown(nodep);
}
// Remove element from scoreboard.
void remove(T_Elem* nodep) {
if (nodep->m_kids.m_ptr == nodep) {
// Node is on the unknown list, replace with next
nodep->replaceWith(nodep->m_next.unlink());
return;
}
// Node is in the known heap, remove it
m_known.remove(nodep);
}
// Get the known element with the highest score (as we are using a max-heap), or nullptr if
// there are no elements with known entries. This does not automatically 'rescore'. The client
// must call 'rescore' appropriately to ensure all elements in the scoreboard are reflected in
// the result of this method.
T_Elem* best() const { return T_Elem::heapNodeToElem(m_known.max()); }
// Tell the scoreboard that this element's score may have changed. At the time of this call,
// the element's score becomes 'unknown' to the scoreboard. Unknown elements will not be
// returned by 'best until the next call to 'rescore'.
void hintScoreChanged(T_Elem* nodep) {
// If it's already in the unknown list, then nothing to do
if (nodep->m_kids.m_ptr == nodep) return;
// Otherwise it was in the heap, remove it
m_known.remove(nodep);
// Prepend it to the unknown list
addUnknown(nodep);
}
// True if we have elements with unknown score
bool needsRescore() const { return m_unknown; }
// True if the element's score is unknown, false otherwise.
static bool needsRescore(const T_Elem* nodep) { return nodep->m_kids.m_ptr == nodep; }
// For each element whose score is unknown, recompute the score and add to the known heap
void rescore() {
// Rescore and insert all unknown elements
for (Node *nodep = m_unknown.unlink(), *nextp; nodep; nodep = nextp) {
// Pick up next
nextp = nodep->m_next.ptr();
// Reset pointers
nodep->m_next.m_ptr = nullptr;
nodep->m_kids.m_ptr = nullptr;
nodep->m_ownerpp = nullptr;
// Re-compute the score of the element
T_Elem::heapNodeToElem(nodep)->rescore();
// re-insert into the heap
m_known.insert(nodep);
}
}
};
// ######################################################################
namespace V3ScoreboardBase {
void selfTest() VL_MT_DISABLED;
} // namespace V3ScoreboardBase
#endif // Guard