# /// script # requires-python = ">=3.10" # dependencies = [] # /// # ─── How to run ─── # python3 examples/computer-architecture/ooo/src/run_all.py """Finite rename/issue model; all instructions enter the window at t=0.""" from dataclasses import asdict, dataclass @dataclass(frozen=True, slots=True) class Instruction: name: str destination: str sources: tuple[str, ...] latency: int constant: int = 0 @dataclass(frozen=True, slots=True) class Renamed: name: str destination: int sources: tuple[int, ...] stale: int latency: int constant: int @dataclass(frozen=True, slots=True) class Issue: name: str issue: int complete: int value: int @dataclass(frozen=True, slots=True) class Schedule: width: int cycles: int events: tuple[Issue, ...] final_values: tuple[tuple[str, int], ...] def rename(program: tuple[Instruction, ...]) -> tuple[Renamed, ...]: """Capture source mappings before replacing the destination mapping.""" mapping = {f"r{i}": i for i in range(8)} result = [] for number, instruction in enumerate(program, 8): result.append(Renamed( instruction.name, number, tuple(mapping[source] for source in instruction.sources), mapping[instruction.destination], instruction.latency, instruction.constant, )) mapping[instruction.destination] = number return tuple(result) def schedule(program: tuple[Instruction, ...], width: int) -> Schedule: """Oldest-ready issue, unbounded units, completion precedes issue at t.""" assert width > 0 pending = list(rename(program)) ready_at = {i: 0 for i in range(8)} values = {i: i for i in range(8)} events = [] time = 0 while pending: issued = 0 for instruction in tuple(pending): if issued >= width: break if all(ready_at.get(source, 10**9) <= time for source in instruction.sources): value = sum(values[source] for source in instruction.sources) + instruction.constant done = time + instruction.latency values[instruction.destination] = value ready_at[instruction.destination] = done events.append(Issue(instruction.name, time, done, value)) pending.remove(instruction) issued += 1 time += 1 assert time < 1000, "finite model did not make progress" final = {f"r{i}": i for i in range(8)} for original, renamed in zip(program, rename(program)): final[original.destination] = values[renamed.destination] return Schedule(width, max(event.complete for event in events), tuple(events), tuple(final.items())) def cases() -> dict: # noqa: DICT_OK -- JSON artifact boundary program = ( Instruction("A", "r1", ("r2",), 4, 8), Instruction("B", "r3", ("r1", "r4"), 1), Instruction("C", "r1", ("r5",), 1, 15), Instruction("D", "r4", ("r6",), 1, 24), Instruction("E", "r7", ("r1", "r4"), 1), Instruction("F", "r2", ("r3", "r7"), 1), ) renamed = rename(program) assert renamed[1].sources == (8, 4) assert renamed[4].sources == (10, 11) assert renamed[2].stale == 8 schedules = tuple(schedule(program, width) for width in (1, 2, 4)) for result in schedules: assert dict(result.final_values)["r2"] == 64 events = {event.name: event for event in result.events} assert events["B"].issue >= events["A"].complete assert events["C"].issue < events["B"].issue assert tuple(result.cycles for result in schedules) == (6, 6, 6) independent = tuple(Instruction(f"I{i}", f"r{i}", (), 1, i) for i in range(1, 5)) independent_schedules = tuple(schedule(independent, width) for width in (1, 2, 4)) assert tuple(result.cycles for result in independent_schedules) == (4, 2, 1) return { "evidence": "教学时序模型", "program": [asdict(i) for i in program], "raw": ["A->B", "B->F", "C->E", "D->E", "E->F"], "war": ["A->F:r2", "B->C:r1", "B->D:r4"], "waw": ["A->C:r1"], "renamed": [asdict(i) for i in renamed], "schedules": [asdict(result) for result in schedules], "independent_schedules": [asdict(result) for result in independent_schedules], "critical_path": "A(4)+B(1)+F(1)=6; issue width alone cannot shorten it", } if __name__ == "__main__": import json print(json.dumps(cases(), ensure_ascii=False, indent=2))