summaryrefslogtreecommitdiff
path: root/experiments/crossover_hardware.py
blob: 6ace65584be1e71e9ae1ce93add1654292527de3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/usr/bin/env python3
"""Hardware profiles shared by portable crossover launchers and audits."""
import os
import subprocess


PROFILES = {
    "timan107_gtx1080": {
        "allowed_physical_gpu_indices": [5, 7],
        "allowed_device_names": ["NVIDIA GeForce GTX 1080"],
    },
    "a6000": {
        "allowed_physical_gpu_indices": None,
        "allowed_device_names": ["NVIDIA RTX A6000"],
    },
}
DEFAULT_PROFILE = "timan107_gtx1080"


def profile_choices():
    return tuple(PROFILES)


def policy(profile, physical_gpu_index=None):
    if profile not in PROFILES:
        raise ValueError(f"unknown crossover hardware profile: {profile}")
    configured = PROFILES[profile]
    allowed = configured["allowed_physical_gpu_indices"]
    if allowed is None:
        if physical_gpu_index is None:
            raise ValueError(
                f"{profile} policy requires a resolved physical GPU index"
            )
        allowed = [int(physical_gpu_index)]
    return {
        "profile": profile,
        "allowed_physical_gpu_indices": list(allowed),
        "allowed_device_names": list(configured["allowed_device_names"]),
        "single_gpu_per_process": True,
    }


def _query_physical_gpus():
    query = subprocess.run(
        [
            "nvidia-smi",
            "--query-gpu=index,uuid,name,memory.total",
            "--format=csv,noheader,nounits",
        ],
        check=True,
        capture_output=True,
        text=True,
    ).stdout.splitlines()
    rows = {}
    for line in query:
        index, uuid, name, memory = [
            value.strip() for value in line.split(",", 3)
        ]
        rows[index] = {
            "uuid": uuid,
            "name": name,
            "total_memory_mib": int(memory),
        }
    return rows


def physical_gpu_report(profile, dry_run=False):
    visible = os.environ.get("CUDA_VISIBLE_DEVICES")
    if dry_run:
        return {
            "hardware_profile": profile,
            "cuda_visible_devices": visible,
            "physical_gpu_index": None,
            "physical_gpu_uuid": None,
            "physical_gpu_name": None,
            "total_memory_mib": None,
        }
    if visible is None or not visible.isdigit():
        raise RuntimeError(
            "formal crossover jobs require CUDA_VISIBLE_DEVICES to contain "
            "one physical numeric GPU index"
        )
    physical_index = int(visible)
    hardware_policy = policy(profile, physical_index)
    if physical_index not in hardware_policy["allowed_physical_gpu_indices"]:
        raise RuntimeError(
            f"physical GPU {physical_index} is not allowed by {profile}"
        )
    rows = _query_physical_gpus()
    if visible not in rows:
        raise RuntimeError(f"physical GPU {visible} not found")
    row = rows[visible]
    if row["name"] not in hardware_policy["allowed_device_names"]:
        raise RuntimeError(
            f"{profile} requires one of "
            f"{hardware_policy['allowed_device_names']}, found {row['name']}"
        )
    return {
        "hardware_profile": profile,
        "cuda_visible_devices": visible,
        "physical_gpu_index": physical_index,
        "physical_gpu_uuid": row["uuid"],
        "physical_gpu_name": row["name"],
        "total_memory_mib": row["total_memory_mib"],
    }


def policy_for_report(profile, report):
    return policy(profile, report["physical_gpu_index"])


def assert_hardware_report(report, hardware_policy):
    assert report["hardware_profile"] == hardware_policy["profile"]
    assert (
        report["physical_gpu_index"]
        in hardware_policy["allowed_physical_gpu_indices"]
    )
    assert report["physical_gpu_uuid"]
    assert report["physical_gpu_name"] in hardware_policy[
        "allowed_device_names"
    ]
    assert report["cuda_visible_devices"] == str(
        report["physical_gpu_index"]
    )