Skip to content

Commit bc9a60b

Browse files
authored
fix: Upgrade JAX environment and fix workload compatibility (GoogleCloudPlatform#1158)
Due to a recent Jax upgrade, previous workload versions are no longer executable in the latest environment. Changes: - Updated base image to include the latest Jax, `tpu-info`, and `libtpu`. - Refactored workload code to ensure compatibility with the updated Jax API.
1 parent 3d92f8c commit bc9a60b

3 files changed

Lines changed: 41 additions & 28 deletions

File tree

dags/tpu_observability/tpu_info_format_validation_dags.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ def generate_second_node_pool_name(
353353
container_name="jax-tpu-worker",
354354
image=(
355355
"asia-northeast1-docker.pkg.dev/cienet-cmcs/yuna-docker/"
356-
"tpu-info:v0.5.1"
356+
"tpu-info:v0.8.1"
357357
),
358358
tpu_cores_per_pod=4,
359359
)

dags/tpu_observability/tpu_sdk_monitoring_validation_dag.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def validate_monitoring_sdk(info: node_pool.Info, pod_name: str) -> None:
131131
tpu_topology="4x4",
132132
container_name="jax-tpu-worker",
133133
image="asia-northeast1-docker.pkg.dev/cienet-cmcs/"
134-
"yuna-docker/tpu-info:v0.5.1",
134+
"yuna-docker/tpu-info:v0.8.1",
135135
tpu_cores_per_pod=4,
136136
)
137137

dags/tpu_observability/utils/jobset_util.py

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@
2727

2828
from airflow.decorators import task
2929
from airflow.exceptions import AirflowFailException
30-
from google.cloud.monitoring_v3 import types
31-
import kubernetes
3230

33-
from dags.tpu_observability.utils.node_pool_util import Info as node_pool_info
3431
from dags.tpu_observability.utils import subprocess_util as subprocess
3532
from dags.tpu_observability.utils.gcp_util import query_time_series
33+
from dags.tpu_observability.utils.node_pool_util import Info as node_pool_info
3634
from dags.tpu_observability.utils.time_util import TimeUtil
35+
from google.cloud.monitoring_v3 import types
36+
import kubernetes
3737
from xlml.utils import gke
3838

3939

@@ -58,25 +58,38 @@ class Workload:
5858
os.environ.setdefault("JAX_USE_PJIT", "true")
5959
jax.distributed.initialize()
6060
61+
idx = jax.process_index()
6162
global_devices = jax.devices()
62-
print(
63-
f"[Host {jax.process_index()}] "
64-
f"Got {len(global_devices)} global devices"
65-
)
63+
print(f"[Host {idx}] Got {len(global_devices)} global devices")
6664
mesh = Mesh(global_devices, ("x",))
6765
68-
print(f"[Host {jax.process_index()}] Allocating data...")
69-
size = 32832
70-
x_global = jnp.ones((size, size), dtype=jnp.float32)
71-
y_global = jnp.ones((size, size), dtype=jnp.float32)
66+
print(f"[Host {idx}] Allocating data...")
67+
print(f"[Host {idx}] Defining sharding...")
68+
size = 32768
69+
global_shape = (size, size)
70+
sharding = NamedSharding(
71+
mesh, jax.sharding.PartitionSpec("x", None)
72+
)
73+
74+
print(f"[Host {idx}] Creating sharded data directly on devices...")
75+
76+
def ones_callback(index):
77+
resolved_indices = [
78+
s.indices(global_shape[i]) for i, s in enumerate(index)
79+
]
80+
local_shape = tuple(
81+
stop - start for start, stop, step in resolved_indices
82+
)
83+
84+
return jnp.ones(local_shape, dtype=jnp.float32)
7285
73-
print(f"[Host {jax.process_index()}] Sharding data...")
74-
sharding = NamedSharding(mesh, jax.sharding.PartitionSpec("x", None))
75-
x = jax.device_put(x_global, sharding)
76-
y = jax.device_put(y_global, sharding)
77-
print(f"[Host {jax.process_index()}] Data on device")
86+
x = jax.make_array_from_callback(
87+
global_shape, sharding, ones_callback)
88+
y = jax.make_array_from_callback(
89+
global_shape, sharding, ones_callback)
90+
91+
print(f"[Host {idx}] Data on device")
7892
79-
# ========= Define heavy workload =========
8093
@pjit
8194
def matmul_ultra_heavy(x, y):
8295
tmp1 = jnp.dot(x, y)
@@ -93,7 +106,6 @@ def matmul_ultra_heavy(x, y):
93106
print(f"[Host {jax.process_index()}] Starting benchmark...")
94107
95108
start = time.time()
96-
# Remember to control loop time to control experiment time
97109
for i in range(1_000_000):
98110
result = matmul_ultra_heavy(x, y)
99111
result.block_until_ready()
@@ -485,17 +497,18 @@ def delete_one_random_pod(
485497
Defaults to "default".
486498
487499
Raises:
488-
AirflowFailException: If no running pods are found in the specified namespace.
500+
AirflowFailException: If no running pods are found in the specified
501+
namespace.
489502
"""
490503
running_pods = get_running_pods(node_pool=node_pool, namespace=namespace)
491504
if not running_pods:
492-
logging.error(f"No running pods found in namespace: {namespace}")
505+
logging.error("No running pods found in namespace: %s", namespace)
493506
raise AirflowFailException(
494507
f"No running pods found in namespace: {namespace}"
495508
)
496509

497510
target_pod = random.choice(running_pods)
498-
logging.info(f"Targeting pod for deletion: {target_pod}")
511+
logging.info("Targeting pod for deletion: %s", target_pod)
499512

500513
with tempfile.NamedTemporaryFile() as temp_config_file:
501514
env = os.environ.copy()
@@ -509,7 +522,7 @@ def delete_one_random_pod(
509522
])
510523

511524
subprocess.run_exec(cmd, env=env)
512-
logging.info(f"Successfully initiated deletion for pod: {target_pod}")
525+
logging.info("Successfully initiated deletion for pod: %s", target_pod)
513526

514527

515528
@task.sensor(poke_interval=30, timeout=900, mode="poke")
@@ -583,8 +596,7 @@ def wait_for_jobset_started(
583596
def wait_for_jobset_ttr_to_be_found(
584597
node_pool: node_pool_info, jobset_name: str
585598
) -> bool:
586-
"""
587-
Polls the jobset time_between_interruptions metric.
599+
"""Polls the jobset time_between_interruptions metric.
588600
589601
A sensor task which polls the jobset time_between_interruptions metric
590602
every 60 seconds for 60 minutes. 60 minutes is used here since this
@@ -594,8 +606,9 @@ def wait_for_jobset_ttr_to_be_found(
594606
impractical for the test to run longer.
595607
596608
Args:
597-
info(Info): An instance of the Info class that encapsulates
598-
the configuration and metadata of a GKE node pool and workload.
609+
node_pool: An instance of the Info class that encapsulates
610+
the configuration and metadata of a GKE node pool and workload.
611+
jobset_name: The name of the JobSet.
599612
"""
600613
now = datetime.datetime.now()
601614

0 commit comments

Comments
 (0)