Skip to content

Commit

Permalink
support multiple models;
Browse files Browse the repository at this point in the history
  • Loading branch information
chaoqing committed Apr 25, 2024
1 parent 86c7f03 commit 61ddf74
Show file tree
Hide file tree
Showing 13 changed files with 339 additions and 164 deletions.
16 changes: 14 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@
],
"files.associations": {
"tuple": "cpp",
"array": "cpp"
"array": "cpp",
"ostream": "cpp",
"type_traits": "cpp",
"optional": "cpp",
"*.tcc": "cpp",
"random": "cpp",
"fstream": "cpp",
"functional": "cpp",
"istream": "cpp",
"limits": "cpp",
"sstream": "cpp",
"streambuf": "cpp",
"complex": "cpp"
}
}
}
6 changes: 3 additions & 3 deletions assets/images/coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 12 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "PyCXpress"
version = "0.0.4"
version = "0.0.5"
description = "PyCXpress is a high-performance hybrid framework that seamlessly integrates Python and C++ to harness the flexibility of Python and the speed of C++ for efficient and expressive computation, particularly in the realm of deep learning and numerical computing."
readme = "README.md"
authors = ["chaoqing <[email protected]>"]
Expand Down Expand Up @@ -63,6 +63,7 @@ pytest-cov = "^5.0.0"

[tool.poetry.group.dev.dependencies]
debugpy = "^1.8.1"
find-libpython = "^0.4.0"

[tool.black]
# https://github.com/psf/black
Expand Down
3 changes: 1 addition & 2 deletions src/PyCXpress/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
"version",
]

import sys
from importlib import metadata as importlib_metadata
from pathlib import Path

Expand All @@ -32,8 +31,8 @@ def get_version() -> str:
ModelRuntimeType,
TensorMeta,
convert_to_spec_tuple,
pycxpress_debugger,
)
from .debugger import pycxpress_debugger


def get_include() -> str:
Expand Down
98 changes: 26 additions & 72 deletions src/PyCXpress/core.py
Original file line number Diff line number Diff line change
@@ -1,78 +1,21 @@
# mypy: disable_error_code="type-arg,arg-type,union-attr,operator,assignment,misc"
import logging

logger = logging.getLogger(__name__)


from typing import Callable, Dict, Iterable, List, Optional, Tuple, Union

import os
from collections import namedtuple
from dataclasses import dataclass
from enum import Enum, auto
from itertools import chain

import numpy as np
from numpy.typing import DTypeLike

# import tensorflow as tf


def pycxpress_debugger(
host: Optional[str] = None,
port: Optional[int] = None,
debugger: Optional[str] = None,
):
if debugger is None:
return

if host is None:
host = os.environ.get("PYCXPRESS_DEBUGGER_HOST", "localhost")

if port is None:
port = os.environ.get("PYCXPRESS_DEBUGGER_PORT", 5678)

if debugger.lower() == "pycharm":
try:
import pydevd_pycharm

pydevd_pycharm.settrace(
host, port=port, stdoutToServer=True, stderrToServer=True, suspend=True
)
except ConnectionRefusedError:
logger.warning(
"Can not connect to Python debug server (maybe not started?)"
)
logger.warning(
"Use PYCXPRESS_DEBUGGER_TYPE=debugpy instead as Pycharm professional edition is needed for Python debug server feature."
)
elif debugger.lower() == "debugpy":
import debugpy

debugpy.listen((host, port))
logger.info(f"debugpy listen on {host}:{port}, please use VSCode to attach")
debugpy.wait_for_client()
else:
logger.warning(
f"Only PYCXPRESS_DEBUGGER_TYPE=debugpy|pycharm supported but {debugger} provided"
)


def get_c_type(t: DTypeLike) -> Tuple[str, int]:
dtype = np.dtype(t)
relation = {
np.dtype("bool"): "bool",
np.dtype("int8"): "int8_t",
np.dtype("int16"): "int16_t",
np.dtype("int32"): "int32_t",
np.dtype("int64"): "int64_t",
np.dtype("uint8"): "uint8_t",
np.dtype("uint16"): "uint16_t",
np.dtype("uint32"): "uint32_t",
np.dtype("uint64"): "uint64_t",
np.dtype("float32"): "float",
np.dtype("float64"): "double",
}
return relation.get(dtype, "char"), dtype.itemsize or 1
from .interface import (
InputTensorProtocol,
ModelProtocol,
OutputTensorProtocol,
TensorBufferProtocol,
)
from .utils import get_c_type, logger


@dataclass
Expand Down Expand Up @@ -162,11 +105,11 @@ def __new__(

@staticmethod
def general_funcs(name: str, field_names: List[str]):
def get_buffer_shape(self, name: str):
buffer = getattr(self.__buffer_data__, name)
return buffer.shape
def get_buffer_shape(self, name: str) -> Tuple[int]:
shape: Tuple[int] = getattr(self.__buffer_data__, name).shape
return shape

def set_buffer_value(self, name: str, value):
def set_buffer_value(self, name: str, value: np.ndarray) -> None:
buffer = getattr(self.__buffer_data__, name)
buffer.data = value

Expand Down Expand Up @@ -209,9 +152,20 @@ def del_func(_):
return property(fget=get_func, fset=set_func, fdel=del_func, doc=field.doc)


def convert_to_spec_tuple(fields: Iterable[TensorMeta]):
return tuple(
(v["name"], v["dtype"], v["buffer_size"]) for v in [v.to_dict() for v in fields]
def convert_to_spec_tuple(
inputFields: Iterable[TensorMeta], outputFields: Iterable
) -> Iterable[TensorBufferProtocol]:
return chain.from_iterable(
[
(
(v["name"], v["dtype"], v["buffer_size"], False)
for v in [v.to_dict() for v in inputFields]
),
(
(v["name"], v["dtype"], v["buffer_size"], True)
for v in [v.to_dict() for v in outputFields]
),
]
)


Expand Down
54 changes: 54 additions & 0 deletions src/PyCXpress/debugger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from typing import Optional

import os

from .utils import logger

_debugger_status_ = [False]


def pycxpress_debugger(
host: Optional[str] = None,
port: Optional[int] = None,
debugger: Optional[str] = None,
):
if _debugger_status_[0] == True:
return

if debugger is None:
return

if host is None:
host = os.environ.get("PYCXPRESS_DEBUGGER_HOST", "localhost")

if port is None:
port = int(os.environ.get("PYCXPRESS_DEBUGGER_PORT", "5678"))

if debugger.lower() == "pycharm":
try:
import pydevd_pycharm

pydevd_pycharm.settrace(
host, port=port, stdoutToServer=True, stderrToServer=True, suspend=True
)
_debugger_status_[0] = True

except ConnectionRefusedError:
logger.warning(
"Can not connect to Python debug server (maybe not started?)"
)
logger.warning(
"Use PYCXPRESS_DEBUGGER_TYPE=debugpy instead as Pycharm professional edition is needed for Python debug server feature."
)
elif debugger.lower() == "debugpy":
import debugpy

_debugger_status_[0] = True

debugpy.listen((host, port))
logger.info(f"debugpy listen on {host}:{port}, please use VSCode to attach")
debugpy.wait_for_client()
else:
logger.warning(
f"Only PYCXPRESS_DEBUGGER_TYPE=debugpy|pycharm supported but {debugger} provided"
)
7 changes: 5 additions & 2 deletions src/PyCXpress/example/Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# Compiler
CC = c++
PYTHONPATH=../../
LD_PRELOAD:=$(shell find_libpython)

# Compiler flags
CFLAGS = -g -Wall -std=c++17 -fPIC
CFLAGS += $(shell python3-config --cflags --ldflags --embed)
CFLAGS += $(shell PYTHONPATH=../../ python3 -m PyCXpress --includes)
CFLAGS += $(shell PYTHONPATH=$(PYTHONPATH) python3 -m PyCXpress --includes)

# The build target executable
TARGET = example.out
Expand Down Expand Up @@ -36,7 +38,8 @@ clean:
rm -f $(OBJECTS) $(DEPENDS) $(TARGET)

run: $(TARGET)
PYTHONPATH=../src/ ./$(TARGET)
$(info [reminding]: use LD_PRELOAD to load libpython before numpy import)
PYTHONPATH=$(PYTHONPATH) LD_PRELOAD=$(LD_PRELOAD) ./$(TARGET)

memcheck: $(TARGET)
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes -s ./$(TARGET)
13 changes: 10 additions & 3 deletions src/PyCXpress/example/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace pcx = PyCXpress;

void show_test(pcx::PythonInterpreter &python) {
void show_test(pcx::Model &python) {
std::vector<double> data(12);
for (size_t i = 0; i < 12; i++) {
data[i] = i;
Expand Down Expand Up @@ -41,12 +41,19 @@ void show_test(pcx::PythonInterpreter &python) {

int main(int argc, char *argv[]) {
auto &python = utils::Singleton<pcx::PythonInterpreter>::Instance();
auto &model0 = python.create_model("model.Model");
auto &model1 = python.create_model("model.Model", "odd");
int loop_times = 3;


while (loop_times--) {
std::cout << "looping " << loop_times << std::endl;
show_test(python);
if (loop_times % 2 == 0) {
show_test(model0);
} else {
show_test(model1);
}
}

return 0;
}
}
Loading

0 comments on commit 61ddf74

Please sign in to comment.