Program Listing for File Cpu.hpp¶
↰ Return to documentation for file (include/sgpl/hardware/Cpu.hpp)
#pragma once
#ifndef SGPL_HARDWARE_CPU_HPP_INCLUDE
#define SGPL_HARDWARE_CPU_HPP_INCLUDE
#include <array>
#include <cassert>
#include <utility>
#include "../utility/RingResevoir.hpp"
#include "Core.hpp"
#include "JumpTable.hpp"
namespace sgpl {
template<typename Spec>
class Cpu {
using core_t = sgpl::Core<Spec>;
using global_jump_table_t
= sgpl::JumpTable<Spec, typename Spec::global_matching_t>;
struct impl_ {
sgpl::RingResevoir<core_t, Spec::num_cores> scheduler;
size_t active_core_idx{};
std::array<global_jump_table_t, Spec::num_global_jump_tables>
global_jump_tables{};
// total number of instructions executed over the lifetime of the object
size_t lifetime_cycle_clock{};
} data;
using tag_t = typename Spec::tag_t;
void RefreshCoreGlobalJumpTablePtrs() noexcept {
for (size_t i{}; i < data.scheduler.GetCapacity(); ++i) {
data.scheduler.GetBuffer()[i].SetGlobalJumpTables(
data.global_jump_tables
);
}
}
public:
Cpu() noexcept { RefreshCoreGlobalJumpTablePtrs(); }
Cpu(const Cpu& other) noexcept : data(other.data) {
RefreshCoreGlobalJumpTablePtrs();
}
Cpu(Cpu&& other) noexcept : data( std::move(other.data) ) {
RefreshCoreGlobalJumpTablePtrs();
}
Cpu& operator=(const Cpu& other) noexcept { return *this = Cpu(other); }
Cpu& operator=(Cpu&& other) noexcept {
std::swap(data, other.data);
return *this;
}
void ActivateNextCore() noexcept {
assert( GetNumBusyCores() );
++data.active_core_idx %= GetNumBusyCores();
}
bool TryActivateNextCore() noexcept {
if ( HasActiveCore() ) { ActivateNextCore(); return true; }
else { assert( data.active_core_idx == 0 ); return false; }
}
void ActivatePrevCore() noexcept {
assert( GetNumBusyCores() );
data.active_core_idx += GetNumBusyCores() - 1;
data.active_core_idx %= GetNumBusyCores();
}
bool TryActivatePrevCore() noexcept {
if ( HasActiveCore() ) { ActivatePrevCore(); return true; }
else { assert( data.active_core_idx == 0 ); return false; }
}
__attribute__ ((hot))
core_t& GetActiveCore() noexcept {
assert( HasActiveCore() );
return data.scheduler.Get( data.active_core_idx );
};
core_t& GetFreshestCore() noexcept {
assert( HasActiveCore() );
return data.scheduler.GetHead();
};
void KillActiveCore() noexcept {
assert( HasActiveCore() );
for ( const auto& req : GetActiveCore().fork_requests ) {
if ( !TryLaunchCore(req) ) break;
}
data.scheduler.Release(data.active_core_idx);
TryActivatePrevCore();
}
void KillStaleCore() noexcept {
assert( !HasFreeCore() );
data.scheduler.ReleaseTail();
// no need to activate prev core, killed core is idx 0
}
void DoLaunchCore() noexcept {
assert( HasFreeCore() );
auto& acquired = data.scheduler.Acquire();
acquired.Reset();
}
bool TryLaunchCore() noexcept {
if ( ! HasFreeCore() ) return false;
else { DoLaunchCore(); return true; }
}
void ForceLaunchCore() noexcept {
if ( ! HasFreeCore() ) KillStaleCore();
DoLaunchCore();
}
void DoLaunchCore( const tag_t& tag, const size_t jt_idx=0 ) noexcept {
assert( HasFreeCore() );
auto& acquired = data.scheduler.Acquire();
acquired.Reset();
acquired.JumpToGlobalAnchorMatch( tag, jt_idx );
}
bool TryLaunchCore( const tag_t& tag, const size_t jt_idx=0 ) noexcept {
if ( ! HasFreeCore() ) return false;
else { DoLaunchCore( tag, jt_idx ); return true; }
}
void ForceLaunchCore( const tag_t& tag, const size_t jt_idx=0 ) noexcept {
if ( ! HasFreeCore() ) KillStaleCore();
DoLaunchCore( tag, jt_idx );
}
size_t GetNumBusyCores() const noexcept { return data.scheduler.GetSize(); }
size_t GetNumFreeCores() const noexcept {
return data.scheduler.GetAvailableCapacity();
}
size_t GetMaxCores() const noexcept { return data.scheduler.GetCapacity(); }
__attribute__ ((hot))
bool HasActiveCore() const noexcept { return GetNumBusyCores(); }
__attribute__ ((hot))
bool HasFreeCore() const noexcept { return GetNumFreeCores(); }
void Reset() noexcept {
data.scheduler.Reset();
data.active_core_idx = {};
for ( auto& table : data.global_jump_tables ) table.Clear();
}
void InitializeAnchors(const sgpl::Program<Spec>& program) noexcept {
Reset();
for( size_t i{}; i < data.global_jump_tables.size() ; ++i ) {
data.global_jump_tables[i].InitializeGlobalAnchors(
program,
Spec::global_jump_table_inclusion_mods[ i ]
);
}
}
const core_t& GetCore( const size_t idx ) const noexcept {
return data.scheduler.Get( idx );
}
const global_jump_table_t& GetGlobalJumpTable( const size_t idx=0 )
const noexcept
{
return data.global_jump_tables[ idx ];
}
void DecayGlobalRegulators() noexcept {
for ( auto& gjt : data.global_jump_tables ) gjt.DecayRegulators();
}
void AdvanceCycleClock(const size_t amt) noexcept {
data.lifetime_cycle_clock += amt;
}
size_t GetCyclesSinceConstruction() const noexcept {
return data.lifetime_cycle_clock;
}
};
} // namespace sgpl
#endif // #ifndef SGPL_HARDWARE_CPU_HPP_INCLUDE