xoscar 0.9.0__cp312-cp312-macosx_10_13_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. xoscar/__init__.py +61 -0
  2. xoscar/_utils.cpython-312-darwin.so +0 -0
  3. xoscar/_utils.pxd +36 -0
  4. xoscar/_utils.pyx +246 -0
  5. xoscar/_version.py +693 -0
  6. xoscar/aio/__init__.py +16 -0
  7. xoscar/aio/base.py +86 -0
  8. xoscar/aio/file.py +59 -0
  9. xoscar/aio/lru.py +228 -0
  10. xoscar/aio/parallelism.py +39 -0
  11. xoscar/api.py +527 -0
  12. xoscar/backend.py +67 -0
  13. xoscar/backends/__init__.py +14 -0
  14. xoscar/backends/allocate_strategy.py +160 -0
  15. xoscar/backends/communication/__init__.py +30 -0
  16. xoscar/backends/communication/base.py +315 -0
  17. xoscar/backends/communication/core.py +69 -0
  18. xoscar/backends/communication/dummy.py +253 -0
  19. xoscar/backends/communication/errors.py +20 -0
  20. xoscar/backends/communication/socket.py +444 -0
  21. xoscar/backends/communication/ucx.py +538 -0
  22. xoscar/backends/communication/utils.py +97 -0
  23. xoscar/backends/config.py +157 -0
  24. xoscar/backends/context.py +437 -0
  25. xoscar/backends/core.py +352 -0
  26. xoscar/backends/indigen/__init__.py +16 -0
  27. xoscar/backends/indigen/__main__.py +19 -0
  28. xoscar/backends/indigen/backend.py +51 -0
  29. xoscar/backends/indigen/driver.py +26 -0
  30. xoscar/backends/indigen/fate_sharing.py +221 -0
  31. xoscar/backends/indigen/pool.py +515 -0
  32. xoscar/backends/indigen/shared_memory.py +548 -0
  33. xoscar/backends/message.cpython-312-darwin.so +0 -0
  34. xoscar/backends/message.pyi +255 -0
  35. xoscar/backends/message.pyx +646 -0
  36. xoscar/backends/pool.py +1630 -0
  37. xoscar/backends/router.py +285 -0
  38. xoscar/backends/test/__init__.py +16 -0
  39. xoscar/backends/test/backend.py +38 -0
  40. xoscar/backends/test/pool.py +233 -0
  41. xoscar/batch.py +256 -0
  42. xoscar/collective/__init__.py +27 -0
  43. xoscar/collective/backend/__init__.py +13 -0
  44. xoscar/collective/backend/nccl_backend.py +160 -0
  45. xoscar/collective/common.py +102 -0
  46. xoscar/collective/core.py +737 -0
  47. xoscar/collective/process_group.py +687 -0
  48. xoscar/collective/utils.py +41 -0
  49. xoscar/collective/xoscar_pygloo.cpython-312-darwin.so +0 -0
  50. xoscar/collective/xoscar_pygloo.pyi +239 -0
  51. xoscar/constants.py +23 -0
  52. xoscar/context.cpython-312-darwin.so +0 -0
  53. xoscar/context.pxd +21 -0
  54. xoscar/context.pyx +368 -0
  55. xoscar/core.cpython-312-darwin.so +0 -0
  56. xoscar/core.pxd +51 -0
  57. xoscar/core.pyx +664 -0
  58. xoscar/debug.py +188 -0
  59. xoscar/driver.py +42 -0
  60. xoscar/errors.py +63 -0
  61. xoscar/libcpp.pxd +31 -0
  62. xoscar/metrics/__init__.py +21 -0
  63. xoscar/metrics/api.py +288 -0
  64. xoscar/metrics/backends/__init__.py +13 -0
  65. xoscar/metrics/backends/console/__init__.py +13 -0
  66. xoscar/metrics/backends/console/console_metric.py +82 -0
  67. xoscar/metrics/backends/metric.py +149 -0
  68. xoscar/metrics/backends/prometheus/__init__.py +13 -0
  69. xoscar/metrics/backends/prometheus/prometheus_metric.py +70 -0
  70. xoscar/nvutils.py +717 -0
  71. xoscar/profiling.py +260 -0
  72. xoscar/serialization/__init__.py +20 -0
  73. xoscar/serialization/aio.py +141 -0
  74. xoscar/serialization/core.cpython-312-darwin.so +0 -0
  75. xoscar/serialization/core.pxd +28 -0
  76. xoscar/serialization/core.pyi +57 -0
  77. xoscar/serialization/core.pyx +944 -0
  78. xoscar/serialization/cuda.py +111 -0
  79. xoscar/serialization/exception.py +48 -0
  80. xoscar/serialization/mlx.py +67 -0
  81. xoscar/serialization/numpy.py +82 -0
  82. xoscar/serialization/pyfury.py +37 -0
  83. xoscar/serialization/scipy.py +72 -0
  84. xoscar/serialization/torch.py +180 -0
  85. xoscar/utils.py +522 -0
  86. xoscar/virtualenv/__init__.py +34 -0
  87. xoscar/virtualenv/core.py +268 -0
  88. xoscar/virtualenv/platform.py +56 -0
  89. xoscar/virtualenv/utils.py +100 -0
  90. xoscar/virtualenv/uv.py +321 -0
  91. xoscar-0.9.0.dist-info/METADATA +230 -0
  92. xoscar-0.9.0.dist-info/RECORD +94 -0
  93. xoscar-0.9.0.dist-info/WHEEL +6 -0
  94. xoscar-0.9.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,160 @@
1
+ # Copyright 2022-2023 XProbe Inc.
2
+ # derived from copyright 1999-2021 Alibaba Group Holding Ltd.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from abc import ABC, abstractmethod
17
+ from random import choice
18
+ from typing import Dict, Optional, Tuple
19
+
20
+ from ..core import ActorRef
21
+ from ..errors import NoIdleSlot
22
+ from ..utils import implements
23
+ from .config import ActorPoolConfig
24
+ from .message import _MessageBase
25
+
26
+ allocated_value = Tuple["AllocateStrategy", Optional[_MessageBase]]
27
+ allocated_values = Dict[Optional[ActorRef], allocated_value]
28
+ allocated_type = Dict[str, allocated_values]
29
+
30
+
31
+ class AllocateStrategy(ABC):
32
+ __slots__ = ()
33
+
34
+ @abstractmethod
35
+ def get_allocated_address(
36
+ self, config: ActorPoolConfig, allocated: allocated_type
37
+ ) -> str:
38
+ """
39
+ Get external address where the actor allocated to.
40
+
41
+ Parameters
42
+ ----------
43
+ config: ActorPoolConfig
44
+ Actor pool config.
45
+ allocated:
46
+ Already allocated of actor and its strategy.
47
+
48
+ Returns
49
+ -------
50
+ allocated_address: str
51
+ External address to allocate.
52
+ """
53
+
54
+
55
+ class AddressSpecified(AllocateStrategy):
56
+ __slots__ = ("address",)
57
+
58
+ def __init__(self, address):
59
+ self.address = address
60
+
61
+ @implements(AllocateStrategy.get_allocated_address)
62
+ def get_allocated_address(
63
+ self, config: ActorPoolConfig, allocated: allocated_type
64
+ ) -> str:
65
+ return self.address
66
+
67
+
68
+ class MainPool(AllocateStrategy):
69
+ __slots__ = ()
70
+
71
+ @implements(AllocateStrategy.get_allocated_address)
72
+ def get_allocated_address(
73
+ self, config: ActorPoolConfig, allocated: allocated_type
74
+ ) -> str:
75
+ # allocate to main process
76
+ main_process_index = config.get_process_indexes()[0]
77
+ return config.get_external_address(main_process_index)
78
+
79
+
80
+ class Random(AllocateStrategy):
81
+ __slots__ = ()
82
+
83
+ @implements(AllocateStrategy.get_allocated_address)
84
+ def get_allocated_address(
85
+ self, config: ActorPoolConfig, allocated: allocated_type
86
+ ) -> str:
87
+ return choice(config.get_external_addresses())
88
+
89
+
90
+ class RandomSubPool(AllocateStrategy):
91
+ __slots__ = ()
92
+
93
+ @implements(AllocateStrategy.get_allocated_address)
94
+ def get_allocated_address(
95
+ self, config: ActorPoolConfig, allocated: allocated_type
96
+ ) -> str:
97
+ return choice(config.get_external_addresses()[1:])
98
+
99
+
100
+ class ProcessIndex(AllocateStrategy):
101
+ __slots__ = ("process_index",)
102
+
103
+ def __init__(self, process_index: int):
104
+ self.process_index = process_index
105
+
106
+ @implements(AllocateStrategy.get_allocated_address)
107
+ def get_allocated_address(
108
+ self, config: ActorPoolConfig, allocated: allocated_type
109
+ ) -> str:
110
+ actual_process_index = config.get_process_indexes()[self.process_index]
111
+ return config.get_pool_config(actual_process_index)["external_address"][0]
112
+
113
+
114
+ class RandomLabel(AllocateStrategy):
115
+ __slots__ = ("label",)
116
+
117
+ def __init__(self, label):
118
+ self.label = label
119
+
120
+ @implements(AllocateStrategy.get_allocated_address)
121
+ def get_allocated_address(
122
+ self, config: ActorPoolConfig, allocated: allocated_type
123
+ ) -> str:
124
+ return choice(config.get_external_addresses(label=self.label))
125
+
126
+
127
+ class IdleLabel(AllocateStrategy):
128
+ __slots__ = "label", "mark"
129
+
130
+ def __init__(self, label, mark):
131
+ self.label = label
132
+ self.mark = mark
133
+
134
+ def __hash__(self):
135
+ return hash((type(self), self.label, self.mark))
136
+
137
+ def __eq__(self, other):
138
+ return (
139
+ isinstance(other, IdleLabel)
140
+ and self.label == other.label
141
+ and self.mark == other.mark
142
+ )
143
+
144
+ @implements(AllocateStrategy.get_allocated_address)
145
+ def get_allocated_address(
146
+ self, config: ActorPoolConfig, allocated: allocated_type
147
+ ) -> str:
148
+ addresses = config.get_external_addresses(label=self.label)
149
+ for addr in addresses:
150
+ occupied = False
151
+ for strategy, _ in allocated.get(addr, dict()).values():
152
+ if strategy == self:
153
+ occupied = True
154
+ break
155
+ if not occupied:
156
+ return addr
157
+ raise NoIdleSlot(
158
+ f"No idle slot for creating actor "
159
+ f"with label {self.label}, mark {self.mark}"
160
+ )
@@ -0,0 +1,30 @@
1
+ # Copyright 2022-2023 XProbe Inc.
2
+ # derived from copyright 1999-2021 Alibaba Group Holding Ltd.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from .base import Channel, ChannelType, Client, Server
17
+ from .core import gen_local_address, get_client_type, get_server_type
18
+ from .dummy import DummyChannel, DummyClient, DummyServer
19
+ from .socket import (
20
+ SocketChannel,
21
+ SocketClient,
22
+ SocketServer,
23
+ UnixSocketClient,
24
+ UnixSocketServer,
25
+ )
26
+ from .ucx import ( # noqa: F401 # pylint: disable=unused-import
27
+ UCXChannel,
28
+ UCXClient,
29
+ UCXServer,
30
+ )
@@ -0,0 +1,315 @@
1
+ # Copyright 2022-2023 XProbe Inc.
2
+ # derived from copyright 1999-2021 Alibaba Group Holding Ltd.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from __future__ import annotations
17
+
18
+ from abc import ABC, abstractmethod
19
+ from dataclasses import dataclass
20
+ from typing import Any, Callable, Coroutine, Type
21
+
22
+ from ...utils import classproperty, implements
23
+
24
+
25
+ @dataclass
26
+ class ChannelType:
27
+ local = 0 # for local communication
28
+ ipc = 1 # inproc
29
+ remote = 2 # remote
30
+
31
+
32
+ class Channel(ABC):
33
+ """
34
+ Channel is used to do data exchange between server and client.
35
+ """
36
+
37
+ __slots__ = "local_address", "dest_address", "compression"
38
+
39
+ name: str | None = None
40
+
41
+ def __init__(
42
+ self,
43
+ local_address: str | None = None,
44
+ dest_address: str | None = None,
45
+ compression: str | None = None,
46
+ ):
47
+ self.local_address = local_address
48
+ self.dest_address = dest_address
49
+ self.compression = compression
50
+
51
+ @abstractmethod
52
+ async def send(self, message: Any):
53
+ """
54
+ Send data to dest. There should be only one send for one recv, otherwise recv messages
55
+ may overlap.
56
+
57
+ Parameters
58
+ ----------
59
+ message:
60
+ data that sent to dest.
61
+ """
62
+
63
+ @abstractmethod
64
+ async def recv(self):
65
+ """
66
+ Receive data that sent from dest.
67
+ """
68
+
69
+ @abstractmethod
70
+ async def close(self):
71
+ """
72
+ Close channel.
73
+ """
74
+
75
+ @property
76
+ @abstractmethod
77
+ def closed(self) -> bool:
78
+ """
79
+ This channel is closed or not.
80
+
81
+ Returns
82
+ -------
83
+ closed:
84
+ If the channel is closed.
85
+ """
86
+
87
+ @property
88
+ @abstractmethod
89
+ def type(self) -> int:
90
+ """
91
+ Channel is used for, can be dummy, ipc or remote.
92
+
93
+ Returns
94
+ -------
95
+ channel_type: int
96
+ type that can be dummy, ipc or remote.
97
+ """
98
+
99
+ @property
100
+ def info(self) -> dict:
101
+ return {
102
+ "name": self.name,
103
+ "compression": self.compression,
104
+ "type": self.type,
105
+ "local_address": self.local_address,
106
+ "dest_address": self.dest_address,
107
+ }
108
+
109
+
110
+ class Server(ABC):
111
+ __slots__ = "address", "channel_handler"
112
+
113
+ scheme: str | None = None
114
+
115
+ def __init__(
116
+ self,
117
+ address: str,
118
+ channel_handler: Callable[[Channel], Coroutine] | None = None,
119
+ ):
120
+ self.address = address
121
+ self.channel_handler = channel_handler
122
+
123
+ @classproperty
124
+ @abstractmethod
125
+ def client_type(self) -> Type["Client"]:
126
+ """
127
+ Return the corresponding client type.
128
+
129
+ Returns
130
+ -------
131
+ client_type: type
132
+ client type.
133
+ """
134
+
135
+ @property
136
+ @abstractmethod
137
+ def channel_type(self) -> int:
138
+ """
139
+ Channel type, can be dummy, ipc or remote.
140
+
141
+ Returns
142
+ -------
143
+ channel_type: int
144
+ type that can be dummy, ipc or remote.
145
+ """
146
+
147
+ @staticmethod
148
+ @abstractmethod
149
+ async def create(config: dict) -> "Server":
150
+ """
151
+ Create a server instance according to configuration.
152
+
153
+ Parameters
154
+ ----------
155
+ config: dict
156
+ configuration about creating a channel.
157
+
158
+ Returns
159
+ -------
160
+ server: Server
161
+ a server that waiting for connections from clients.
162
+ """
163
+
164
+ @abstractmethod
165
+ async def start(self):
166
+ """
167
+ Used for listening to port or similar stuff.
168
+ """
169
+
170
+ @abstractmethod
171
+ async def join(self, timeout=None):
172
+ """
173
+ Wait forever until timeout.
174
+ """
175
+
176
+ @abstractmethod
177
+ async def on_connected(self, *args, **kwargs):
178
+ """
179
+ Return a channel when new client connected.
180
+
181
+ Returns
182
+ -------
183
+ channel: Channel
184
+ channel for communication
185
+ """
186
+
187
+ @abstractmethod
188
+ async def stop(self):
189
+ """
190
+ Stop the server.
191
+ """
192
+
193
+ @property
194
+ @abstractmethod
195
+ def stopped(self) -> bool:
196
+ """
197
+ If this server is stopped or not.
198
+
199
+ Returns
200
+ -------
201
+ if_stopped: bool
202
+ This server is stopped or not.
203
+ """
204
+
205
+ @property
206
+ def info(self) -> dict:
207
+ return {
208
+ "name": self.scheme,
209
+ "address": self.address,
210
+ "channel_type": self.channel_type,
211
+ }
212
+
213
+ @classmethod
214
+ def parse_config(cls, config: dict) -> dict:
215
+ # skip parsing config by default
216
+ return dict()
217
+
218
+ async def __aenter__(self):
219
+ await self.start()
220
+ return self
221
+
222
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
223
+ await self.stop()
224
+
225
+
226
+ class Client(ABC):
227
+ __slots__ = "local_address", "dest_address", "channel"
228
+
229
+ scheme: str | None = None
230
+
231
+ def __init__(
232
+ self, local_address: str | None, dest_address: str | None, channel: Channel
233
+ ):
234
+ self.local_address = local_address
235
+ self.dest_address = dest_address
236
+ self.channel = channel
237
+
238
+ @property
239
+ def channel_type(self) -> int:
240
+ """
241
+ Channel type, can be dummy, ipc or remote.
242
+
243
+ Returns
244
+ -------
245
+ channel_type: int
246
+ type that can be dummy, ipc or remote.
247
+ """
248
+ return self.channel.type
249
+
250
+ @staticmethod
251
+ @abstractmethod
252
+ async def connect(
253
+ dest_address: str, local_address: str | None = None, **kwargs
254
+ ) -> "Client":
255
+ """
256
+ Create a client that is able to connect to some server.
257
+
258
+ Parameters
259
+ ----------
260
+ dest_address: str
261
+ Destination server address that to connect to.
262
+ local_address: str
263
+ local address.
264
+
265
+ Returns
266
+ -------
267
+ client: Client
268
+ Client that holds a channel to communicate.
269
+ """
270
+
271
+ @classmethod
272
+ def parse_config(cls, config: dict) -> dict:
273
+ # skip parsing config by default
274
+ return dict()
275
+
276
+ @implements(Channel.send)
277
+ async def send(self, message):
278
+ return await self.channel.send(message)
279
+
280
+ @implements(Channel.recv)
281
+ async def recv(self):
282
+ return await self.channel.recv()
283
+
284
+ async def close(self):
285
+ """
286
+ Close connection.
287
+ """
288
+ await self.channel.close()
289
+
290
+ @property
291
+ def closed(self) -> bool:
292
+ """
293
+ This client is closed or not.
294
+
295
+ Returns
296
+ -------
297
+ closed: bool
298
+ If the client is closed.
299
+ """
300
+ return self.channel.closed
301
+
302
+ @property
303
+ def info(self) -> dict:
304
+ return {
305
+ "local_address": self.local_address,
306
+ "dest_address": self.dest_address,
307
+ "channel_name": self.channel.name,
308
+ "channel_type": self.channel_type,
309
+ }
310
+
311
+ async def __aenter__(self):
312
+ return self
313
+
314
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
315
+ await self.close()
@@ -0,0 +1,69 @@
1
+ # Copyright 2022-2023 XProbe Inc.
2
+ # derived from copyright 1999-2021 Alibaba Group Holding Ltd.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from __future__ import annotations
17
+
18
+ from typing import Type
19
+ from urllib.parse import urlparse
20
+
21
+ from .base import Client, Server
22
+
23
+ _scheme_to_client_types: dict[str, Type[Client]] = dict()
24
+ _scheme_to_server_types: dict[str, Type[Server]] = dict()
25
+
26
+
27
+ def register_client(client_type: Type[Client]):
28
+ _scheme_to_client_types[client_type.scheme] = client_type # type: ignore
29
+ return client_type
30
+
31
+
32
+ def register_server(server_type: Type[Server]):
33
+ _scheme_to_server_types[server_type.scheme] = server_type # type: ignore
34
+ return server_type
35
+
36
+
37
+ def _check_scheme(scheme: str | None, types: dict):
38
+ if scheme == "":
39
+ scheme = None
40
+ if scheme not in types: # pragma: no cover
41
+ raise ValueError(
42
+ f"address illegal, address scheme "
43
+ f"should be one of "
44
+ f'{", ".join(types)}, '
45
+ f"got {scheme}"
46
+ )
47
+ return scheme
48
+
49
+
50
+ def get_scheme(address: str) -> str | None:
51
+ if "://" not in address:
52
+ scheme = None
53
+ else:
54
+ scheme = urlparse(address).scheme
55
+ return scheme
56
+
57
+
58
+ def get_client_type(address: str) -> Type[Client]:
59
+ scheme = _check_scheme(get_scheme(address), _scheme_to_client_types)
60
+ return _scheme_to_client_types[scheme]
61
+
62
+
63
+ def get_server_type(address: str) -> Type[Server]:
64
+ scheme = _check_scheme(get_scheme(address), _scheme_to_server_types)
65
+ return _scheme_to_server_types[scheme]
66
+
67
+
68
+ def gen_local_address(process_index: int) -> str:
69
+ return f"dummy://{process_index}"