提交 4e044e34 编写于 作者: W wangguibao

Fix README

Change-Id: I44e4566f435b3868ffcefc1dca8d29676b63460b
上级 2528ffa8
......@@ -86,7 +86,6 @@ set(EXTERNAL_LIBS
brpc
)
if(WITH_MKLML)
list(APPEND EXTERNAL_LIBS ${MKLML_IOMP_LIB})
endif()
......@@ -104,9 +103,10 @@ endif()
add_subdirectory(configure)
add_subdirectory(pdcodegen)
add_subdirectory(sdk-cpp)
add_subdirectory(demo-client)
if (NOT CLIENT_ONLY)
add_subdirectory(predictor)
add_subdirectory(inferencer-fluid-cpu)
add_subdirectory(serving)
add_subdirectory(demo-serving)
endif()
......@@ -41,6 +41,22 @@ Paddle serving框架为策略工程师提供以下三层面的功能性扩展:
| |-- proto
| |-- src
| `-- tests
|-- demo-client # Client端示例;包括如文本分类、图像分类等任务的例子
| |-- conf # conf目录
| |-- data # data目录
| | \-- images
| `-- src # src目录
|-- demo-serving # Serving示例。该目录下代码与libpdserving.a联编,产出一个可执行的serving二进制
| |-- conf # Serving示例的Conf目录
| |-- data # Serving示例的data目录
| | `-- model
| | `-- paddle
| | `-- fluid
| | |-- SE_ResNeXt50_32x4d
| | `-- text_classification_lstm
| |-- op # Serving示例OP
| |-- proto # Serving示例的proto文件
| `-- scripts
|-- doc # 文档
|-- inferencer-fluid-cpu # 与PaddlePaddle CPU预测库的接口代码
| |-- include
......@@ -51,6 +67,8 @@ Paddle serving框架为策略工程师提供以下三层面的功能性扩展:
|-- predictor # Serving端库: libpdserving.a
| |-- common
| |-- conf
| |-- cts
| | `-- lib
| |-- framework
| |-- mempool
| |-- op
......@@ -60,23 +78,10 @@ Paddle serving框架为策略工程师提供以下三层面的功能性扩展:
| |-- src
| `-- unittest
|-- sdk-cpp # Client端库: libpdsdk-cpp.a
| |-- conf # Client端示例的conf目录
| |-- data # Client端示例的data目录
| | `-- images
| |-- demo # Client端示例代码;包括如文本分类、图像分类等任务的例子
| |-- include # Client端库的头文件
| |-- proto # Client端示例的proto文件
| `-- src # Client端库的源代码文件
|-- serving # Serving示例。该目录下代码与libpdserving.a联编,产出一个可执行的serving二进制
| |-- conf # Serving示例的Conf目录
| |-- data # Serving示例的data目录
| | `-- model
| | `-- paddle
| | `-- fluid
| | `-- SE_ResNeXt50_32x4d
| |-- op # Serving示例OP
| |-- proto # Serving示例的proto文件
| `-- scripts
| |-- include
| |-- plugin
| |-- proto
| `-- src
`-- tools # CI工具
`-- codestyle
```
......
......@@ -832,7 +832,6 @@ function(PROTOBUF_GENERATE_SERVING_CPP FOR_SERVING_SIDE SRCS HDRS )
list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc")
list(APPEND ${HDRS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h")
message("For serving side " ${FOR_SERVING_SIDE})
if (${FOR_SERVING_SIDE})
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc"
......
if (NOT EXISTS
${CMAKE_CURRENT_LIST_DIR}/data/text_classification/test_set.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_CURRENT_LIST_DIR}/data/text_classification)
execute_process(COMMAND wget
--no-check-certificate
https://paddle-serving.bj.bcebos.com/data/text_classification/test_set.tar.gz
--output-document
${CMAKE_CURRENT_LIST_DIR}/data/text_classification/test_set.tar.gz)
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf
"${CMAKE_CURRENT_LIST_DIR}/data/text_classification/test_set.tar.gz"
WORKING_DIRECTORY
${CMAKE_CURRENT_LIST_DIR}/data/text_classification
)
endif()
add_executable(ximage ${CMAKE_CURRENT_LIST_DIR}/src/ximage.cpp)
target_link_libraries(ximage -Wl,--whole-archive sdk-cpp
-Wl,--no-whole-archive -lpthread -lcrypto -lm -lrt -lssl -ldl
-lz)
add_executable(echo ${CMAKE_CURRENT_LIST_DIR}/src/echo.cpp)
target_link_libraries(echo -Wl,--whole-archive sdk-cpp -Wl,--no-whole-archive
-lpthread -lcrypto -lm -lrt -lssl -ldl
-lz)
add_executable(dense_format ${CMAKE_CURRENT_LIST_DIR}/src/dense_format.cpp)
target_link_libraries(dense_format -Wl,--whole-archive sdk-cpp -Wl,--no-whole-archive -lpthread -lcrypto -lm -lrt -lssl -ldl
-lz)
add_executable(sparse_format ${CMAKE_CURRENT_LIST_DIR}/src/sparse_format.cpp)
target_link_libraries(sparse_format -Wl,--whole-archive sdk-cpp -Wl,--no-whole-archive -lpthread -lcrypto -lm -lrt -lssl -ldl
-lz)
add_executable(int64tensor_format ${CMAKE_CURRENT_LIST_DIR}/src/int64tensor_format.cpp)
target_link_libraries(int64tensor_format -Wl,--whole-archive sdk-cpp -Wl,--no-whole-archive -lpthread -lcrypto -lm -lrt -lssl -ldl
-lz)
add_executable(text_classification
${CMAKE_CURRENT_LIST_DIR}/src/text_classification.cpp)
target_link_libraries(text_classification -Wl,--whole-archive sdk-cpp -Wl,--no-whole-archive -lpthread -lcrypto -lm -lrt -lssl -ldl
-lz)
add_executable(text_classification_press
${CMAKE_CURRENT_LIST_DIR}/src/text_classification_press.cpp)
target_link_libraries(text_classification_press -Wl,--whole-archive sdk-cpp -Wl,--no-whole-archive -lpthread -lcrypto -lm -lrt -lssl -ldl
-lz)
# install
install(TARGETS ximage
RUNTIME DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/image_classification/bin)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/conf DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/image_classification/)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/data/images DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/image_classification/data)
install(TARGETS echo
RUNTIME DESTINATION ${PADDLE_SERVING_INSTALL_DIR}/demo/client/echo/bin)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/conf DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/echo/)
install(TARGETS dense_format
RUNTIME DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/dense_format/bin)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/conf DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/dense_format/)
install(TARGETS sparse_format
RUNTIME DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/sparse_format/bin)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/conf DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/sparse_format/)
install(TARGETS int64tensor_format
RUNTIME DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/int64tensor_format/bin)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/conf DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/int64tensor_format/)
install(TARGETS text_classification text_classification_press
RUNTIME DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/text_classification/bin)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/conf DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/text_classification/)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/data/text_classification DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/text_classification/data)
......@@ -62,7 +62,7 @@ void print_res(const Request& req,
int main(int argc, char** argv) {
PredictorApi api;
// initialize logger instance
// initialize logger instance
#ifdef BCLOUD
logging::LoggingSettings settings;
settings.logging_dest = logging::LOG_TO_FILE;
......
......@@ -45,7 +45,7 @@ void print_res(const RequestAndResponse& req,
int main(int argc, char** argv) {
PredictorApi api;
// initialize logger instance
// initialize logger instance
#ifdef BCLOUD
logging::LoggingSettings settings;
settings.logging_dest = logging::LOG_TO_FILE;
......
......@@ -74,7 +74,7 @@ void print_res(const Request& req,
int main(int argc, char** argv) {
PredictorApi api;
// initialize logger instance
// initialize logger instance
#ifdef BCLOUD
logging::LoggingSettings settings;
settings.logging_dest = logging::LOG_TO_FILE;
......
......@@ -72,7 +72,7 @@ void print_res(const Request& req,
int main(int argc, char** argv) {
PredictorApi api;
// initialize logger instance
// initialize logger instance
#ifdef BCLOUD
logging::LoggingSettings settings;
settings.logging_dest = logging::LOG_TO_FILE;
......
......@@ -170,7 +170,7 @@ void extract_res(const Request &req, const Response &res) {
int main(int argc, char **argv) {
PredictorApi api;
// initialize logger instance
// initialize logger instance
#ifdef BCLOUD
logging::LoggingSettings settings;
settings.logging_dest = logging::LOG_TO_FILE;
......
......@@ -122,7 +122,7 @@ void print_res(const Request& req,
int main(int argc, char** argv) {
PredictorApi api;
// initialize logger instance
// initialize logger instance
#ifdef BCLOUD
logging::LoggingSettings settings;
settings.logging_dest = logging::LOG_TO_FILE;
......
......@@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "serving/op/classify_op.h"
#include "demo-serving/op/classify_op.h"
#include "demo-serving/op/reader_op.h"
#include "predictor/framework/infer.h"
#include "predictor/framework/memory.h"
#include "serving/op/reader_op.h"
namespace baidu {
namespace paddle_serving {
......
......@@ -19,7 +19,7 @@
#else
#include "paddle/fluid/inference/paddle_inference_api.h"
#endif
#include "serving/image_class.pb.h"
#include "demo-serving/image_class.pb.h"
namespace baidu {
namespace paddle_serving {
......
......@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "serving/op/common_echo_op.h"
#include "demo-serving/op/common_echo_op.h"
namespace baidu {
namespace paddle_serving {
......
......@@ -13,7 +13,7 @@
// limitations under the License.
#pragma once
#include "serving/echo_service.pb.h"
#include "demo-serving/echo_service.pb.h"
#include "predictor/common/inner_common.h"
#include "predictor/framework/channel.h"
......
......@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "serving/op/dense_echo_op.h"
#include "demo-serving/op/dense_echo_op.h"
namespace baidu {
namespace paddle_serving {
......
......@@ -13,7 +13,7 @@
// limitations under the License.
#pragma once
#include "serving/dense_service.pb.h"
#include "demo-serving/dense_service.pb.h"
#include "predictor/common/inner_common.h"
#include "predictor/framework/channel.h"
......
......@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "serving/op/int64tensor_echo_op.h"
#include "demo-serving/op/int64tensor_echo_op.h"
namespace baidu {
namespace paddle_serving {
......
......@@ -13,7 +13,7 @@
// limitations under the License.
#pragma once
#include "serving/int64tensor_service.pb.h"
#include "demo-serving/int64tensor_service.pb.h"
#include "predictor/common/inner_common.h"
#include "predictor/framework/channel.h"
......
......@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "serving/op/reader_op.h"
#include "demo-serving/op/reader_op.h"
#include <algorithm>
#include "predictor/framework/memory.h"
......
......@@ -15,12 +15,12 @@
#pragma once
#include <string>
#include <vector>
#include "demo-serving/image_class.pb.h"
#include "predictor/builtin_format.pb.h"
#include "predictor/common/inner_common.h"
#include "predictor/framework/channel.h"
#include "predictor/framework/op_repository.h"
#include "predictor/op/op.h"
#include "serving/image_class.pb.h"
// opencv
#include "opencv/cv.h"
......
......@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "serving/op/sparse_echo_op.h"
#include "demo-serving/op/sparse_echo_op.h"
namespace baidu {
namespace paddle_serving {
......
......@@ -13,7 +13,7 @@
// limitations under the License.
#pragma once
#include "serving/sparse_service.pb.h"
#include "demo-serving/sparse_service.pb.h"
#include "predictor/common/inner_common.h"
#include "predictor/framework/channel.h"
......
......@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "serving/op/text_classification_op.h"
#include "demo-serving/op/text_classification_op.h"
#include <algorithm>
#include "predictor/framework/infer.h"
#include "predictor/framework/memory.h"
......
......@@ -19,7 +19,7 @@
#else
#include "paddle/fluid/inference/paddle_inference_api.h"
#endif
#include "serving/text_classification.pb.h"
#include "demo-serving/text_classification.pb.h"
namespace baidu {
namespace paddle_serving {
......
......@@ -21,8 +21,8 @@
#include "json2pb/pb_to_json.h"
#endif
#include "demo-serving/op/write_json_op.h"
#include "predictor/framework/memory.h"
#include "serving/op/write_json_op.h"
#ifndef BCLOUD
using json2pb::ProtoMessageToJson;
......@@ -62,8 +62,7 @@ int WriteJsonOp::inference() {
return -1;
}
std::string* text = ins->mutable_response_json();
if (!ProtoMessageToJson(
classify_out->predictions(si), text, &err_string)) {
if (!ProtoMessageToJson(classify_out->predictions(si), text, &err_string)) {
LOG(ERROR) << "Failed convert message["
<< classify_out->predictions(si).ShortDebugString()
<< "], err: " << err_string;
......
......@@ -13,11 +13,11 @@
// limitations under the License.
#pragma once
#include "demo-serving/image_class.pb.h"
#include "predictor/common/inner_common.h"
#include "predictor/framework/channel.h"
#include "predictor/framework/op_repository.h"
#include "predictor/op/op.h"
#include "serving/image_class.pb.h"
namespace baidu {
namespace paddle_serving {
......
......@@ -21,8 +21,8 @@
#include "json2pb/pb_to_json.h"
#endif
#include "demo-serving/op/write_op.h"
#include "predictor/framework/memory.h"
#include "serving/op/write_op.h"
#ifndef BCLOUD
using json2pb::ProtoMessageToJson;
......@@ -62,8 +62,7 @@ int WriteOp::inference() {
return -1;
}
std::string* text = ins->mutable_response_json();
if (!ProtoMessageToJson(
classify_out->predictions(si), text, &err_string)) {
if (!ProtoMessageToJson(classify_out->predictions(si), text, &err_string)) {
LOG(ERROR) << "Failed convert message["
<< classify_out->predictions(si).ShortDebugString()
<< "], err: " << err_string;
......
......@@ -13,12 +13,12 @@
// limitations under the License.
#pragma once
#include "demo-serving/image_class.pb.h"
#include "predictor/builtin_format.pb.h"
#include "predictor/common/inner_common.h"
#include "predictor/framework/channel.h"
#include "predictor/framework/op_repository.h"
#include "predictor/op/op.h"
#include "serving/image_class.pb.h"
namespace baidu {
namespace paddle_serving {
......
......@@ -600,7 +600,7 @@ Serving扩展能力的测试是指,在不同模型上:
(右键在新窗口中浏览大图)
# 6. 净开销测试
# 5. 净开销测试
本测试是为了描画引入Serving框架后,在Serving端空转的情况下,每query消耗的时间,也就是框架引入的开销。
......@@ -612,21 +612,20 @@ Serving扩展能力的测试是指,在不同模型上:
| CNN | 1 |
| LSTM | 1 |
# 7.结论
# 6.结论
## 7.1 单线程模式下准确率和QPS等指标与单机模式对比
## 6.1 单线程模式下准确率和QPS等指标与单机模式对比
准确率:Serving模式下与单机模式下预测准确率一致
QPS:与模型特点有关:当模型预测时间极短时,Serving框架本身的开销和网络通信固定时间在单次请求中的时间占比占了绝大部分,这导致Serving模式下的QPS与单机模式相比下降明显;当预测时间较长,Serving框架开销和网络通信时间在单次请求中的占比较小,Serving模式下QPS与单机模式下相差不多。
## 7.2 Serving扩展能力
## 6.2 Serving扩展能力
当模型较为复杂时(以上述实验中CNN和LSTM模型为例),Paddle Serving能够提供较好的线性扩展能力;当模型是简单模型(以上述实验中BOW模型为例),随着serving端线程数的增加,qps的增长趋势较为杂乱,看不出明显的线性趋势。猜测是因为预测时间较短,而线程切换、框架本身的开销等占了大头,导致虽然随着线程数增加,qps也有增长,但当并发数增大时,qps反而出现下降。
## 7.3 净开销测试
## 6.3 净开销测试
本测试用来估计框架本身带来的时间消耗。
在Serving模式下,框架引入的时间开销较小,约为1ms。
if (NOT EXISTS
${CMAKE_CURRENT_LIST_DIR}/data/text_classification/test_set.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_CURRENT_LIST_DIR}/data/text_classification)
execute_process(COMMAND wget
--no-check-certificate
https://paddle-serving.bj.bcebos.com/data/text_classification/test_set.tar.gz
--output-document
${CMAKE_CURRENT_LIST_DIR}/data/text_classification/test_set.tar.gz)
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf
"${CMAKE_CURRENT_LIST_DIR}/data/text_classification/test_set.tar.gz"
WORKING_DIRECTORY
${CMAKE_CURRENT_LIST_DIR}/data/text_classification
)
endif()
include(src/CMakeLists.txt)
include(proto/CMakeLists.txt)
add_library(sdk-cpp ${sdk_cpp_srcs})
add_dependencies(sdk-cpp pdcodegen configure)
target_link_libraries(sdk-cpp brpc configure protobuf leveldb)
target_include_directories(sdk-cpp PUBLIC
${CMAKE_BINARY_DIR}/predictor/)
add_executable(ximage ${CMAKE_CURRENT_LIST_DIR}/demo/ximage.cpp)
target_link_libraries(ximage -Wl,--whole-archive sdk-cpp
-Wl,--no-whole-archive -lpthread -lcrypto -lm -lrt -lssl -ldl
-lz)
add_executable(echo ${CMAKE_CURRENT_LIST_DIR}/demo/echo.cpp)
target_link_libraries(echo -Wl,--whole-archive sdk-cpp -Wl,--no-whole-archive
-lpthread -lcrypto -lm -lrt -lssl -ldl
-lz)
add_executable(dense_format ${CMAKE_CURRENT_LIST_DIR}/demo/dense_format.cpp)
target_link_libraries(dense_format -Wl,--whole-archive sdk-cpp -Wl,--no-whole-archive -lpthread -lcrypto -lm -lrt -lssl -ldl
-lz)
add_executable(sparse_format ${CMAKE_CURRENT_LIST_DIR}/demo/sparse_format.cpp)
target_link_libraries(sparse_format -Wl,--whole-archive sdk-cpp -Wl,--no-whole-archive -lpthread -lcrypto -lm -lrt -lssl -ldl
-lz)
add_executable(int64tensor_format ${CMAKE_CURRENT_LIST_DIR}/demo/int64tensor_format.cpp)
target_link_libraries(int64tensor_format -Wl,--whole-archive sdk-cpp -Wl,--no-whole-archive -lpthread -lcrypto -lm -lrt -lssl -ldl
-lz)
add_executable(text_classification
${CMAKE_CURRENT_LIST_DIR}/demo/text_classification.cpp)
target_link_libraries(text_classification -Wl,--whole-archive sdk-cpp -Wl,--no-whole-archive -lpthread -lcrypto -lm -lrt -lssl -ldl
-lz)
add_executable(text_classification_press
${CMAKE_CURRENT_LIST_DIR}/demo/text_classification_press.cpp)
target_link_libraries(text_classification_press -Wl,--whole-archive sdk-cpp -Wl,--no-whole-archive -lpthread -lcrypto -lm -lrt -lssl -ldl
-lz)
# install
install(TARGETS sdk-cpp
ARCHIVE DESTINATION ${PADDLE_SERVING_INSTALL_DIR}/lib
)
install(TARGETS ximage
RUNTIME DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/image_classification/bin)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/conf DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/image_classification/)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/data/images DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/image_classification/data)
install(TARGETS echo
RUNTIME DESTINATION ${PADDLE_SERVING_INSTALL_DIR}/demo/client/echo/bin)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/conf DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/echo/)
install(TARGETS dense_format
RUNTIME DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/dense_format/bin)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/conf DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/dense_format/)
install(TARGETS sparse_format
RUNTIME DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/sparse_format/bin)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/conf DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/sparse_format/)
install(TARGETS int64tensor_format
RUNTIME DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/int64tensor_format/bin)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/conf DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/int64tensor_format/)
install(TARGETS text_classification text_classification_press
RUNTIME DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/text_classification/bin)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/conf DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/text_classification/)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/data/text_classification DESTINATION
${PADDLE_SERVING_INSTALL_DIR}/demo/client/text_classification/data)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include
DESTINATION ${PADDLE_SERVING_INSTALL_DIR}/include/sdk-cpp/)
FILE(GLOB inc ${CMAKE_CURRENT_BINARY_DIR}/*.pb.h)
install(FILES ${inc}
DESTINATION ${PADDLE_SERVING_INSTALL_DIR}/include/sdk-cpp)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册