Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Xiaomi
Mace
提交
fbf80ad5
Mace
项目概览
Xiaomi
/
Mace
通知
106
Star
40
Fork
27
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Mace
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
fbf80ad5
编写于
11月 01, 2017
作者:
Y
Yin Li
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Fix perf op type
上级
c93b928a
变更
8
显示空白变更内容
内联
并排
Showing
8 changed file
with
146 addition
and
87 deletion
+146
-87
mace/dsp/hexagon/android.min
mace/dsp/hexagon/android.min
+0
-37
mace/dsp/hexagon/hexagon_controller.h
mace/dsp/hexagon/hexagon_controller.h
+21
-0
mace/dsp/hexagon/hexagon_nn.h
mace/dsp/hexagon/hexagon_nn.h
+27
-25
mace/dsp/hexagon/libhexagon_controller.so
mace/dsp/hexagon/libhexagon_controller.so
+0
-0
mace/dsp/hexagon_control_wrapper.cc
mace/dsp/hexagon_control_wrapper.cc
+66
-16
mace/dsp/hexagon_control_wrapper.h
mace/dsp/hexagon_control_wrapper.h
+3
-3
mace/dsp/hexagon_control_wrapper_test.cc
mace/dsp/hexagon_control_wrapper_test.cc
+18
-6
mace/dsp/hexagon_nn_ops.h
mace/dsp/hexagon_nn_ops.h
+11
-0
未找到文件。
mace/dsp/hexagon/android.min
已删除
100644 → 0
浏览文件 @
c93b928a
$(info ------------------------------------------)
$(info --- V = $(V))
$(info --- GLUE_DIR = $(GLUE_DIR))
$(info --- HEXAGON_SDK_ROOT = $(HEXAGON_SDK_ROOT))
$(info ------------------------------------------)
INCDIRS += ../../../libs/common/adspmsgd/ship/android_Release
LIBDIRS += ../../../libs/common/adspmsgd/ship/android_Release
BUILD_DLLS=libhexagon_controller
hexagon_controller_lib_QAICIDLS += \
interface/hexagon_nn \
$(MAKE_D_DSPCV_INCDIR)/dspCV
# hexagon interface
hexagon_controller_lib_C_SRCS += \
$V/hexagon_nn_stub \
$V/dspCV_stub
hexagon_controller_lib_DLLS += libcdsprpc
hexagon_controller_lib_LIBS += rpcmem adspmsgd
hexagon_controller_lib_LD_FLAGS += -llog
hexagon_controller_lib_DEFINES += VERIFY_PRINT_ERROR
libhexagon_controller_QAICIDLS += $(hexagon_controller_lib_QAICIDLS)
libhexagon_controller_C_SRCS += $(hexagon_controller_lib_C_SRCS)
libhexagon_controller_DLLS += $(hexagon_controller_lib_DLLS)
libhexagon_controller_LIBS += $(hexagon_controller_lib_LIBS)
libhexagon_controller_LD_FLAGS += $(hexagon_controller_lib_LD_FLAGS)
libhexagon_controller_DEFINES += $(hexagon_controller_lib_DEFINES)
BUILD_COPIES = \
$(DLLS) \
$(EXES) \
$(LIBS) \
$(SHIP_DIR)/ ;
mace/dsp/hexagon/hexagon_controller.h
0 → 100644
浏览文件 @
fbf80ad5
#ifndef MACE_DSP_HEXAGON_DSP_CONTROLLER_H_
#define MACE_DSP_HEXAGON_DSP_CONTROLLER_H_
#include "hexagon_nn.h"
#ifdef __cplusplus
extern
"C"
{
#else
#include <stdbool.h>
#endif // __cplusplus
int
hexagon_controller_InitHexagonWithMaxAttributes
(
int
enable_dcvs
,
int
bus_usage
);
int
hexagon_controller_DeInitHexagon
();
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // MACE_DSP_HEXAGON_DSP_CONTROLLER_H_
\ No newline at end of file
mace/dsp/hexagon/hexagon_nn.h
浏览文件 @
fbf80ad5
...
@@ -48,7 +48,9 @@ struct hexagon_nn_output {
...
@@ -48,7 +48,9 @@ struct hexagon_nn_output {
typedef
struct
hexagon_nn_perfinfo
hexagon_nn_perfinfo
;
typedef
struct
hexagon_nn_perfinfo
hexagon_nn_perfinfo
;
struct
hexagon_nn_perfinfo
{
struct
hexagon_nn_perfinfo
{
unsigned
int
node_id
;
unsigned
int
node_id
;
unsigned
int
node_type
;
unsigned
int
executions
;
unsigned
int
executions
;
unsigned
int
unused
;
unsigned
int
counter_lo
;
unsigned
int
counter_lo
;
unsigned
int
counter_hi
;
unsigned
int
counter_hi
;
};
};
...
...
mace/dsp/hexagon/libhexagon_controller.so
浏览文件 @
fbf80ad5
无法预览此类型文件
mace/dsp/hexagon_control_wrapper.cc
浏览文件 @
fbf80ad5
...
@@ -7,6 +7,16 @@
...
@@ -7,6 +7,16 @@
namespace
mace
{
namespace
mace
{
#define MAX_NODE 2048 * 8
enum
{
NN_GRAPH_PERFEVENT_CYCLES
=
0
,
NN_GRAPH_PERFEVENT_USER0
=
1
,
NN_GRAPH_PERFEVENT_USER1
=
2
,
NN_GRAPH_PERFEVENT_HWPMU
=
3
,
NN_GRAPH_PERFEVENT_UTIME
=
5
,
};
int
HexagonControlWrapper
::
GetVersion
()
{
int
HexagonControlWrapper
::
GetVersion
()
{
int
version
;
int
version
;
hexagon_nn_version
(
&
version
);
hexagon_nn_version
(
&
version
);
...
@@ -20,15 +30,15 @@ bool HexagonControlWrapper::Config() {
...
@@ -20,15 +30,15 @@ bool HexagonControlWrapper::Config() {
bool
HexagonControlWrapper
::
Init
()
{
bool
HexagonControlWrapper
::
Init
()
{
LOG
(
INFO
)
<<
"Hexagon init"
;
LOG
(
INFO
)
<<
"Hexagon init"
;
op_map_
.
Init
();
hexagon_controller_InitHexagonWithMaxAttributes
(
0
,
100
);
// TODO(liyin): dspCV init
nn_id_
=
hexagon_nn_init
();
nn_id_
=
hexagon_nn_init
();
ResetPerfInfo
();
return
true
;
return
true
;
}
}
bool
HexagonControlWrapper
::
Finalize
()
{
bool
HexagonControlWrapper
::
Finalize
()
{
LOG
(
INFO
)
<<
"Hexagon finalize"
;
LOG
(
INFO
)
<<
"Hexagon finalize"
;
// TODO(liyin): dspCV deinit
hexagon_controller_DeInitHexagon
();
return
true
;
return
true
;
}
}
...
@@ -36,7 +46,8 @@ bool HexagonControlWrapper::SetupGraph(NetDef net_def) {
...
@@ -36,7 +46,8 @@ bool HexagonControlWrapper::SetupGraph(NetDef net_def) {
LOG
(
INFO
)
<<
"Hexagon setup graph"
;
LOG
(
INFO
)
<<
"Hexagon setup graph"
;
// const node
// const node
for
(
const
TensorProto
&
tensor_proto
:
net_def
.
tensors
())
{
for
(
const
TensorProto
&
tensor_proto
:
net_def
.
tensors
())
{
vector
<
int
>
tensor_shape
(
tensor_proto
.
dims
().
begin
(),
tensor_proto
.
dims
().
end
());
vector
<
int
>
tensor_shape
(
tensor_proto
.
dims
().
begin
(),
tensor_proto
.
dims
().
end
());
while
(
tensor_shape
.
size
()
<
4
)
{
while
(
tensor_shape
.
size
()
<
4
)
{
tensor_shape
.
insert
(
tensor_shape
.
begin
(),
1
);
tensor_shape
.
insert
(
tensor_shape
.
begin
(),
1
);
}
}
...
@@ -49,7 +60,8 @@ bool HexagonControlWrapper::SetupGraph(NetDef net_def) {
...
@@ -49,7 +60,8 @@ bool HexagonControlWrapper::SetupGraph(NetDef net_def) {
NULL
,
NULL
,
0
);
0
);
}
else
{
}
else
{
unique_ptr
<
Tensor
>
tensor
=
serializer_
.
Deserialize
(
tensor_proto
,
DeviceType
::
CPU
);
unique_ptr
<
Tensor
>
tensor
=
serializer_
.
Deserialize
(
tensor_proto
,
DeviceType
::
CPU
);
VLOG
(
0
)
<<
"Tensor size: "
<<
tensor
->
size
();
VLOG
(
0
)
<<
"Tensor size: "
<<
tensor
->
size
();
hexagon_nn_append_const_node
(
nn_id_
,
node_id
(
tensor_proto
.
node_id
()),
hexagon_nn_append_const_node
(
nn_id_
,
node_id
(
tensor_proto
.
node_id
()),
tensor_shape
[
0
],
tensor_shape
[
1
],
tensor_shape
[
0
],
tensor_shape
[
1
],
...
@@ -58,14 +70,17 @@ bool HexagonControlWrapper::SetupGraph(NetDef net_def) {
...
@@ -58,14 +70,17 @@ bool HexagonControlWrapper::SetupGraph(NetDef net_def) {
tensor
->
raw_data
()),
tensor
->
raw_data
()),
tensor
->
raw_size
());
tensor
->
raw_size
());
}
}
VLOG
(
0
)
<<
"Const: "
<<
tensor_proto
.
name
()
<<
", node_id: "
<<
node_id
(
tensor_proto
.
node_id
())
VLOG
(
0
)
<<
"Const: "
<<
tensor_proto
.
name
()
<<
"
\n\t
shape: "
<<
tensor_shape
[
0
]
<<
" "
<<
tensor_shape
[
1
]
<<
" "
<<
tensor_shape
[
2
]
<<
" "
<<
tensor_shape
[
3
];
<<
", node_id: "
<<
node_id
(
tensor_proto
.
node_id
())
<<
"
\n\t
shape: "
<<
tensor_shape
[
0
]
<<
" "
<<
tensor_shape
[
1
]
<<
" "
<<
tensor_shape
[
2
]
<<
" "
<<
tensor_shape
[
3
];
}
}
// op node
// op node
for
(
const
OperatorDef
&
op
:
net_def
.
op
())
{
for
(
const
OperatorDef
&
op
:
net_def
.
op
())
{
int
op_id
=
op_map_
.
GetOpId
(
op
.
type
());
unsigned
int
op_id
;
MACE_CHECK
(
op_id
!=
OP_INVALID
,
"invalid op: "
,
op
.
name
());
MACE_CHECK
(
hexagon_nn_op_name_to_id
(
op
.
type
().
data
(),
&
op_id
)
==
0
,
"invalid op: "
,
op
.
name
());
vector
<
hexagon_nn_input
>
inputs
(
op
.
node_input_size
());
vector
<
hexagon_nn_input
>
inputs
(
op
.
node_input_size
());
for
(
size_t
i
=
0
;
i
<
op
.
node_input_size
();
++
i
)
{
for
(
size_t
i
=
0
;
i
<
op
.
node_input_size
();
++
i
)
{
inputs
[
i
].
src_id
=
node_id
(
op
.
node_input
(
i
).
node_id
());
inputs
[
i
].
src_id
=
node_id
(
op
.
node_input
(
i
).
node_id
());
...
@@ -80,9 +95,13 @@ bool HexagonControlWrapper::SetupGraph(NetDef net_def) {
...
@@ -80,9 +95,13 @@ bool HexagonControlWrapper::SetupGraph(NetDef net_def) {
op
.
padding
());
op
.
padding
());
hexagon_nn_append_node
(
nn_id_
,
node_id
(
op
.
node_id
()),
op_id
,
padding_type
,
hexagon_nn_append_node
(
nn_id_
,
node_id
(
op
.
node_id
()),
op_id
,
padding_type
,
inputs
.
data
(),
inputs
.
size
(),
outputs
.
data
(),
outputs
.
size
());
inputs
.
data
(),
inputs
.
size
(),
outputs
.
data
(),
outputs
.
size
());
VLOG
(
0
)
<<
"Op: "
<<
op
.
name
()
<<
", type: "
<<
op
.
type
()
<<
", node_id: "
<<
node_id
(
op
.
node_id
())
<<
", padding_type: "
<<
padding_type
;
VLOG
(
0
)
<<
"Op: "
<<
op
.
name
()
<<
", type: "
<<
op
.
type
()
<<
", node_id: "
<<
node_id
(
op
.
node_id
())
<<
", padding_type: "
<<
padding_type
;
for
(
const
auto
&
input
:
inputs
)
{
for
(
const
auto
&
input
:
inputs
)
{
VLOG
(
0
)
<<
"
\t
input: "
<<
input
.
src_id
<<
":"
<<
input
.
output_idx
;
VLOG
(
0
)
<<
"
\t
input: "
<<
input
.
src_id
<<
":"
<<
input
.
output_idx
;
}
}
...
@@ -121,7 +140,6 @@ bool HexagonControlWrapper::SetupGraph(const std::string& model_file) {
...
@@ -121,7 +140,6 @@ bool HexagonControlWrapper::SetupGraph(const std::string& model_file) {
return
SetupGraph
(
net_def
);
return
SetupGraph
(
net_def
);
}
}
bool
HexagonControlWrapper
::
TeardownGraph
()
{
bool
HexagonControlWrapper
::
TeardownGraph
()
{
LOG
(
INFO
)
<<
"Hexagon teardown graph"
;
LOG
(
INFO
)
<<
"Hexagon teardown graph"
;
return
hexagon_nn_teardown
(
nn_id_
)
==
0
;
return
hexagon_nn_teardown
(
nn_id_
)
==
0
;
...
@@ -156,15 +174,47 @@ void HexagonControlWrapper::SetDebugLevel(int level) {
...
@@ -156,15 +174,47 @@ void HexagonControlWrapper::SetDebugLevel(int level) {
void
HexagonControlWrapper
::
GetPerfInfo
()
{
void
HexagonControlWrapper
::
GetPerfInfo
()
{
LOG
(
INFO
)
<<
"Get perf info"
;
LOG
(
INFO
)
<<
"Get perf info"
;
vector
<
hexagon_nn_perfinfo
>
perf_info
(
10000
);
vector
<
hexagon_nn_perfinfo
>
perf_info
(
MAX_NODE
);
unsigned
int
n_items
;
unsigned
int
n_items
;
hexagon_nn_get_perfinfo
(
nn_id_
,
perf_info
.
data
(),
10000
,
&
n_items
);
hexagon_nn_get_perfinfo
(
nn_id_
,
perf_info
.
data
(),
MAX_NODE
,
&
n_items
);
std
::
unordered_map
<
uint32_t
,
float
>
node_id_counters
;
std
::
unordered_map
<
std
::
string
,
std
::
pair
<
int
,
float
>>
node_type_counters
;
float
total_duration
=
0.0
;
for
(
int
i
=
0
;
i
<
n_items
;
++
i
)
{
for
(
int
i
=
0
;
i
<
n_items
;
++
i
)
{
unsigned
int
node_id
=
perf_info
[
i
].
node_id
;
unsigned
int
node_type_id
=
perf_info
[
i
].
node_type
;
node_id_counters
[
node_id
]
=
((
static_cast
<
uint64_t
>
(
perf_info
[
i
].
counter_hi
)
<<
32
)
+
perf_info
[
i
].
counter_lo
)
*
1.0
f
/
perf_info
[
i
].
executions
;
LOG
(
INFO
)
<<
"node id: "
<<
perf_info
[
i
].
node_id
LOG
(
INFO
)
<<
"node id: "
<<
perf_info
[
i
].
node_id
<<
", node type: "
<<
perf_info
[
i
].
node_type
<<
", executions: "
<<
perf_info
[
i
].
executions
<<
", executions: "
<<
perf_info
[
i
].
executions
<<
", counter_hi: "
<<
perf_info
[
i
].
counter_hi
<<
", duration: "
<<
node_id_counters
[
node_id
];
<<
", counter_lo: "
<<
perf_info
[
i
].
counter_lo
;
char
node_type_buf
[
1280
];
hexagon_nn_op_id_to_name
(
node_type_id
,
node_type_buf
,
1280
);
std
::
string
node_type
(
node_type_buf
);
if
(
node_type_counters
.
find
(
node_type
)
==
node_type_counters
.
end
())
{
node_type_counters
[
node_type
]
=
{
0
,
0.0
};
}
++
node_type_counters
[
node_type
].
first
;
node_type_counters
[
node_type
].
second
+=
node_id_counters
[
node_id
];
total_duration
+=
node_id_counters
[
node_id
];
}
for
(
auto
&
node_type_counter
:
node_type_counters
)
{
LOG
(
INFO
)
<<
"node type: "
<<
node_type_counter
.
first
<<
", time: "
<<
node_type_counter
.
second
.
first
<<
", duration: "
<<
node_type_counter
.
second
.
second
;
}
}
LOG
(
INFO
)
<<
"total duration: "
<<
total_duration
;
}
void
HexagonControlWrapper
::
ResetPerfInfo
()
{
LOG
(
INFO
)
<<
"Reset perf info"
;
hexagon_nn_reset_perfinfo
(
nn_id_
,
NN_GRAPH_PERFEVENT_UTIME
);
}
}
}
// namespace mace
}
// namespace mace
\ No newline at end of file
mace/dsp/hexagon_control_wrapper.h
浏览文件 @
fbf80ad5
...
@@ -5,7 +5,7 @@
...
@@ -5,7 +5,7 @@
#ifndef MACE_DSP_HEXAGON_CONTROL_WRAPPER_H_
#ifndef MACE_DSP_HEXAGON_CONTROL_WRAPPER_H_
#define MACE_DSP_HEXAGON_CONTROL_WRAPPER_H_
#define MACE_DSP_HEXAGON_CONTROL_WRAPPER_H_
#include "mace/dsp/hexagon/hexagon_
nn
.h"
#include "mace/dsp/hexagon/hexagon_
controller
.h"
#include "mace/dsp/hexagon_nn_ops.h"
#include "mace/dsp/hexagon_nn_ops.h"
#include "mace/core/common.h"
#include "mace/core/common.h"
#include "mace/core/tensor.h"
#include "mace/core/tensor.h"
...
@@ -57,18 +57,18 @@ class HexagonControlWrapper {
...
@@ -57,18 +57,18 @@ class HexagonControlWrapper {
void
PrintLog
();
void
PrintLog
();
void
PrintGraph
();
void
PrintGraph
();
void
GetPerfInfo
();
void
GetPerfInfo
();
void
ResetPerfInfo
();
void
SetDebugLevel
(
int
level
);
void
SetDebugLevel
(
int
level
);
private:
private:
// CAVEAT: Need offset as HVX library reserves some ids
// CAVEAT: Need offset as HVX library reserves some ids
static
constexpr
int
NODE_ID_OFFSET
=
10000
;
static
constexpr
int
NODE_ID_OFFSET
=
10000
;
uint32_t
node_id
(
uint32_t
nodeid
)
{
inline
uint32_t
node_id
(
uint32_t
nodeid
)
{
return
NODE_ID_OFFSET
+
nodeid
;
return
NODE_ID_OFFSET
+
nodeid
;
}
}
int
nn_id_
;
int
nn_id_
;
OpMap
op_map_
;
Serializer
serializer_
;
Serializer
serializer_
;
vector
<
index_t
>
input_shape_
;
vector
<
index_t
>
input_shape_
;
...
...
mace/dsp/hexagon_control_wrapper_test.cc
浏览文件 @
fbf80ad5
...
@@ -13,22 +13,34 @@ TEST(HexagonControlerWrapper, GetVersion) {
...
@@ -13,22 +13,34 @@ TEST(HexagonControlerWrapper, GetVersion) {
HexagonControlWrapper
wrapper
;
HexagonControlWrapper
wrapper
;
VLOG
(
0
)
<<
"version: "
<<
wrapper
.
GetVersion
();
VLOG
(
0
)
<<
"version: "
<<
wrapper
.
GetVersion
();
wrapper
.
Init
();
wrapper
.
Init
();
wrapper
.
SetDebugLevel
(
3
);
wrapper
.
SetDebugLevel
(
0
);
wrapper
.
Config
();
wrapper
.
Config
();
VLOG
(
0
)
<<
wrapper
.
SetupGraph
(
"quantized_
tes
t_dsp.pb"
);
VLOG
(
0
)
<<
wrapper
.
SetupGraph
(
"quantized_
icne
t_dsp.pb"
);
wrapper
.
PrintGraph
();
wrapper
.
PrintGraph
();
Tensor
input_tensor
;
Tensor
input_tensor
;
Tensor
output_tensor
;
Tensor
output_tensor
;
input_tensor
.
Resize
({
1
,
28
,
28
,
3
});
input_tensor
.
Resize
({
1
,
480
,
480
,
3
});
float
*
input_data
=
input_tensor
.
mutable_data
<
float
>
();
float
*
input_data
=
input_tensor
.
mutable_data
<
float
>
();
for
(
int
i
=
0
;
i
<
input_tensor
.
size
();
++
i
)
{
for
(
int
i
=
0
;
i
<
input_tensor
.
size
();
++
i
)
{
input_data
[
i
]
=
i
;
input_data
[
i
]
=
i
%
256
;
}
}
wrapper
.
ResetPerfInfo
();
timeval
tv1
,
tv2
;
gettimeofday
(
&
tv1
,
NULL
);
int
round
=
2
;
for
(
int
i
=
0
;
i
<
round
;
++
i
)
{
VLOG
(
0
)
<<
wrapper
.
ExecuteGraph
(
input_tensor
,
&
output_tensor
);
VLOG
(
0
)
<<
wrapper
.
ExecuteGraph
(
input_tensor
,
&
output_tensor
);
wrapper
.
PrintLog
();
}
gettimeofday
(
&
tv2
,
NULL
);
VLOG
(
0
)
<<
"avg duration: "
<<
((
tv2
.
tv_sec
-
tv1
.
tv_sec
)
*
1000
+
(
tv2
.
tv_usec
-
tv1
.
tv_usec
)
/
1000
)
/
round
;
wrapper
.
GetPerfInfo
();
wrapper
.
GetPerfInfo
();
wrapper
.
PrintLog
();
const
float
*
output_data
=
output_tensor
.
data
<
float
>
();
const
float
*
output_data
=
output_tensor
.
data
<
float
>
();
VLOG
(
0
)
<<
output_tensor
.
size
()
<<
output_tensor
.
dtype
();
VLOG
(
0
)
<<
output_tensor
.
size
()
<<
output_tensor
.
dtype
();
...
...
mace/dsp/hexagon_nn_ops.h
浏览文件 @
fbf80ad5
...
@@ -12,6 +12,9 @@ namespace mace {
...
@@ -12,6 +12,9 @@ namespace mace {
#define OP_INVALID -1
#define OP_INVALID -1
// The following macros are deprecated unless we found cache op meta in stub
// is necessary for performance or other causes.
typedef
enum
op_type_enum
{
typedef
enum
op_type_enum
{
#define DEF_OP(NAME, ...) OP_##NAME,
#define DEF_OP(NAME, ...) OP_##NAME,
...
@@ -21,6 +24,14 @@ typedef enum op_type_enum {
...
@@ -21,6 +24,14 @@ typedef enum op_type_enum {
#undef DEF_OP
#undef DEF_OP
}
op_type
;
}
op_type
;
#define DEF_OP(NAME,...) #NAME,
static
const
char
*
hexagon_nn_op_names
[
NN_OPS_MAX
]
=
{
#include "mace/dsp/ops.h"
};
#undef DEF_OP
class
OpMap
{
class
OpMap
{
public:
public:
void
Init
()
{
void
Init
()
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录