Skip to content

Commit 41d4839

Browse files
raytomatochanglan
authored andcommitted
Enable shm for running colocated python.
GitOrigin-RevId: ebcedf2
1 parent 7e63a93 commit 41d4839

3 files changed

Lines changed: 64 additions & 13 deletions

File tree

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
ARG TARGET=base
44
ARG BASE_IMAGE=ubuntu:24.04
5-
ARG BASE_IMAGE_COLOCATED=us-docker.pkg.dev/cloud-tpu-v2-images/pathways-colocated-python/sidecar:2026_01_27-python_3.12-jax_0.8.2
5+
ARG BASE_IMAGE_COLOCATED=us-docker.pkg.dev/cloud-tpu-v2-images/pathways-colocated-python/sidecar:2026_02_09-python_3.12-jax_0.8.3
66

77
FROM ${BASE_IMAGE} AS base
88

axlearn/cloud/gcp/pathways_utils.py

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@
9393
# While workers will share #workers * _PATHWAYS_BACK_OFF_LIMIT total times.
9494
_PATHWAYS_BACK_OFF_LIMIT = 32
9595

96+
_PATHWAYS_SHM_DIR = "/tmp/ifrt_proxy"
97+
_PATHWAYS_SHM_VOLUME_NAME = "shared-memory"
98+
9699
# Notary proxy configuration for gke_gateway_route
97100
NOTARY_PROXY_IMAGE = "docker.apple.com/polymer/notary-proxy:44d03e27b8c9"
98101
NOTARY_PROXY_HTTP_PORT = 38081
@@ -232,13 +235,18 @@ def build_colocated_python_container(self, image: str):
232235
image=get_colocated_python_image(image),
233236
restartPolicy="Always",
234237
env=[
238+
{
239+
"name": "CLOUD_PATHWAYS_SIDECAR_SHM_DIRECTORY",
240+
"value": _PATHWAYS_SHM_DIR,
241+
},
235242
{
236243
"name": "GRPC_SERVER_ADDRESS",
237244
"value": f"0.0.0.0:{_COLOCATED_CONTAINER_PORT}",
238245
},
239246
],
240247
imagePullPolicy="Always",
241248
ports=[dict(containerPort=_COLOCATED_CONTAINER_PORT)],
249+
volumeMounts=[{"mountPath": _PATHWAYS_SHM_DIR, "name": _PATHWAYS_SHM_VOLUME_NAME}],
242250
)
243251

244252
@property
@@ -415,7 +423,9 @@ def _build_pathways_head_container(self) -> dict:
415423
# Setting it to 1 byte so effectively all Jax device_put use shared memory.
416424
self._update_env_list(env_list, "IFRT_PROXY_LARGE_TRANSFER_THRESHOLD", "1")
417425
self._update_env_list(
418-
env_list, "IFRT_PROXY_LARGE_TRANSFER_OPTIMIZATION_DIRECTORY", "/tmp/ifrt_proxy"
426+
env_list,
427+
"IFRT_PROXY_LARGE_TRANSFER_OPTIMIZATION_DIRECTORY",
428+
_PATHWAYS_SHM_DIR,
419429
)
420430
env_list.append(
421431
{
@@ -439,7 +449,7 @@ def _build_pathways_head_container(self) -> dict:
439449
head_container["securityContext"] = {"capabilities": {"add": ["SYS_PTRACE"]}}
440450

441451
volume_mounts = head_container.get("volumeMounts", [])
442-
volume_mounts.append(dict(name="shared-memory", mountPath="/tmp/ifrt_proxy"))
452+
volume_mounts.append(dict(name=_PATHWAYS_SHM_VOLUME_NAME, mountPath=_PATHWAYS_SHM_DIR))
443453
head_container["volumeMounts"] = volume_mounts
444454

445455
return head_container
@@ -490,13 +500,13 @@ def _build_pathways_head_sidecar_containers(self) -> list[Nested[Any]]:
490500
{"name": "XLA_FLAGS", "value": f"--xla_dump_to=/output/{cfg.name}/xla"},
491501
{
492502
"name": "IFRT_PROXY_LARGE_TRANSFER_OPTIMIZATION_DIRECTORY",
493-
"value": "/tmp/ifrt_proxy",
503+
"value": _PATHWAYS_SHM_DIR,
494504
},
495505
],
496506
ports=[dict(containerPort=_PATHWAYS_PROXY_PORT)],
497507
volumeMounts=[
498508
dict(name="shared-output", mountPath="/output"),
499-
dict(name="shared-memory", mountPath="/tmp/ifrt_proxy"),
509+
dict(name=_PATHWAYS_SHM_VOLUME_NAME, mountPath=_PATHWAYS_SHM_DIR),
500510
],
501511
),
502512
dict(
@@ -540,7 +550,7 @@ def _build_pathways_head_pod(self) -> Nested[Any]:
540550
else:
541551
# gcsfuse mounts shared-memory. To avoid double mounting, we only mount
542552
# shared-memory explicitly when gcsfuse_mount is not enabled.
543-
volumes.append(dict(name="shared-memory", emptyDir=dict(medium="Memory")))
553+
volumes.append(dict(name=_PATHWAYS_SHM_VOLUME_NAME, emptyDir=dict(medium="Memory")))
544554

545555
node_selector = {
546556
_PATHWAYS_HEAD_NODE_POOL_SELECTOR_KEY: _PATHWAYS_HEAD_NODE_POOL_SELECTOR_VALUE,
@@ -668,11 +678,25 @@ def _build_pathways_worker_container(
668678
f"--gcs_scratch_location={cfg.output_dir}/pathways-staging",
669679
# Recycling host memory gives a slight increase in performance.
670680
"--tpu_pinned_host_allocation_recycle=true",
671-
# The flag below is needed for better H2D performance.
672-
# We use 1/4 of the host memory, rounding up to power of 2 as premapped buffer.
673-
# Note that pathways worker requires this flag to be a power of 2.
674-
f"--tpu_premapped_buffer_size={round_up_to_power_of_2(host_memory//4)*(1<<30)}",
675681
]
682+
if not self._colocated_python.is_colocated_python_enabled:
683+
worker_container["args"].append(
684+
# The flag below is needed for better H2D performance.
685+
# We use 1/4 of the host memory, rounding up to power of 2 as premapped buffer.
686+
# Note that pathways worker requires this flag to be a power of 2.
687+
f"--tpu_premapped_buffer_size={round_up_to_power_of_2(host_memory//4)*(1<<30)}",
688+
)
689+
else:
690+
# Colocated python uses more host memory.
691+
# Thus we need to reduce the premapped buffer size.
692+
premapped_buffer_size_gb = min(round_up_to_power_of_2(host_memory // 16), 32)
693+
worker_container["args"].extend(
694+
[
695+
f"--tpu_premapped_buffer_size={premapped_buffer_size_gb * (1<<30)}",
696+
f"--cloud_pathways_sidecar_shm_directory={_PATHWAYS_SHM_DIR}",
697+
]
698+
)
699+
676700
mega_scale_args = xla_flags_from_options(self._mxla_options).split()
677701
worker_container["args"].extend(mega_scale_args)
678702

@@ -681,6 +705,10 @@ def _build_pathways_worker_container(
681705
ports = worker_container.get("ports", [])
682706
ports.append({"containerPort": _PATHWAYS_WORKER_PORT})
683707
worker_container["ports"] = ports
708+
if self._colocated_python.is_colocated_python_enabled:
709+
worker_container["volumeMounts"] = [
710+
dict(name=_PATHWAYS_SHM_VOLUME_NAME, mountPath=_PATHWAYS_SHM_DIR)
711+
]
684712

685713
# Command will be executed by the head node, and it will compile the model and
686714
# distribute works to workers.
@@ -706,11 +734,18 @@ def _build_pathways_worker_pod(
706734
pod_spec["containers"] = [
707735
self._build_pathways_worker_container(pathways_worker_replicated_job_index)
708736
]
737+
709738
if self._colocated_python.is_colocated_python_enabled:
710739
image = cfg.image_id or self._bundler.id(cfg.name)
711740
pod_spec["initContainers"].append(
712741
self._colocated_python.build_colocated_python_container(image)
713742
)
743+
744+
shared_memory_volume = {
745+
"name": _PATHWAYS_SHM_VOLUME_NAME,
746+
"emptyDir": {"medium": "Memory"},
747+
}
748+
pod_spec["volumes"].append(shared_memory_volume)
714749
worker_pod["spec"] = pod_spec
715750

716751
# Service account for nodes.
@@ -1027,11 +1062,17 @@ def _build_pathways_worker_container(self) -> dict:
10271062
+ f"{_PATHWAYS_RESOURCE_MANAGER_PORT}",
10281063
f"--gcs_scratch_location={cfg.output_dir}/pathways-staging",
10291064
]
1065+
if self._colocated_python.is_colocated_python_enabled:
1066+
args.append(f"--cloud_pathways_sidecar_shm_directory={_PATHWAYS_SHM_DIR}")
10301067
worker_container["args"] = args
10311068
ports = worker_container.get("ports", [])
10321069
ports.append({"containerPort": _PATHWAYS_WORKER_PORT})
10331070
worker_container["ports"] = ports
10341071
worker_container["image"] = self._colocated_python.pathways_server_image
1072+
if self._colocated_python.is_colocated_python_enabled:
1073+
worker_container["volumeMounts"] = [
1074+
dict(name=_PATHWAYS_SHM_VOLUME_NAME, mountPath=_PATHWAYS_SHM_DIR)
1075+
]
10351076

10361077
worker_container.pop("command")
10371078
return worker_container
@@ -1047,11 +1088,17 @@ def build_worker_pod(self) -> dict:
10471088
pod_spec.pop("restartPolicy")
10481089
pod_spec["dnsPolicy"] = "ClusterFirstWithHostNet"
10491090
pod_spec["containers"] = [self._build_pathways_worker_container()]
1091+
10501092
if self._colocated_python.is_colocated_python_enabled:
10511093
image = cfg.image_id or self._bundler.id(cfg.name)
10521094
pod_spec["initContainers"].append(
10531095
self._colocated_python.build_colocated_python_container(image)
10541096
)
1097+
shared_memory_volume = {
1098+
"name": _PATHWAYS_SHM_VOLUME_NAME,
1099+
"emptyDir": {"medium": "Memory"},
1100+
}
1101+
pod_spec["volumes"].append(shared_memory_volume)
10551102
worker_pod["spec"] = pod_spec
10561103

10571104
# Service account for nodes.

axlearn/cloud/gcp/pathways_utils_test.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,11 @@ def test_build_pathways_worker_pod(self, sidecars):
227227
annotations.get("tpu-provisioner.cloud.google.com/node-service-account", None),
228228
)
229229
self.assertIn("--tpu_pinned_host_allocation_recycle=true", worker_container["args"])
230-
# 128GiB
231-
self.assertIn("--tpu_premapped_buffer_size=137438953472", worker_container["args"])
230+
# 32GiB or 128GiB
231+
buffer_size = (
232+
34359738368 if _COLOCATED_PYTHON_SIDECAR_NAME in sidecars else 137438953472
233+
)
234+
self.assertIn(f"--tpu_premapped_buffer_size={buffer_size}", worker_container["args"])
232235

233236
expected_num_init_containers = 2 if _COLOCATED_PYTHON_SIDECAR_NAME in sidecars else 1
234237
self.assertEqual(expected_num_init_containers, len(pod_spec.get("initContainers", [])))
@@ -596,7 +599,8 @@ def test_build_worker_pod(self, sidecars):
596599
else _PATHWAYS_SERVER_IMAGE
597600
)
598601
self.assertEqual(container["image"], server_image)
599-
self.assertEqual(len(container["args"]), 3)
602+
num_args = 4 if _COLOCATED_PYTHON_SIDECAR_NAME in sidecars else 3
603+
self.assertEqual(len(container["args"]), num_args)
600604

601605
expected_num_init_containers = 2 if _COLOCATED_PYTHON_SIDECAR_NAME in sidecars else 1
602606
self.assertEqual(expected_num_init_containers, len(pod_spec.get("initContainers", [])))

0 commit comments

Comments
 (0)