Skip to content

Commit 6623096

Browse files
committed
Add Implementation documentation.
Also change previous design file, make concept consistant.
1 parent 6b78a11 commit 6623096

File tree

2 files changed

+112
-6
lines changed

2 files changed

+112
-6
lines changed

doc/design/multi_language_interface/why_plain_c.md renamed to doc/design/multi_language_interface/00.why_plain_c.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,20 @@ extern "C"
7070
paddle_error paddle_matrix_shape(paddle_matrix matrix,
7171
uint64_t *width,
7272
uint64_t *height) {
73-
auto m = (paddle::math::matrix*)(matrix);
73+
auto m = (paddle::capi::CMatrix*)(matrix);
7474
*width = m->width();
7575
*height = m->height();
7676
}
7777
```
7878

79-
其中`paddle/math/matrix.hpp`文件内容为:
79+
其中`paddle/capi/CMatrix.hpp`文件内容为:
8080

8181
```cpp
8282
namespace paddle {
8383
namespace math {
8484

85-
class Matrix {
86-
//...
85+
class CMatrix {
86+
std::shared_ptr<paddle::Matrix> mat;
8787
};
8888

8989
} // namespace math
@@ -113,6 +113,6 @@ class Matrix {
113113
| 手写多语言绑定 | 不使用SWIG | 使用SWIG需要多语言绑定的开发人员熟练掌握SWIG配置,社区参与困难。SWIG生成的代码不能保证多语言代码风格的一致性 |
114114
115115
116-
## 简单实现
116+
## 实现
117117
118-
TBD
118+
参考[预测接口实现](./01.inference_implementation.md)
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# C-API 模型推断实现文档
2+
3+
本文档描述Paddle C-API的实现细节。Paddle C-API是多语言API的基础部分。Paddle需要暴露的API很多。先实现模型推断的API,通过模型推断API的实现作为一个样例,来进行讨论。至于为什么需要C-API,请参考[这里](./00.why_plain_c.md)
4+
5+
## 暴露接口原则
6+
7+
1. 所有的接口均为C接口。即使用`extern "C"`
8+
2. 除构造某种类型的函数(`paddle_matrix_create`等),其他函数均返回`paddle_error`。且调用时不能抛出异常或出现运行时错误。
9+
3. 所有类型名为`paddle_类型名`,所有与类型相关的函数,函数名为`paddle_类型名_函数名`
10+
4. 如果某一个Paddle Core概念(GradientMachine/Matrix)需要被暴露到其他语言,那么
11+
* 为了暴露的接口尽量简单。只暴露概念的接口,而不暴露概念的实现。即暴露`GradientMachine`或者`Matrix`但不暴露`RecurrentGradientMachine`和`CpuSparseMatrix`。
12+
* 暴露这个概念必要函数。`必要`是指,即完成某一个任务的最少函数。
13+
5. 不在`capi`接口层做过多封装。
14+
* 如果某一个Paddle概念必须要暴露,但是又过于琐碎。不在`capi`这一层进行封装,而是直接修改Paddle Core。让Paddle核心中,这一概念不再琐碎。
15+
16+
17+
## 目录结构
18+
19+
```text
20+
Paddle
21+
`-- paddle
22+
`-- capi
23+
`-- examples # The example project for C-API.
24+
`-- tests # unittests for C-API
25+
`-- capi.h # C-API header file.
26+
`-- capi_private.h # The shared header file between implementation sources.
27+
`-- matrix.{h, cpp}
28+
`-- gradient_machine.{h, cpp}
29+
`-- ...
30+
```
31+
32+
33+
Paddle的C-API目录结构如上图表所示。这个目录中除了`capi_private.h`之外的所有头文件,均会被安装到include/paddle路径下。C-API生成的二进制文件会被安装到`lib`目录下。即,安装后的目录结构为
34+
35+
```text
36+
`-- include
37+
`-- paddle
38+
`-- capi.h
39+
`-- matrix.h
40+
`-- gradient_machine.h
41+
`-- ...
42+
`-- lib
43+
`-- libpaddle_capi_shared.{so, dylib} # In mac, dynamic libary's file name extention is `dylib`
44+
`-- libpaddle_capi_whole.a # static library for all symbols of Paddle.
45+
```
46+
47+
## 实现方式
48+
49+
下面分别介绍某一类文件的实现方式。
50+
51+
### capi.h
52+
53+
`capi.h`是用户使用C-API时所唯一需要引入的头文件。在`capi.h`中,引入了类型的头文件,`matrix.h`, `gradient_machine.h`。在引入其他类型的头文件时,使用相对路径的引用方式。即`#include "matrix.h"`
54+
55+
### 具体某种类型的头文件
56+
57+
具体某种类型的头文件,即例如`matrix.h``gradient_machine.h`等。在这些头文件中,包含了某种类型的类型定义和暴露的全部函数。
58+
59+
这个头文件不假设其他文件的引用顺序,即使用户直接引用某种类型的头文件,也不应该报错(虽然不鼓励这样)。如果某一个类型需要引用另一个类型,例如`gradient_machine`需要引用`matrix`,则直接引入另一种类型的头文件,即`#include "matrix.h"`
60+
61+
### capi_private.h
62+
63+
`capi_prviate.h`是各个实现中共享的头文件,他主要包含了实际暴露的类型结构。在用户使用C-API时,Paddle的类型全部退化成`void *`,即`typedef paddle_matrix void*`。但,对于每种C-API暴露的类型,均是在`capi_private.h`中实现的结构体。
64+
65+
```cpp
66+
struct CMatrix {
67+
int type = MatrixType;
68+
std::shared_ptr<paddle::Matrix> mat;
69+
};
70+
```
71+
72+
通常,这个结构体包含两个项目。
73+
74+
* `type`是一个类型的标志。对于每种类型,type字段均不尽相同。这样,即使C-API接受的类型全是`void *`,我们也可以确定每一个参数的类型。
75+
76+
```cpp
77+
void some_c_api_function(void* some_instance) {
78+
int* type = (int *) some_instance;
79+
switch (*type) {
80+
case MatrixType:
81+
CMatrix* mat = (CMatrix *) some_instance;
82+
...
83+
...
84+
}
85+
}
86+
```
87+
* 这个结构体中的另一个项目是,Paddle Core中这一类型接口的智能指针(shared_ptr)。
88+
* 使用智能指针的原因是: 用户可以安全的释放某个C-API的实例,而不必在意Paddle Core是否还在使用这个实例。
89+
* 例如,用户通过C-API获得了神经网络的参数实例。当用户使用完这个参数后,直接删除这个参数即可。即便Paddle Core中的模型还在使用这个参数,这个参数也不会一并删除。
90+
91+
### 具体某种类型的实现文件
92+
93+
具体某种类型的实现文件,即`matrix.cpp`, `gradient_machine.cpp`等文件。在这些文件中,使用C++ 11实现了C-API的接口,并且使用`extern "C"`导出这些接口。在实现过程中,对输入参数的安全性进行了必要的判断,并将C-API接口的参数转发给`Paddle Core`
94+
95+
### libpaddle\_capi_shared.{so, dylib}
96+
97+
`libpaddle_capi_shared`是C-API导出的动态库。这个动态库的连接参数与Paddle的其他二进制(例如`paddle_traienr`)类似。用户可以直接使用这个动态库来引入Paddle C-API。具体使用方法为`-lpaddle_capi_shared`。
98+
99+
### libpaddle\_capi_whole.a
100+
101+
`libpaddle_capi_whole`是C-API导出的静态库。这个静态库包含了Paddle的全部符号。他是将`libpaddle_gserver.a`, `libpaddle_math.a`, `libpaddle_capi.a`等全部静态库中的目标文件全部打包后产生的文件。具体使用方法为`--whole-archive -lpaddle_capi_whole --no-whole-archive`。
102+
103+
104+
### examples
105+
106+
在样例中,使用`C99`开发了模型预测的样例代码。具体请参考[example/README.md](../../../paddle/capi/examples/README.md)。

0 commit comments

Comments
 (0)