xoscar 0.4.0__cp312-cp312-macosx_10_9_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.
Potentially problematic release.
This version of xoscar might be problematic. Click here for more details.
- xoscar/__init__.py +60 -0
- xoscar/_utils.cpython-312-darwin.so +0 -0
- xoscar/_utils.pxd +36 -0
- xoscar/_utils.pyx +241 -0
- xoscar/_version.py +693 -0
- xoscar/aio/__init__.py +16 -0
- xoscar/aio/base.py +86 -0
- xoscar/aio/file.py +59 -0
- xoscar/aio/lru.py +228 -0
- xoscar/aio/parallelism.py +39 -0
- xoscar/api.py +493 -0
- xoscar/backend.py +67 -0
- xoscar/backends/__init__.py +14 -0
- xoscar/backends/allocate_strategy.py +160 -0
- xoscar/backends/communication/__init__.py +30 -0
- xoscar/backends/communication/base.py +315 -0
- xoscar/backends/communication/core.py +69 -0
- xoscar/backends/communication/dummy.py +242 -0
- xoscar/backends/communication/errors.py +20 -0
- xoscar/backends/communication/socket.py +414 -0
- xoscar/backends/communication/ucx.py +531 -0
- xoscar/backends/communication/utils.py +97 -0
- xoscar/backends/config.py +145 -0
- xoscar/backends/context.py +404 -0
- xoscar/backends/core.py +193 -0
- xoscar/backends/indigen/__init__.py +16 -0
- xoscar/backends/indigen/backend.py +51 -0
- xoscar/backends/indigen/driver.py +26 -0
- xoscar/backends/indigen/pool.py +469 -0
- xoscar/backends/message.cpython-312-darwin.so +0 -0
- xoscar/backends/message.pyi +239 -0
- xoscar/backends/message.pyx +599 -0
- xoscar/backends/pool.py +1596 -0
- xoscar/backends/router.py +207 -0
- xoscar/backends/test/__init__.py +16 -0
- xoscar/backends/test/backend.py +38 -0
- xoscar/backends/test/pool.py +208 -0
- xoscar/batch.py +256 -0
- xoscar/collective/__init__.py +27 -0
- xoscar/collective/common.py +102 -0
- xoscar/collective/core.py +737 -0
- xoscar/collective/process_group.py +687 -0
- xoscar/collective/utils.py +41 -0
- xoscar/collective/xoscar_pygloo.cpython-312-darwin.so +0 -0
- xoscar/collective/xoscar_pygloo.pyi +239 -0
- xoscar/constants.py +21 -0
- xoscar/context.cpython-312-darwin.so +0 -0
- xoscar/context.pxd +21 -0
- xoscar/context.pyx +368 -0
- xoscar/core.cpython-312-darwin.so +0 -0
- xoscar/core.pxd +50 -0
- xoscar/core.pyx +658 -0
- xoscar/debug.py +188 -0
- xoscar/driver.py +42 -0
- xoscar/errors.py +63 -0
- xoscar/libcpp.pxd +31 -0
- xoscar/metrics/__init__.py +21 -0
- xoscar/metrics/api.py +288 -0
- xoscar/metrics/backends/__init__.py +13 -0
- xoscar/metrics/backends/console/__init__.py +13 -0
- xoscar/metrics/backends/console/console_metric.py +82 -0
- xoscar/metrics/backends/metric.py +149 -0
- xoscar/metrics/backends/prometheus/__init__.py +13 -0
- xoscar/metrics/backends/prometheus/prometheus_metric.py +70 -0
- xoscar/nvutils.py +717 -0
- xoscar/profiling.py +260 -0
- xoscar/serialization/__init__.py +20 -0
- xoscar/serialization/aio.py +138 -0
- xoscar/serialization/core.cpython-312-darwin.so +0 -0
- xoscar/serialization/core.pxd +28 -0
- xoscar/serialization/core.pyi +57 -0
- xoscar/serialization/core.pyx +944 -0
- xoscar/serialization/cuda.py +111 -0
- xoscar/serialization/exception.py +48 -0
- xoscar/serialization/numpy.py +82 -0
- xoscar/serialization/pyfury.py +37 -0
- xoscar/serialization/scipy.py +72 -0
- xoscar/utils.py +517 -0
- xoscar-0.4.0.dist-info/METADATA +223 -0
- xoscar-0.4.0.dist-info/RECORD +82 -0
- xoscar-0.4.0.dist-info/WHEEL +5 -0
- xoscar-0.4.0.dist-info/top_level.txt +2 -0
xoscar/backends/core.py
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
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
|
+
import asyncio
|
|
19
|
+
import copy
|
|
20
|
+
import logging
|
|
21
|
+
from typing import Type, Union
|
|
22
|
+
|
|
23
|
+
from .._utils import Timer
|
|
24
|
+
from ..errors import ServerClosed
|
|
25
|
+
from ..profiling import get_profiling_data
|
|
26
|
+
from .communication import Client, UCXClient
|
|
27
|
+
from .message import DeserializeMessageFailed, ErrorMessage, ResultMessage, _MessageBase
|
|
28
|
+
from .router import Router
|
|
29
|
+
|
|
30
|
+
ResultMessageType = Union[ResultMessage, ErrorMessage]
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ActorCaller:
|
|
35
|
+
__slots__ = "_client_to_message_futures", "_clients", "_profiling_data"
|
|
36
|
+
|
|
37
|
+
_client_to_message_futures: dict[Client, dict[bytes, asyncio.Future]]
|
|
38
|
+
_clients: dict[Client, asyncio.Task]
|
|
39
|
+
|
|
40
|
+
def __init__(self):
|
|
41
|
+
self._client_to_message_futures = dict()
|
|
42
|
+
self._clients = dict()
|
|
43
|
+
self._profiling_data = get_profiling_data()
|
|
44
|
+
|
|
45
|
+
def _listen_client(self, client: Client):
|
|
46
|
+
if client not in self._clients:
|
|
47
|
+
self._clients[client] = asyncio.create_task(self._listen(client))
|
|
48
|
+
self._client_to_message_futures[client] = dict()
|
|
49
|
+
client_count = len(self._clients)
|
|
50
|
+
if client_count >= 100: # pragma: no cover
|
|
51
|
+
if (client_count - 100) % 10 == 0: # pragma: no cover
|
|
52
|
+
logger.warning(
|
|
53
|
+
"Actor caller has created too many clients (%s >= 100), "
|
|
54
|
+
"the global router may not be set.",
|
|
55
|
+
client_count,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
async def get_client_via_type(
|
|
59
|
+
self, router: Router, dest_address: str, client_type: Type[Client]
|
|
60
|
+
) -> Client:
|
|
61
|
+
client = await router.get_client_via_type(
|
|
62
|
+
dest_address, client_type, from_who=self
|
|
63
|
+
)
|
|
64
|
+
self._listen_client(client)
|
|
65
|
+
return client
|
|
66
|
+
|
|
67
|
+
async def get_client(self, router: Router, dest_address: str) -> Client:
|
|
68
|
+
client = await router.get_client(dest_address, from_who=self)
|
|
69
|
+
self._listen_client(client)
|
|
70
|
+
return client
|
|
71
|
+
|
|
72
|
+
async def _listen(self, client: Client):
|
|
73
|
+
while not client.closed:
|
|
74
|
+
try:
|
|
75
|
+
try:
|
|
76
|
+
message: _MessageBase = await client.recv()
|
|
77
|
+
except (EOFError, ConnectionError, BrokenPipeError):
|
|
78
|
+
# remote server closed, close client and raise ServerClosed
|
|
79
|
+
try:
|
|
80
|
+
await client.close()
|
|
81
|
+
except (ConnectionError, BrokenPipeError):
|
|
82
|
+
# close failed, ignore it
|
|
83
|
+
pass
|
|
84
|
+
raise ServerClosed(
|
|
85
|
+
f"Remote server {client.dest_address} closed"
|
|
86
|
+
) from None
|
|
87
|
+
future = self._client_to_message_futures[client].pop(message.message_id)
|
|
88
|
+
if not future.done():
|
|
89
|
+
future.set_result(message)
|
|
90
|
+
except DeserializeMessageFailed as e:
|
|
91
|
+
message_id = e.message_id
|
|
92
|
+
future = self._client_to_message_futures[client].pop(message_id)
|
|
93
|
+
future.set_exception(e.__cause__) # type: ignore
|
|
94
|
+
except Exception as e: # noqa: E722 # pylint: disable=bare-except
|
|
95
|
+
message_futures = self._client_to_message_futures[client]
|
|
96
|
+
self._client_to_message_futures[client] = dict()
|
|
97
|
+
for future in message_futures.values():
|
|
98
|
+
future.set_exception(copy.copy(e))
|
|
99
|
+
finally:
|
|
100
|
+
# message may have Ray ObjectRef, delete it early in case next loop doesn't run
|
|
101
|
+
# as soon as expected.
|
|
102
|
+
try:
|
|
103
|
+
del message
|
|
104
|
+
except NameError:
|
|
105
|
+
pass
|
|
106
|
+
try:
|
|
107
|
+
del future
|
|
108
|
+
except NameError:
|
|
109
|
+
pass
|
|
110
|
+
await asyncio.sleep(0)
|
|
111
|
+
|
|
112
|
+
message_futures = self._client_to_message_futures[client]
|
|
113
|
+
self._client_to_message_futures[client] = dict()
|
|
114
|
+
error = ServerClosed(f"Remote server {client.dest_address} closed")
|
|
115
|
+
for future in message_futures.values():
|
|
116
|
+
future.set_exception(copy.copy(error))
|
|
117
|
+
|
|
118
|
+
async def call_with_client(
|
|
119
|
+
self, client: Client, message: _MessageBase, wait: bool = True
|
|
120
|
+
) -> ResultMessage | ErrorMessage | asyncio.Future:
|
|
121
|
+
loop = asyncio.get_running_loop()
|
|
122
|
+
wait_response = loop.create_future()
|
|
123
|
+
self._client_to_message_futures[client][message.message_id] = wait_response
|
|
124
|
+
|
|
125
|
+
with Timer() as timer:
|
|
126
|
+
try:
|
|
127
|
+
await client.send(message)
|
|
128
|
+
except ConnectionError:
|
|
129
|
+
try:
|
|
130
|
+
await client.close()
|
|
131
|
+
except ConnectionError:
|
|
132
|
+
# close failed, ignore it
|
|
133
|
+
pass
|
|
134
|
+
raise ServerClosed(f"Remote server {client.dest_address} closed")
|
|
135
|
+
|
|
136
|
+
if not wait:
|
|
137
|
+
r = wait_response
|
|
138
|
+
else:
|
|
139
|
+
r = await wait_response
|
|
140
|
+
|
|
141
|
+
self._profiling_data.collect_actor_call(message, timer.duration)
|
|
142
|
+
return r
|
|
143
|
+
|
|
144
|
+
async def call_send_buffers(
|
|
145
|
+
self,
|
|
146
|
+
client: UCXClient,
|
|
147
|
+
local_buffers: list,
|
|
148
|
+
meta_message: _MessageBase,
|
|
149
|
+
wait: bool = True,
|
|
150
|
+
) -> ResultMessage | ErrorMessage | asyncio.Future:
|
|
151
|
+
loop = asyncio.get_running_loop()
|
|
152
|
+
wait_response = loop.create_future()
|
|
153
|
+
self._client_to_message_futures[client][meta_message.message_id] = wait_response
|
|
154
|
+
|
|
155
|
+
with Timer() as timer:
|
|
156
|
+
try:
|
|
157
|
+
await client.send_buffers(local_buffers, meta_message)
|
|
158
|
+
except ConnectionError: # pragma: no cover
|
|
159
|
+
try:
|
|
160
|
+
await client.close()
|
|
161
|
+
except ConnectionError:
|
|
162
|
+
# close failed, ignore it
|
|
163
|
+
pass
|
|
164
|
+
raise ServerClosed(f"Remote server {client.dest_address} closed")
|
|
165
|
+
|
|
166
|
+
if not wait: # pragma: no cover
|
|
167
|
+
r = wait_response
|
|
168
|
+
else:
|
|
169
|
+
r = await wait_response
|
|
170
|
+
|
|
171
|
+
self._profiling_data.collect_actor_call(meta_message, timer.duration)
|
|
172
|
+
return r
|
|
173
|
+
|
|
174
|
+
async def call(
|
|
175
|
+
self,
|
|
176
|
+
router: Router,
|
|
177
|
+
dest_address: str,
|
|
178
|
+
message: _MessageBase,
|
|
179
|
+
wait: bool = True,
|
|
180
|
+
) -> ResultMessage | ErrorMessage | asyncio.Future:
|
|
181
|
+
client = await self.get_client(router, dest_address)
|
|
182
|
+
return await self.call_with_client(client, message, wait)
|
|
183
|
+
|
|
184
|
+
async def stop(self):
|
|
185
|
+
try:
|
|
186
|
+
await asyncio.gather(*[client.close() for client in self._clients])
|
|
187
|
+
except (ConnectionError, ServerClosed):
|
|
188
|
+
pass
|
|
189
|
+
self.cancel_tasks()
|
|
190
|
+
|
|
191
|
+
def cancel_tasks(self):
|
|
192
|
+
# cancel listening for all clients
|
|
193
|
+
_ = [task.cancel() for task in self._clients.values()]
|
|
@@ -0,0 +1,16 @@
|
|
|
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 .backend import IndigenActorBackend
|
|
@@ -0,0 +1,51 @@
|
|
|
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 ...backend import BaseActorBackend, register_backend
|
|
19
|
+
from ..context import IndigenActorContext
|
|
20
|
+
from .driver import IndigenActorDriver
|
|
21
|
+
from .pool import MainActorPool
|
|
22
|
+
|
|
23
|
+
__all__ = ["IndigenActorBackend"]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@register_backend
|
|
27
|
+
class IndigenActorBackend(BaseActorBackend):
|
|
28
|
+
@staticmethod
|
|
29
|
+
def name():
|
|
30
|
+
# None means Indigen is default scheme
|
|
31
|
+
# ucx can be recognized as Indigen backend as well
|
|
32
|
+
return [None, "ucx"]
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def get_context_cls():
|
|
36
|
+
return IndigenActorContext
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def get_driver_cls():
|
|
40
|
+
return IndigenActorDriver
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
async def create_actor_pool(
|
|
44
|
+
cls, address: str, n_process: int | None = None, **kwargs
|
|
45
|
+
):
|
|
46
|
+
from ..pool import create_actor_pool
|
|
47
|
+
|
|
48
|
+
assert n_process is not None
|
|
49
|
+
return await create_actor_pool(
|
|
50
|
+
address, pool_cls=MainActorPool, n_process=n_process, **kwargs
|
|
51
|
+
)
|
|
@@ -0,0 +1,26 @@
|
|
|
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 numbers import Number
|
|
17
|
+
from typing import Dict
|
|
18
|
+
|
|
19
|
+
from ...driver import BaseActorDriver
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class IndigenActorDriver(BaseActorDriver):
|
|
23
|
+
@classmethod
|
|
24
|
+
def setup_cluster(cls, address_to_resources: Dict[str, Dict[str, Number]]):
|
|
25
|
+
# nothing need to be done in driver of Indigen backend
|
|
26
|
+
pass
|