Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
96cd379
Added: single-thread implementation
phtevesn Apr 12, 2026
a75ac18
Unconfirmed: adjustments to BBwithSpill and REgister objects.
phtevesn Apr 12, 2026
74116f5
Added: PCPU_FindOneSchedule
phtevesn Apr 12, 2026
e57be44
Added: 2 other PCPU functionns
phtevesn Apr 12, 2026
4099527
temp
phtevesn Apr 12, 2026
11d759a
Tested: BBWithSpill and Register work on single thread.
phtevesn Apr 12, 2026
7caeedd
temp
phtevesn Apr 13, 2026
7af475c
Attempt 1: Allocation of ACOScheduler variables. PCPUSchedInstVars wi…
phtevesn Apr 18, 2026
46f52e1
Attempt 1: edited allocation functions
phtevesn Apr 18, 2026
fe729e9
Attempt 1: Benchmarks ran initially I forgot to commit, made some cha…
phtevesn Apr 18, 2026
56f8cc8
temp
phtevesn Apr 18, 2026
cc3f3fe
Attempt 1: benchmarks runnable, bbwith spill independent and acoready…
phtevesn Apr 19, 2026
3525a0a
Attempt: everything up to crntSlotnum in PCPUACOSchedVars does not re…
phtevesn Apr 25, 2026
bac8a7f
Edited: Runs a few schedules, once it running the ants there is a mal…
phtevesn Apr 25, 2026
757db1c
Edited: believed to fully have adjused the ACOScheduler class now mus…
phtevesn Apr 26, 2026
eb2554b
Added: Data structure for SchedInstruction class
phtevesn Apr 26, 2026
efd4c13
Edited: Applied instruction functions, stil broken
phtevesn Apr 26, 2026
138fb2d
temp
phtevesn Apr 26, 2026
48f5e08
temp
phtevesn May 3, 2026
498ea4d
Added: Accurate MaxPriorityInv and commeted out number of ants termin…
phtevesn May 9, 2026
9591486
temp;
phtevesn May 9, 2026
c9728a4
Added: New score function, errors remain.
phtevesn May 10, 2026
f34c9d8
fix: add recursive_mutex to random number generator
mocha8686 May 9, 2026
30bd74f
fix: remove uninitialized int usages and add default edge labels to 0
mocha8686 May 9, 2026
428e805
fix: cv-unqualify mutex
mocha8686 May 10, 2026
15a7cc3
fix: pass reference to function as default instead
mocha8686 May 10, 2026
8366c5f
fix: use 2 threads
mocha8686 May 11, 2026
8b557bb
fix: stabilize CPU-parallel ACO and switch to 8-thread execution
HornetSys May 23, 2026
88b7abb
Update - remove the unnecessary update and change print to Logger:Info
HornetSys May 28, 2026
aee700e
feat: replace per-iteration thread spawn with persistent CPU thread pool
HornetSys May 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 50 additions & 1 deletion example/optsched-cfg/sched.ini
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ USE_TWO_PASS NO
HEUR_ENABLED YES
# ACO_ENABLED is the Ant Colony Optimization scheduler.
ACO_ENABLED YES
# MO_ENABLED toggles multiple occupancy schedule generation.
# If YES, scheduler explores multiple occupancy points; otherwise it uses a single occupancy.
MO_ENABLED NO
# ENUM_ENABLED is the Branch and Bound scheduler.
ENUM_ENABLED NO

Expand Down Expand Up @@ -69,6 +72,21 @@ SECOND_PASS_LENGTH_TIMEOUT 0
# BLOCK : use the time limits in the above fields as is
TIMEOUT_PER INSTR

# Whether to limit occupancy when scheduling.
# YES : apply occupancy limiting logic
# NO : do not apply occupancy limiting
SHOULD_LIMIT_OCCUPANCY NO

# Target occupancy limit when SHOULD_LIMIT_OCCUPANCY is YES.
# 0 means unlimited.
OCCUPANCY_LIMIT 0

# How to determine the occupancy limit. Valid values:
# NONE : no occupancy limit source is used
# HEURISTIC : use a heuristic to decide whether to limit occupancy
# FILE : read the limit from occupancy_limits.ini
OCCUPANCY_LIMIT_SOURCE NONE

# The heuristic used for the list scheduler. Valid values are any combination of:
# CP: critical path
# LUC: last use count
Expand All @@ -77,6 +95,8 @@ TIMEOUT_PER INSTR
# NID: node ID
# LLVM: LLVM’s default list scheduler order
# Example: LUC_CP_NID
LIST_HEURISTIC LLVM
# Legacy key, supported for backward compatibility.
HEURISTIC LLVM

# The heuristic used for the enumerator. If the two pass scheduling
Expand Down Expand Up @@ -155,6 +175,12 @@ ACO_TOURNAMENT NO
#use fixd value for bias or not. If not, use ratio instaed
ACO_USE_FIXED_BIAS NO

# Weighted second-pass comparison; only meaningful when USE_TWO_PASS is YES.
# VALUES:
# YES
# NO
USE_WEIGHTED_SECOND_PASS NO

#Fixed number of evaporation
ACO_FIXED_BIAS 20
ACO2P_FIXED_BIAS 20
Expand All @@ -169,6 +195,24 @@ ACO2P_DECAY_FACTOR 0.2

ACO_ANT_PER_ITERATION 10

# ACO stop iteration ranges, selected by problem size.
# These control how many stagnant iterations are allowed before ACO stops.
# If unset, defaults are: 10, 20, 50, 100 for ranges 1..4.
ACO_STOP_ITERATIONS_RANGE1 10
ACO_STOP_ITERATIONS_RANGE2 20
ACO_STOP_ITERATIONS_RANGE3 50
ACO_STOP_ITERATIONS_RANGE4 100
ACO2P_STOP_ITERATIONS_RANGE1 10
ACO2P_STOP_ITERATIONS_RANGE2 20
ACO2P_STOP_ITERATIONS_RANGE3 50
ACO2P_STOP_ITERATIONS_RANGE4 100

# Upper bound type for the ACO ready list.
# Options:
# NO
# MIN_DEGREE
ACO_READY_LIST_UB NO

ACO_TRACE NO

#If you want to use pheromone table debugging set ACO_DBG_REGIONS
Expand Down Expand Up @@ -198,7 +242,10 @@ ACO2P_STOP_ITERATIONS 50
LLVM_MUTATIONS NO

# Whether or not to run ACO on the device
DEV_ACO YES
DEV_ACO NO

# Number of host ACO ants to use when DEV_ACO is NO
HOST_ANTS 8

# (Chris) If using the SLIL cost function, enabling this option
# will force the B&B scheduler to skip DAGs with zero PERP.
Expand Down Expand Up @@ -297,3 +344,5 @@ HIST_TABLE_HASH_BITS 16
CYCLES_FROM_OPTIMAL 0
# Threshold of when to skip ACO, determined by how deeply inserted in a loop list schedule is (-1 to disable this filter)
LOOP_DEPTH -1

RANDOM_SEED 0
123 changes: 123 additions & 0 deletions include/opt-sched/Scheduler/aco.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,19 @@ Last Update: Jan. 2020
#include "opt-sched/Scheduler/ready_list.h"
#include "opt-sched/Scheduler/device_vector.h"
#include "llvm/ADT/ArrayRef.h"
#include <atomic>
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <random>
#include <thread>
#include <utility>
#include <vector>
#include <hip/hip_runtime.h>

struct CPUThreadPool;

namespace llvm {
namespace opt_sched {

Expand Down Expand Up @@ -50,6 +60,77 @@ struct BlockDecision {
int blockOccupancyNum; // range 0-(difference in occupancy from AMD's schedule)
};

struct alignas(64) ParallelCPUVars {
InstCount crntCycleNum_;
InstCount crntSlotNum_;
InstCount crntSpillCost_;
InstCount crntStepNum_;
InstCount peakSpillCost_;
InstCount totSpillCost_;
InstCount slilSpillCost_;
InstCount dynamicSlilLowerBound_;
int schduldInstCnt_;
int schduldEntryInstCnt_;
int schduldExitInstCnt_;

WeightedBitVector *liveRegs_; // array[regTypeCnt_]
WeightedBitVector *livePhysRegs_; // array[regTypeCnt_]
InstCount *peakRegPressures_; // array[regTypeCnt_]
InstCount *spillCosts_; // array[instCnt]
int *sumOfLiveIntervalLengths_; // array[regTypeCnt_]
SmallVector<unsigned, 8> regPressures_; // or just unsigned*
};


struct alignas(64) PCPUACOSchedVars {
//ACOScheduler
ACOReadyList *readyLs;
InstCount MaxScoringInst;
int RP0OrPositiveCount;

//ConstrainedScheduler:InstSchedule
InstCount schduldInstCnt;
bool isCrntCycleBlkd;
InstCount crntCycleNum;
InstCount crntSlotNum;
int16_t rsrvSlotCnt;
ReserveSlot *rsrvSlots;
int16_t *avlblSlotsInCrntCycle;

pheromone_t MaxPriorityInv;
KeysHelper1 *kHelper1;
std::mt19937 rng;

/*
void ConstrainedScheduler::SchdulInst_(SchedInstruction *inst, InstCount)
schduldInstCnt_
isCrntCycleBlkd_
void ConstrainedScheduler::DoRsrvSlots_(SchedInstruction *inst)
rsrvSlots_
rsrvSlotCnt_
crntCycleNum_
crntSlotNum_

void ConstrainedScheduler::UpdtSlotAvlblty_(SchedInstruction *inst)
avlblSlotsInCrntCycle_;

isSchedComplete ??? -> requires investigation what is totInstCnt

bool ConstrainedScheduler::ChkInstLglty_(SchedInstruction *inst) const
isCrntCycleBlkd_

bool ConstrainedScheduler::MovToNxtSlot_(SchedInstruction *inst)
crntCycleNum_
crntSlotNum_
crntRealSlotNum_

void ConstrainedScheduler::InitNewCycle_()
isCrntCycleBlkd_
avlblSlotsInCrntCycle_
*/
//may need multiple khelpers as well unsure
};

class ACOScheduler : public ConstrainedScheduler {
public:
ACOScheduler(DataDepGraph *dataDepGraph, MachineModel *machineModel,
Expand Down Expand Up @@ -77,6 +158,40 @@ class ACOScheduler : public ConstrainedScheduler {
void AllocDevArraysForParallelACO();
// Finds a schedule, if passed a device side schedule, use that instead
// of creating a new one


InstSchedule *FindManyCPUSchedule(InstCount RPTarget);
InstSchedule *PCPU_FindOneSchedule(InstCount RPTarget,
int thread,
PCPUACOSchedVars &pcpu_sched_vars,
ParallelCPUVars &pcpu,
std::atomic<int> &antsTerminated,
int kernelNum = -1);
InstCount PCPU_SelectInstruction(SchedInstruction *lastInst, InstCount totalStalls,
SchedRegion *rgn, bool &unnecessarilyStalling,
bool closeToRPTarget, bool currentlyWaiting,
int thread,
PCPUACOSchedVars &pcpu_sched_vars,
ParallelCPUVars &pcpu,
int kernelNum = -1);
inline void PCPU_UpdateACOReadyList(SchedInstruction *inst, bool IsSecondPass,
int thread,
PCPUACOSchedVars &pcpu_sched_vars,
int heurChoice = 0);
PCPUACOSchedVars *AllocPCPUACOSchedVars(int numThreads);
void FreePCPUACOSchedVars(PCPUACOSchedVars *pcpu_sched_vars, int numThreads);

void PCPU_DoRsrvSlots_(SchedInstruction *inst, PCPUACOSchedVars &pcpu_sched_vars);
void PCPU_SchdulInst_(SchedInstruction *inst, PCPUACOSchedVars &pcpu_sched_vars);
void PCPU_UpdtSlotAvlblty_(SchedInstruction *inst, PCPUACOSchedVars &pcpu_sched_vars);
bool PCPU_IsSchedComplete_(PCPUACOSchedVars &pcpu_sched_vars);
bool PCPU_ChkInstLglty_(SchedInstruction *inst, PCPUACOSchedVars &pcpu_sched_vars) const;
bool PCPU_MovToNxtSlot_(SchedInstruction *inst, PCPUACOSchedVars &pcpu_sched_vars);
void PCPU_InitNewCycle_(PCPUACOSchedVars &pcpu_sched_vars);
void PCPU_InitSchedInsts(int numThreads);
void PCPU_ResetSchedInsts(int numThreads);
void PCPU_FreeSchedInsts(int numThreads);

__host__ __device__
InstSchedule *FindOneSchedule(InstCount RPTarget,
InstSchedule *dev_schedule = NULL, int kernelNum = -1);
Expand Down Expand Up @@ -129,6 +244,9 @@ class ACOScheduler : public ConstrainedScheduler {
pheromone_t &Pheromone(InstCount from, InstCount to, int kernelNum = 0);
__host__ __device__
pheromone_t Score(InstCount FromId, InstCount ToId, HeurType ToHeuristic, bool IsFirstPass, int kernelNum = 0);

pheromone_t PCPU_Score(InstCount FromId, InstCount ToId, HeurType ToHeuristic, bool IsFirstPass, PCPUACOSchedVars &pcpu_sched_vars, int kernelNum = 0);

DCF_OPT ParseDCFOpt(const std::string &opt);
__host__ __device__
InstCount SelectInstruction(SchedInstruction *lastInst, InstCount totalStalls,
Expand Down Expand Up @@ -190,6 +308,11 @@ class ACOScheduler : public ConstrainedScheduler {
SchedPriorities priorities1_;
SchedPriorities priorities2_;

// Pre-built per-instruction successor list (successor ptr + prdcsrNum).
// Populated before PCPU threads launch to avoid cursor race on scsrLst_.
std::vector<std::vector<std::pair<SchedInstruction *, InstCount>>> instScsrs_;

std::unique_ptr<CPUThreadPool> cpuPool_;
};

} // namespace opt_sched
Expand Down
34 changes: 34 additions & 0 deletions include/opt-sched/Scheduler/bb_spill.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Last Update: Apr. 2011
#include <vector>
#include <hip/hip_runtime.h>

#define RUN_PARALLEL_CPU 1

namespace llvm {
namespace opt_sched {

Expand All @@ -29,6 +31,7 @@ class BitVector;

class BBWithSpill : public SchedRegion {
private:
ParallelCPUVars *pcpu_vars_;
LengthCostEnumerator *enumrtr_;

InstCount crntSpillCost_;
Expand Down Expand Up @@ -267,6 +270,37 @@ class BBWithSpill : public SchedRegion {
// size_t calculateMemoryNeeded() {
// return regTypeCnt_ * sizeof(WeightedBitVector) * numThreads * 2;
// }

void AllocParallelCPUVars(int numThreads);
void ResetParallelCPUVars(int numThreads);
void FreeParallelCPUVars(int numThreads);

void PCPU_CmputCrntSpillCost_(ParallelCPUVars &pcpu);
void PCPU_UpdateSpillInfoForSchdul_(SchedInstruction *inst,
bool trackCnflcts,
ParallelCPUVars &pcpu,
int thread);
void PCPU_SchdulInst(SchedInstruction *inst, InstCount cycleNum,
InstCount slotNum, bool trackCnflcts,
ParallelCPUVars &pcpu,
int thread);

InstCount PCPU_GetCrntSpillCost(ParallelCPUVars &pcpu);
InstCount PCPU_ReturnPeakSpillCost(ParallelCPUVars &pcpu);
InstCount PCPU_getOccupancy(ParallelCPUVars &pcpu);
bool PCPU_closeToRPConstraint(ParallelCPUVars &pcpu, int blockOccupancyNum = 0);
bool PCPU_IsRPHigh(int regType, ParallelCPUVars &pcpu) const;

InstCount PCPU_CmputNormCost_(InstSchedule *sched, COST_COMP_MODE compMode,
InstCount &execCost, bool trackCnflcts,
ParallelCPUVars &pcpu);
InstCount PCPU_CmputCost_(InstSchedule *sched, COST_COMP_MODE compMode,
InstCount &execCost, bool trackCnflcts,
ParallelCPUVars &pcpu);
void PCPU_UpdateScheduleCost(InstSchedule *sched, ParallelCPUVars &pcpu);
InstCount PCPU_CmputCostForFunction(SPILL_COST_FUNCTION SpillCF, ParallelCPUVars &pcpu);
ParallelCPUVars &GetPCPUVars(int thread);

protected:
// (Chris)
inline virtual const int *GetSLIL_() const {
Expand Down
4 changes: 2 additions & 2 deletions include/opt-sched/Scheduler/graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -628,13 +628,13 @@ inline GraphNode *GraphNode::GetNxtPrdcsr(UDT_GLABEL &label) {

__host__
inline GraphNode *GraphNode::GetFrstScsr() {
UDT_GLABEL label;
UDT_GLABEL label{};
return GetFrstScsr(label);
}

__host__
inline GraphNode *GraphNode::GetNxtScsr() {
UDT_GLABEL label;
UDT_GLABEL label{};
return GetNxtScsr(label);
}

Expand Down
15 changes: 15 additions & 0 deletions include/opt-sched/Scheduler/register.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ namespace opt_sched {
// Forward Declaration to treat circular dependence
class SchedInstruction;

struct alignas(64) AlignedInt {
int value;
};

// Represents a a single register of a certain type and tracks the number of
// times this register is defined and used.
class Register {
Expand Down Expand Up @@ -128,6 +132,14 @@ class Register {
// Calls hipFree on all arrays/objects that were allocated with hipMalloc
void FreeDevicePointers();

void PCPU_AddCrntUse(int threadIdx);
void PCPU_ResetCrntUseCnt(int threadIdx);
bool PCPU_IsLive(int threadIdx) const;
void AllocParallelCPURegs(int numThreads);
void ResetParallelCPURegs(int numThreads);
void FreeParallelCPURegs();


private:
int16_t type_;
int num_;
Expand All @@ -136,6 +148,9 @@ class Register {
int crntUseCnt_;
// Device array which holds a separate crntUseCnt_ for each thread
int *dev_crntUseCnt_;
//Parallel cpu array to hold separate crntUseCnt_
AlignedInt *pcpu_crntUseCnt_;

int crntLngth_;
int physicalNumber_;
BitVector conflicts_;
Expand Down
Loading