Tutorial 4: Compare Schedulers¶
Systematic comparison of HEFT vs CPOP vs Round Robin across multiple scenarios, with statistical analysis using multiple seeds.
What You Will Learn¶
- Run the same scenario with all three scheduling algorithms
- Understand scheduler strengths and weaknesses on different DAG structures
- Use multiple seeds for statistical comparison
- Analyze results across different DAG structures using Python scripts
Prerequisites¶
- ncsim installed (
pip install -e .) - Three built-in scenarios available in
scenarios/ - Python 3.10+ with the
jsonandstatisticsstandard library modules
Step 1: Choose Test Scenarios¶
We will use three built-in scenarios that stress different aspects of the scheduling problem:
| Scenario | File | Nodes | Tasks | Characteristics |
|---|---|---|---|---|
| Simple Demo | demo_simple.yaml |
2 | 2 | Minimal chain -- one dependency, trivial |
| Parallel Spread | parallel_spread.yaml |
5 | 10 | Fan-out/fan-in -- 8 parallel tasks |
| Bandwidth Contention | bandwidth_contention.yaml |
3 | 3 | Shared link -- contention-heavy |
Why these three?
Each scenario isolates a different scheduling challenge. Simple Demo is a baseline where all schedulers should perform similarly. Parallel Spread rewards schedulers that balance load across heterogeneous nodes. Bandwidth Contention tests how schedulers handle shared network resources.
Step 2: Run All Combinations¶
Run each scenario with each of the three schedulers. We use widest_path
routing to ensure multi-hop scenarios work correctly:
for scenario in demo_simple parallel_spread bandwidth_contention; do
for sched in heft cpop round_robin; do
ncsim --scenario "scenarios/${scenario}.yaml" \
--output "results/tutorial4/${scenario}_${sched}" \
--scheduler "$sched" \
--routing widest_path
done
done
This produces 9 output directories (3 scenarios x 3 schedulers), each
containing metrics.json, trace.jsonl, and scenario.yaml.
Check the output
After the loop completes, verify that all 9 directories were created:
You should see directories like demo_simple_heft,
demo_simple_cpop, demo_simple_round_robin, and so on.
Step 3: Collect Results¶
Use this Python script to extract makespans from all metrics.json files
and build a comparison table:
import json
import os
scenarios = ["demo_simple", "parallel_spread", "bandwidth_contention"]
schedulers = ["heft", "cpop", "round_robin"]
base_dir = "results/tutorial4"
# Collect makespans
results = {}
for scenario in scenarios:
results[scenario] = {}
for sched in schedulers:
metrics_path = os.path.join(base_dir, f"{scenario}_{sched}", "metrics.json")
with open(metrics_path) as f:
metrics = json.load(f)
results[scenario][sched] = metrics["makespan"]
# Print comparison table
print(f"{'Scenario':<25} {'HEFT':>10} {'CPOP':>10} {'Round Robin':>12} {'Winner':>12}")
print("-" * 72)
for scenario in scenarios:
makespans = results[scenario]
winner = min(makespans, key=makespans.get)
print(f"{scenario:<25} {makespans['heft']:>10.3f} {makespans['cpop']:>10.3f} "
f"{makespans['round_robin']:>12.3f} {winner:>12}")
Save this as compare_schedulers.py and run it:
Step 4: Analyze Results¶
Simple Demo (2 tasks, chain)¶
With only two tasks and two nodes, there is very little room for scheduling decisions. HEFT typically assigns both tasks to the faster node to avoid transfer overhead. CPOP does the same -- the critical path is the entire DAG, and it maps everything to the fastest processor. Round Robin cycles tasks across nodes, potentially introducing an unnecessary transfer.
Expected outcome: HEFT and CPOP produce identical makespans. Round Robin may match them or be slightly worse.
Parallel Spread (10 tasks, fan-out/fan-in)¶
This scenario has 8 independent parallel tasks between a root and a sink. The 5 nodes have heterogeneous compute capacities (80, 90, 100, 90, 80 units/s). A good scheduler will distribute the 8 parallel tasks across all nodes proportionally to their speeds.
- HEFT evaluates each task independently using Earliest Finish Time, spreading work across all available nodes.
- CPOP concentrates the critical path on the fastest node. Since the parallel tasks form multiple paths of equal length, the critical path selection may not provide an advantage.
- Round Robin distributes tasks cyclically without considering node speed or transfer costs.
Expected outcome: HEFT produces the best makespan by exploiting heterogeneity. CPOP is close but may over-concentrate work. Round Robin is the worst because it ignores node capacity differences.
Bandwidth Contention (3 tasks, shared link)¶
Three tasks with pinned placement force two concurrent transfers through
a single shared link. The scheduler's choice is constrained by the
pinned_to fields, so all three schedulers produce identical results.
Expected outcome: All schedulers produce the same makespan because
the placement is fully determined by pinned_to constraints.
Pinned tasks override the scheduler
When tasks have pinned_to set, the scheduler cannot change their
placement. This scenario tests the simulation engine's bandwidth
sharing, not the scheduler's intelligence.
Summary Table¶
| Scenario | HEFT | CPOP | Round Robin | Winner |
|---|---|---|---|---|
| demo_simple | Best or tied | Best or tied | Same or worse | HEFT / CPOP |
| parallel_spread | Best | Close second | Worst | HEFT |
| bandwidth_contention | Tied | Tied | Tied | All equal |
Step 5: Statistical Comparison with Multiple Seeds¶
A single run may not tell the full story. When shadow fading or other stochastic elements are enabled, running with multiple seeds provides statistical confidence. Even for deterministic scenarios, sweeping seeds is good practice to verify consistency.
Run each scenario-scheduler combination with seeds 1 through 10:
for scenario in demo_simple parallel_spread; do
for sched in heft cpop round_robin; do
for seed in $(seq 1 10); do
ncsim --scenario "scenarios/${scenario}.yaml" \
--output "results/tutorial4/sweep/${scenario}_${sched}_s${seed}" \
--scheduler "$sched" \
--routing widest_path \
--seed "$seed"
done
done
done
Number of runs
This loop produces 60 simulation runs (2 scenarios x 3 schedulers x 10 seeds). Each run completes in under a second, so the total wall time is modest.
Compute Mean and Standard Deviation¶
Use this script to aggregate results across seeds:
import json
import os
from statistics import mean, stdev
scenarios = ["demo_simple", "parallel_spread"]
schedulers = ["heft", "cpop", "round_robin"]
seeds = range(1, 11)
base_dir = "results/tutorial4/sweep"
print(f"{'Scenario':<25} {'Scheduler':<14} {'Mean':>10} {'Std Dev':>10} {'Min':>10} {'Max':>10}")
print("-" * 82)
for scenario in scenarios:
for sched in schedulers:
makespans = []
for seed in seeds:
path = os.path.join(
base_dir, f"{scenario}_{sched}_s{seed}", "metrics.json"
)
with open(path) as f:
metrics = json.load(f)
makespans.append(metrics["makespan"])
avg = mean(makespans)
sd = stdev(makespans) if len(makespans) > 1 else 0.0
lo = min(makespans)
hi = max(makespans)
print(f"{scenario:<25} {sched:<14} {avg:>10.3f} {sd:>10.4f} {lo:>10.3f} {hi:>10.3f}")
print()
Save this as sweep_analysis.py and run it:
Interpreting standard deviation
For deterministic scenarios (no shadow fading), all seeds produce the
same makespan, so the standard deviation is 0. When
shadow_fading_sigma > 0, the standard deviation reflects how much
the wireless environment affects performance.
Step 6: Interpret the Results¶
When Does HEFT Win?¶
HEFT is the best general-purpose scheduler. It evaluates every task on every node and selects the placement that minimizes the Earliest Finish Time. This makes it particularly strong when:
- The network has heterogeneous node capacities
- The DAG has multiple independent paths that can be parallelized
- Communication costs are significant and co-locating tasks helps
When Does CPOP Win?¶
CPOP excels in specific conditions:
- The DAG has a dominant critical path (one long chain of dependent tasks that determines the makespan)
- One node is significantly faster than the others
- Running the critical path entirely on the fastest node avoids inter-node transfer overhead
CPOP can underperform HEFT
When the DAG has multiple paths of similar length, CPOP may overload the fast processor with critical-path tasks while leaving other nodes idle. HEFT's per-task EFT evaluation avoids this imbalance.
When Are They Equivalent?¶
HEFT and CPOP produce identical results when:
- The scenario is trivially small (1--2 tasks)
- All tasks are pinned to specific nodes (
pinned_to) - The network is homogeneous (all nodes have equal capacity)
Round Robin as Baseline¶
Round Robin assigns tasks in cyclic order without considering compute capacity, data dependencies, or transfer costs. It exists solely to provide a lower bound on scheduler intelligence. In any non-trivial scenario, HEFT and CPOP should outperform Round Robin.
Summary¶
| Scheduler | Strengths | Weaknesses | Best For |
|---|---|---|---|
| HEFT | Communication-aware, exploits heterogeneity, parallelism | Slightly higher scheduling overhead | General-purpose default |
| CPOP | Optimizes dominant critical path, minimizes critical-path transfers | Can overload one node, ignores parallel paths | Single dominant critical path + one fast node |
| Round Robin | Simple, predictable, fast to compute | Ignores everything -- capacity, data, topology | Baseline comparisons only |
Recommendation: Use HEFT as the default scheduler. Switch to CPOP only when you have a clear dominant critical path and a single fast node. Use Round Robin exclusively as a comparison baseline.
Next Steps¶
- Tutorial 5: Viz Walkthrough -- Visualize these results in the web UI
- Scheduling Concepts -- Deep dive into HEFT, CPOP, and Round Robin algorithms
- Batch Experiments -- Automate large-scale parameter sweeps