Skip to content

Commit d45b17d

Browse files
authored
add sys_info utils (#5)
1 parent f78d2e3 commit d45b17d

17 files changed

Lines changed: 514 additions & 32 deletions

.gitattributes

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.py text eol=lf
2+
*.sh text eol=lf
3+
*.md text eol=lf
4+
*.ipynb text eol=lf

notebook/test-api-service.ipynb

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"id": "a03da0d4",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": [
10+
"import os, sys\n",
11+
"sys.path.insert(0, '../src/')"
12+
]
13+
},
14+
{
15+
"cell_type": "code",
16+
"execution_count": null,
17+
"id": "503e782e",
18+
"metadata": {},
19+
"outputs": [],
20+
"source": [
21+
"from aloha.service.v0 import APICaller"
22+
]
23+
},
24+
{
25+
"cell_type": "code",
26+
"execution_count": null,
27+
"id": "12967663",
28+
"metadata": {},
29+
"outputs": [],
30+
"source": [
31+
"caller = APICaller()"
32+
]
33+
},
34+
{
35+
"cell_type": "code",
36+
"execution_count": null,
37+
"id": "250d9b9c",
38+
"metadata": {},
39+
"outputs": [],
40+
"source": [
41+
"url_base = 'http://localhost:80'"
42+
]
43+
},
44+
{
45+
"cell_type": "code",
46+
"execution_count": null,
47+
"id": "5d227afd",
48+
"metadata": {},
49+
"outputs": [],
50+
"source": [
51+
"caller.call(url_base + '/api/common/sys_info', kind='gpu')"
52+
]
53+
},
54+
{
55+
"cell_type": "code",
56+
"execution_count": null,
57+
"id": "c6d390a6",
58+
"metadata": {},
59+
"outputs": [],
60+
"source": [
61+
"caller.call(url_base + '/api/common/sys_info/gpu')"
62+
]
63+
}
64+
],
65+
"metadata": {
66+
"kernelspec": {
67+
"display_name": "Python 3 (ipykernel)",
68+
"language": "python",
69+
"name": "python3"
70+
},
71+
"language_info": {
72+
"codemirror_mode": {
73+
"name": "ipython",
74+
"version": 3
75+
},
76+
"file_extension": ".py",
77+
"mimetype": "text/x-python",
78+
"name": "python",
79+
"nbconvert_exporter": "python",
80+
"pygments_lexer": "ipython3",
81+
"version": "3.10.2"
82+
}
83+
},
84+
"nbformat": 4,
85+
"nbformat_minor": 5
86+
}

src/aloha/service/http/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .plain_http_handler import PlainHttpHandler

src/aloha/service/v2/plain_http_handler.py renamed to src/aloha/service/http/plain_http_handler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from typing import Optional, Awaitable
33

44

5-
class BaseHandler(web.RequestHandler):
5+
class PlainHttpHandler(web.RequestHandler):
66
def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]:
77
pass
88

src/aloha/service/v0/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .api_handler import APIHandler
2+
from .caller import APICaller
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import abc
2+
import json
3+
import logging
4+
from typing import Optional, Awaitable
5+
6+
from tornado import web
7+
8+
from ...logger import LOG
9+
10+
_RESP_BAD_REQUEST = {'code': '5101', 'message': ['Bad request: fail to parse body as JSON object!']}
11+
12+
13+
class APIHandler(web.RequestHandler):
14+
LOG = LOG
15+
16+
def __init__(self, *args, **kwargs):
17+
super().__init__(*args, **kwargs)
18+
19+
@abc.abstractmethod
20+
def response(self, *args, **kwargs) -> dict:
21+
raise NotImplementedError()
22+
23+
def set_default_headers(self) -> None:
24+
self.set_header('Content-Type', 'application/json; charset=utf-8')
25+
26+
def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]:
27+
pass
28+
29+
async def post(self, *args, **kwargs):
30+
try:
31+
req = self.request.body
32+
body = json.loads(req.decode('utf-8'))
33+
kwargs.update(body)
34+
except json.decoder.JSONDecodeError: # invalid request body, cannot be parsed as JSON
35+
return self.finish(_RESP_BAD_REQUEST)
36+
37+
resp = dict(code=5200, message=['success'])
38+
try:
39+
result = self.response(*args, **kwargs) # this call may throw TypeError when argument missing
40+
resp['data'] = result
41+
except Exception as e:
42+
if LOG.level == logging.DEBUG:
43+
self.LOG.error(e, exc_info=True)
44+
return self.finish({'code': 5201, 'message': [str(e)]})
45+
46+
resp = json.dumps(resp, ensure_ascii=False, default=str, separators=(',', ':'))
47+
return self.finish(resp)

src/aloha/service/v0/caller.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import requests
2+
3+
from ...logger import LOG
4+
5+
6+
class APICaller:
7+
@staticmethod
8+
def wrap_request_data(data):
9+
assert isinstance(data, dict), "Data object must be a dict!"
10+
return data
11+
12+
@staticmethod
13+
def call(api_url, timeout=5, **kwargs):
14+
"""Trigger API call
15+
16+
:param api_url: do NOT start with slash (/)
17+
:param timeout: requests timeout in seconds
18+
:param kwargs: request data
19+
:return:
20+
"""
21+
payload = APICaller.wrap_request_data(data=kwargs)
22+
LOG.debug('Calling API: %s' % api_url)
23+
resp = requests.post(
24+
api_url, json=payload, timeout=timeout, headers={'Content-Type': 'application/json'}
25+
)
26+
27+
try:
28+
ret = resp.json()
29+
except Exception as e:
30+
LOG.error(str(e))
31+
raise RuntimeError(resp.text)
32+
33+
try:
34+
return ret['data']
35+
except KeyError:
36+
raise RuntimeError(resp.text)

src/aloha/service/v1/caller.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@ def call(api_url, timeout=5, **kwargs):
4646
LOG.debug('Calling API: %s' % api_url)
4747
resp = requests.post(
4848
api_url, json=payload, timeout=timeout, headers={'Content-Type': 'application/json'}
49-
).json()
50-
ret = resp['data']
51-
return ret
49+
)
50+
51+
try:
52+
ret = resp.json()
53+
except Exception as e:
54+
LOG.error(str(e))
55+
raise RuntimeError(resp.text)
56+
57+
try:
58+
return ret['data']
59+
except KeyError:
60+
raise RuntimeError(resp.text)

src/aloha/service/v2/caller.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import requests
21
import uuid
32
from datetime import datetime, timedelta
43

4+
import requests
5+
56
from ...encrypt.jwt import encode
67
from ...logger import LOG
78
from ...settings import SETTINGS
@@ -46,10 +47,15 @@ def call(cls, api_url, timeout=5, **kwargs) -> str:
4647
"""
4748
LOG.debug('Calling API: %s' % api_url)
4849
# LOG.debug('Param: %s' % json.dumps(kwargs, ensure_ascii=False))
50+
4951
resp = requests.post(
50-
api_url,
51-
json=kwargs,
52-
timeout=timeout,
53-
headers=cls.get_headers()
54-
).json()
55-
return resp
52+
api_url, json=kwargs, timeout=timeout, headers=cls.get_headers()
53+
)
54+
55+
try:
56+
ret = resp.json()
57+
except Exception as e:
58+
LOG.error(str(e))
59+
raise RuntimeError(resp.text)
60+
61+
return ret

src/aloha/util/sys_cuda.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
__all__ = ('get_cuda_info',)
2+
3+
from collections import namedtuple
4+
5+
from ..logger import LOG
6+
7+
Status = namedtuple('Status', 'version,gpu_availability')
8+
9+
10+
def get_gpu_status_for_tf() -> dict:
11+
status = Status(version=None, gpu_availability=False)
12+
try:
13+
import tensorflow as tf
14+
LOG.info('tensorflow version = %s' % tf.__version__)
15+
status = Status(
16+
version=tf.__version__,
17+
gpu_availability=tf.test.is_gpu_available()
18+
)
19+
except Exception as e:
20+
LOG.error('Error detecting CUDA availability for tensorflow')
21+
LOG.error(str(e))
22+
return status._asdict()
23+
24+
25+
def get_gpu_status_for_torch() -> dict:
26+
status = Status(version=None, gpu_availability=False)
27+
try:
28+
import torch
29+
LOG.info('torch version = %s' % torch.__version__)
30+
status = Status(
31+
version=torch.__version__,
32+
gpu_availability=torch.cuda.is_available()
33+
)
34+
except Exception as e:
35+
LOG.error('Error detecting CUDA availability for torch')
36+
LOG.error(str(e))
37+
return status._asdict()
38+
39+
40+
def get_cuda_info() -> dict:
41+
return {
42+
"cuda_availability_for_torch": get_gpu_status_for_torch(),
43+
"cuda_availability_for_tf": get_gpu_status_for_tf(),
44+
}
45+
46+
47+
def main(*args, **kwargs):
48+
data = get_cuda_info()
49+
import json
50+
print(json.dumps(data, ensure_ascii=False, indent=2))
51+
52+
53+
if __name__ == '__main__':
54+
main()

0 commit comments

Comments
 (0)