Files
ray-project--ray/python/ray/train/v2/_internal/callbacks/metrics.py
T
2026-07-13 13:17:40 +08:00

125 lines
4.6 KiB
Python

from contextlib import contextmanager
from typing import Dict, Optional
import ray
from ray.train.v2._internal.execution.callback import (
ControllerCallback,
TrainContextCallback,
WorkerCallback,
WorkerGroupCallback,
)
from ray.train.v2._internal.execution.context import TrainRunContext, get_train_context
from ray.train.v2._internal.execution.controller.state import (
TrainControllerState,
TrainControllerStateType,
)
from ray.train.v2._internal.metrics.base import Metric
from ray.train.v2._internal.metrics.controller import ControllerMetrics
from ray.train.v2._internal.metrics.worker import WorkerMetrics
from ray.train.v2._internal.util import time_monotonic
class ControllerMetricsCallback(ControllerCallback, WorkerGroupCallback):
"""Callback that records controller-specific metrics."""
def after_controller_start(self, train_run_context: TrainRunContext):
"""Initialize metrics after controller starts."""
self._run_name = train_run_context.get_run_config().name
self._run_id = train_run_context.run_id
self._metrics: Dict[str, Metric] = ControllerMetrics.get_controller_metrics(
self._run_name, self._run_id
)
# Record initial state
self._metrics[ControllerMetrics.CONTROLLER_STATE].record(
TrainControllerStateType.INITIALIZING
)
async def before_controller_shutdown(self):
"""Shutdown metrics before controller shuts down."""
for metric in self._metrics.values():
metric.reset()
def after_controller_state_update(
self,
previous_state: TrainControllerState,
current_state: TrainControllerState,
):
"""Record state transitions after controller state updates."""
self._metrics[ControllerMetrics.CONTROLLER_STATE].record(
current_state._state_type
)
@contextmanager
def on_worker_group_start(self):
"""Measure time taken to start worker group."""
start_time_s = time_monotonic()
yield
elapsed_time_s = time_monotonic() - start_time_s
self._metrics[ControllerMetrics.WORKER_GROUP_START_TOTAL_TIME_S].record(
elapsed_time_s
)
@contextmanager
def on_worker_group_shutdown(self):
"""Measure time taken to shutdown worker group."""
start_time_s = time_monotonic()
yield
elapsed_time_s = time_monotonic() - start_time_s
self._metrics[ControllerMetrics.WORKER_GROUP_SHUTDOWN_TOTAL_TIME_S].record(
elapsed_time_s
)
class WorkerMetricsCallback(WorkerCallback, TrainContextCallback):
"""Callback that records worker-specific metrics."""
def __init__(self, train_run_context: TrainRunContext):
self._run_name = train_run_context.get_run_config().name
self._run_id = train_run_context.run_id
self._metrics: Optional[Dict[str, Metric]] = None
def after_init_train_context(self):
"""Initialize metrics after train context is initialized."""
train_context = get_train_context()
core_context = ray.runtime_context.get_runtime_context()
world_rank = train_context.get_world_rank()
worker_actor_id = core_context.get_actor_id()
self._metrics = WorkerMetrics.get_worker_metrics(
self._run_name, self._run_id, world_rank, worker_actor_id
)
def before_worker_shutdown(self):
"""Shutdown metrics before shutdown."""
if self._metrics:
for metric in self._metrics.values():
metric.reset()
@contextmanager
def on_report(self):
"""
Context manager to measure the time taken to report a checkpoint to the storage.
"""
start_time_s = time_monotonic()
yield
elapsed_time_s = time_monotonic() - start_time_s
self._metrics[WorkerMetrics.REPORT_TOTAL_BLOCKED_TIME_S].record(elapsed_time_s)
@contextmanager
def on_checkpoint_sync(self):
"""Measure time spent in the cross-rank barrier that synchronizes the
checkpoint directory name across all workers."""
start_time_s = time_monotonic()
yield
elapsed_time_s = time_monotonic() - start_time_s
self._metrics[WorkerMetrics.CHECKPOINT_SYNC_TOTAL_TIME_S].record(elapsed_time_s)
@contextmanager
def on_checkpoint_transfer(self):
"""Measure time spent transferring checkpoint files to storage."""
start_time_s = time_monotonic()
yield
elapsed_time_s = time_monotonic() - start_time_s
self._metrics[WorkerMetrics.CHECKPOINT_TRANSFER_TOTAL_TIME_S].record(
elapsed_time_s
)