昇腾社区首页
中文
注册
开发者
下载

Guard功能介绍

当前Guard主要基于下面数据结构实现,如下图所示:

主要包括下面几个模块:

Guard宏

为用户提供了几个宏来生成Guard,主要包括以下几种,通过这些宏可以进行Guard校验并生成相应的Guard,头文件所在路径为:

${INSTALL_DIR}/toolkit/tools/msopgen/template/custom_operator_sample/xx/xx/metadef/inc/graph/symbolizer/symbol_checker.h

其中,${INSTALL_DIR}请替换为CANN软件安装后文件存储路径。若安装的Ascend-cann-toolkit软件包,以root安装举例,则安装后文件存储路径为:/usr/local/Ascend/ascend-toolkit/latest。

  • 用于分支校验的ExpectGuard宏:
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    /* 校验表达式e0与e1是否相等,
    如果e0的hint值等于e1的hint值,则宏返回true,并且生成e0 == e1的Guard,
    反之,则返回false,并生成e0 != e1的Guard
    */
    #define EXPECT_SYMBOL_EQ(e0, e1)
    
    /* 校验表达式e0与e1是否不相等,
    如果e0的hint值不等于e1的hint值,则宏返回true,并且生成e0 != e1的Guard,
    反之,则返回false,并生成e0 == e1的Guard
    */
    #define EXPECT_SYMBOL_NE(e0, e1)
    
    /* 校验表达式e0是否小于e1,
    如果e0的hint值小于e1的hint值,则宏返回true,并且生成e0 < e1的Guard,
    反之,则返回false,并生成e1 <= e0的Guard
    */
    #define EXPECT_SYMBOL_LT(e0, e1)
    
    /* 校验表达式e0是否小于等于e1,
    如果e0的hint值小于等于e1的hint值,则宏返回true,并且生成e0 <= e1的Guard,
    反之,则返回false,并生成e1 < e0的Guard
    */
    #define EXPECT_SYMBOL_LE(e0, e1)
    
    /* 校验表达式e0是否大于e1,
    如果e0的hint值大于e1的hint值,则宏返回true,并且生成e1 < e0的Guard,
    反之,则返回false,并生成e0 <= e1的Guard
    */
    #define EXPECT_SYMBOL_GT(e0, e1)
    
    /* 校验表达式e0是否大于等于e1,
    如果e0的hint值大于等于e1的hint值,则宏返回true,并且生成e0 >= e1的Guard,
    反之,则返回false,并生成e0 < e1的Guard
    */
    #define EXPECT_SYMBOL_GE(e0, e1)
    
  • 用于强校验的AssertGuard宏:
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    /* 强校验表达式e0与e1是否相等,
    如果e0的hint值等于e1的hint值,则生成e0 == e1的Guard,并继续往下执行
    反之,则报错并终止流程
    */
    #define ASSERT_SYMBOL_EQ(e0, e1)
    
    /* 强校验表达式e0与e1是否不相等,
    如果e0的hint值不等于e1的hint值,则生成e0 != e1的Guard,并继续往下执行
    反之,则报错并终止流程
    */
    #define ASSERT_SYMBOL_NE(e0, e1)
    
    /* 强校验表达式e0是否小于e1,
    如果e0的hint值小于e1的hint值,则生成e0 < e1的Guard,并继续往下执行
    反之,则报错并终止流程
    */
    #define ASSERT_SYMBOL_LT(e0, e1)
    
    /* 强校验表达式e0是否小于等于e1,
    如果e0的hint值小于等于e1的hint值,则生成e0 <= e1的Guard,并继续往下执行
    反之,则报错并终止流程
    */
    #define ASSERT_SYMBOL_LE(e0, e1)
    
    /* 强校验表达式e0是否大于e1,
    如果e0的hint值大于e1的hint值,则生成e1 < e0的Guard,并继续往下执行
    反之,则报错并终止流程
    */
    #define ASSERT_SYMBOL_GT(e0, e1)
    
    /* 强校验表达式e0是否大于等于e1,
    如果e0的hint值大于等于e1的hint值,则生成e1 <= e0的Guard,并继续往下执行
    反之,则报错并终止流程
    */
    #define ASSERT_SYMBOL_GE(e0, e1)
    

StaticCheck工具类

Guard衍生能力中还提供了一些StaticCheck接口,用于判断符号关系,接口如下,头文件所在路径为:

${INSTALL_DIR}/toolkit/tools/msopgen/template/custom_operator_sample/xx/xx/metadef/inc/graph/symbolizer/symbolic_utils.h

其中,${INSTALL_DIR}请替换为CANN软件安装后文件存储路径。若安装的Ascend-cann-toolkit软件包,以root安装举例,则安装后文件存储路径为:/usr/local/Ascend/ascend-toolkit/latest。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class SymbolicUtils {
  // 基于之前生成的Guard信息判断e1与e2是否相等,仅基于已有Guard做校验,不生成新的Guard,主要用于内存优化等编译态优化时判断使用
  static bool StaticCheckEq(const Expression &e1, const Expression &e2);

  // 基于之前生成的Guard信息判断e1与e2是否不相等,仅基于已有Guard做校验,不生成新的Guard,主要用于内存优化等编译态优化时判断使用
  static bool StaticCheckNe(const Expression &e1, const Expression &e2);

  // 基于之前生成的Guard信息判断e1是否小于e2,仅基于已有Guard做校验,不生成新的Guard,主要用于内存优化等编译态优化时判断使用
  static bool StaticCheckLt(const Expression &e1, const Expression &e2);

  // 基于之前生成的Guard信息判断e1是否小于等于e2,仅基于已有Guard做校验,不生成新的Guard,主要用于内存优化等编译态优化时判断使用
  static bool StaticCheckLe(const Expression &e1, const Expression &e2);

  // 基于之前生成的Guard信息判断e1是否大于e2,仅基于已有Guard做校验,不生成新的Guard,主要用于内存优化等编译态优化时判断使用
  static bool StaticCheckGt(const Expression &e1, const Expression &e2);

  // 基于之前生成的Guard信息判断e1是否大于等于e2,仅基于已有Guard做校验,不生成新的Guard,主要用于内存优化等编译态优化时判断使用
  static bool StaticCheckGe(const Expression &e1, const Expression &e2);
}

ShapeEnvAttr

ShapeEnvContext是Guard功能的核心模块,主要提供符号hint值的存储、Guard的存储、基于Guard的化简以及符号hint值计算等功能。当对一张图的输入进行符号泛化时,会在图中生成一个ShapeEnvAttr对象,并将泛化的符号与hint值的映射关系存储其中。而ShapeEnvContext则是作为设置ShapeEnvAttr的作用域而存在的对象,用来表示某段代码需要在该ShapeEnvAttr的作用下使用Guard功能。该模块头文件所在路径为:

${INSTALL_DIR}/toolkit/tools/msopgen/template/custom_operator_sample/xx/xx/metadef/inc/graph/attribute_group/attr_group_shape_env.h

其中,${INSTALL_DIR}请替换为CANN软件安装后文件存储路径。若安装的Ascend-cann-toolkit软件包,以root安装举例,则安装后文件存储路径为:/usr/local/Ascend/ascend-toolkit/latest。

伪码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class ShapeEnvGuarder {
 public:
  explicit ShapeEnvGuarder(ShapeEnvAttr *shape_env_context);
  ~ShapeEnvGuarder();
  ShapeEnvGuarder(const ShapeEnvGuarder &) = delete;
  ShapeEnvGuarder(const ShapeEnvGuarder &&) = delete;
  ShapeEnvGuarder &operator=(const ShapeEnvGuarder &) = delete;
  ShapeEnvGuarder &&operator=(const ShapeEnvGuarder &&) = delete;
 private:
  ShapeEnvAttr *origin_context_; // ShapeEnvContext
};

void test(ComputeGraphPtr &graph) {
  auto root_graph = ge::GraphUtils::FindRootGraph(graph);
  GE_ASSERT_NOTNULL(root_graph);
  // 设置context
  ShapeEnvGuarder guarder(root_graph->GetAttrsGroup<ShapeEnvAttr>());
  // 需要生成Guard的逻辑
  xxxx
}

在上述代码中,ShapeEnvGuarder作为ShapeEnvAttr的作用域使用,当Guard对象被创建时,后续的代码都可以基于当前图中的ShapeEnvAttr使用Guard能力,当Guard对象被销毁时,则ShapeEnvAttr的影响结束。

所有Guard的使用都需要在ShapeEnvAttr的作用域中使用,否则将无法享受到Guard的能力,比如当前只有Lowering融合策略中的CanFuse和符号推导可以享受到Guard能力,而与符号化不在同一个进程内的Codegen和Schedule组件则无法享受Guard能力。

GuardCodegen模块

ShapeEnvAttr模块存储了生成的Guard信息。那么,在执行阶段,如何利用这些Guard信息呢?如前所述,Guard实际上是一系列关系表达式。因此,可以将这些表达式转换为if判断代码,并在执行阶段开始时对符号的值进行一次检查,从而实现Guard检查的功能。为此,我们提供了GuardCodegen模块,用于将Guard转换为一段检查代码。如下图所示,图中的guard_eq(s0, s1)被转化为了if (!(s0 == s1)) { return false; }语句,当此处if判断为true时,表示Guard不满足,需要进行模型重编译。