|
2 | 2 |
|
3 | 3 | """A library to measure e2e metrics like goodput.""" |
4 | 4 |
|
5 | | -import contextlib |
6 | | -import enum |
7 | 5 | import importlib |
8 | | -from typing import Optional, TypeVar |
| 6 | +from typing import Optional |
9 | 7 |
|
10 | 8 | from absl import flags, logging |
11 | 9 |
|
12 | | -from axlearn.common.config import REQUIRED, Configurable, Required, config_class |
13 | | - |
14 | | - |
15 | | -class Event(enum.Enum): |
16 | | - """Event to be recorded (Legacy). |
17 | | -
|
18 | | - Attributes: |
19 | | - START_JOB: Start of job. |
20 | | - END_JOB: End of job. |
21 | | - START_STEP: Start of a training step. Should be recorded with `step` as a positional arg. |
22 | | - START_ACCELERATOR_INIT: Start of accelerator mesh initialization. |
23 | | - END_ACCELERATOR_INIT: End of accelerator mesh initialization. |
24 | | - START_TRAINING_PREPARATION: Start of training preparation. |
25 | | - END_TRAINING_PREPARATION: End of training preparation. |
26 | | - START_DATA_LOADING: Start of data loading. |
27 | | - END_DATA_LOADING: End of data loading. |
28 | | - START_CUSTOM_BADPUT_EVENT: Start of custom badput event. |
29 | | - END_CUSTOM_BADPUT_EVENT: End of custom badput event. |
30 | | - """ |
31 | | - |
32 | | - START_JOB = "START_JOB" |
33 | | - END_JOB = "END_JOB" |
34 | | - START_STEP = "START_STEP" |
35 | | - START_ACCELERATOR_INIT = "START_ACCELERATOR_INIT" |
36 | | - END_ACCELERATOR_INIT = "END_ACCELERATOR_INIT" |
37 | | - START_TRAINING_PREPARATION = "START_TRAINING_PREPARATION" |
38 | | - END_TRAINING_PREPARATION = "END_TRAINING_PREPARATION" |
39 | | - START_DATA_LOADING = "START_DATA_LOADING" |
40 | | - END_DATA_LOADING = "END_DATA_LOADING" |
41 | | - START_CUSTOM_BADPUT_EVENT = "START_CUSTOM_BADPUT_EVENT" |
42 | | - END_CUSTOM_BADPUT_EVENT = "END_CUSTOM_BADPUT_EVENT" |
43 | | - |
44 | | - |
45 | | -class EventType(enum.Enum): |
46 | | - """Event to be recorded. |
47 | | -
|
48 | | - Attributes: |
49 | | - JOB: Start and end of the job. |
50 | | - STEP: Start of a training step. Should be recorded with `step` as a positional arg. |
51 | | - ACCELERATOR_INIT: Start and end of accelerator mesh initialization. |
52 | | - TRAINING_PREPARATION: Start and end of training preparation. |
53 | | - DATA_LOADING: Start and end of data loading. |
54 | | - CUSTOM_BADPUT_EVENT: Start and end of custom badput events. |
55 | | - """ |
56 | | - |
57 | | - JOB = "job" |
58 | | - STEP = "step" |
59 | | - ACCELERATOR_INIT = "tpu_init" |
60 | | - TRAINING_PREPARATION = "training_preparation" |
61 | | - DATA_LOADING = "data_loading" |
62 | | - CUSTOM_BADPUT_EVENT = "custom_badput_event" |
63 | | - |
64 | | - |
65 | | -class Recorder(Configurable): |
66 | | - """The base interface for collecting e2e metrics.""" |
67 | | - |
68 | | - @config_class |
69 | | - class Config(Configurable.Config): |
70 | | - """Configures Recorder. |
71 | | -
|
72 | | - Attributes: |
73 | | - name: Name of the recorder. |
74 | | - """ |
75 | | - |
76 | | - name: Required[str] = REQUIRED |
77 | | - |
78 | | - @classmethod |
79 | | - def from_flags(cls, fv: Optional[flags.FlagValues]) -> "Recorder": |
80 | | - """Converts flags to a recorder.""" |
81 | | - raise NotImplementedError(cls) |
82 | | - |
83 | | - def record(self, event: Event, *args, **kwargs): |
84 | | - """Records a single, instantaneous event. |
85 | | -
|
86 | | - Note: |
87 | | - This method is maintained for backward compatibility. |
88 | | - New child recorder implementations should prioritize implementing the |
89 | | - `record_event` context manager instead. |
90 | | - """ |
91 | | - raise NotImplementedError(type(self)) |
92 | | - |
93 | | - def start_monitoring(self, **kwargs): |
94 | | - """Starts computing and uploading metrics in the background. |
95 | | -
|
96 | | - Note: |
97 | | - This method is maintained for backward compatibility. New child |
98 | | - recorders should prioritize implementing the `maybe_monitor_all` |
99 | | - context manager, which provides a clearer lifecycle for monitoring. |
100 | | - """ |
101 | | - raise NotImplementedError(type(self)) |
102 | | - |
103 | | - @contextlib.contextmanager |
104 | | - def record_event(self, event: EventType, *args, **kwargs): |
105 | | - """A context manager to record the start and end of an event. |
106 | | -
|
107 | | - This is the preferred method for recording events. Child classes |
108 | | - should implement this context manager to handle timed operations. |
109 | | -
|
110 | | - Example: |
111 | | - with recorder.record_event(EventType.ACCELERATOR_INIT): |
112 | | - # Device initialization. |
113 | | - """ |
114 | | - # pylint: disable=unnecessary-pass |
115 | | - # pylint: disable=unused-argument |
116 | | - try: |
117 | | - yield |
118 | | - finally: |
119 | | - pass |
120 | | - |
121 | | - @contextlib.contextmanager |
122 | | - def maybe_monitor_all(self): |
123 | | - """Context manager to start and stop computing and monitoring metrics. |
124 | | -
|
125 | | - This is the preferred method for monitoring events. Child classes |
126 | | - should implement this context manager to manage all types of monitoring. |
127 | | -
|
128 | | - Example: |
129 | | - with recorder.maybe_monitor_all(): |
130 | | - # Train |
131 | | - """ |
132 | | - yield |
133 | | - |
134 | | - |
135 | | -_recorders: dict[str, type] = {} |
136 | | -_T = TypeVar("_T") |
137 | | - |
138 | | - |
139 | | -def register_recorder(name: str): |
140 | | - def fn(cls: _T) -> _T: |
141 | | - """Registers a recorder class for `get_recorder_config`.""" |
142 | | - if name in _recorders: |
143 | | - raise ValueError(f"Recorder {name} is already registered.") |
144 | | - _recorders[name] = cls |
145 | | - return cls |
146 | | - |
147 | | - return fn |
148 | | - |
149 | | - |
150 | | -def define_flags(**kwargs): |
151 | | - """Common measurement flags.""" |
152 | | - |
153 | | - flags.DEFINE_string( |
154 | | - "recorder_type", |
155 | | - None, |
156 | | - "The recorder type. It can be a recorder name, e.g. `my_recorder`, or " |
157 | | - "a module paired with a recorder name, e.g. `my.module:my_recorder`.", |
158 | | - **kwargs, |
159 | | - ) |
160 | | - flags.DEFINE_multi_string( |
161 | | - "recorder_spec", |
162 | | - [], |
163 | | - "Recorder spec provided as key=value. " |
164 | | - "Refer to each recorders's `from_flags` method docstring for details.", |
165 | | - **kwargs, |
166 | | - ) |
167 | | - |
| 10 | +from axlearn.common.measurement_base import ( |
| 11 | + Event, |
| 12 | + EventType, |
| 13 | + Recorder, |
| 14 | + _recorders, |
| 15 | + define_flags, |
| 16 | + register_recorder, |
| 17 | +) |
| 18 | + |
| 19 | +__all__ = [ |
| 20 | + "Event", |
| 21 | + "EventType", |
| 22 | + "Recorder", |
| 23 | + "define_flags", |
| 24 | + "register_recorder", |
| 25 | + "global_recorder", |
| 26 | + "initialize", |
| 27 | + "record_event", |
| 28 | + "start_monitoring", |
| 29 | +] |
168 | 30 |
|
169 | 31 | global_recorder: Optional[Recorder] = None |
170 | 32 |
|
|
0 commit comments