Object.h概述

命名空间:

TVM::runtime

文件中包含的结构:

  • 1.结构体TypeIndex
  • 2.类Object
  • 3.类ObjectPtr
  • 4.类ObjectRef
  • 5.结构体ObjectPtrHash
  • 6.结构体ObjectPtrEqual
  • 7.宏

结构体TypeIndex

该结构体内部仅包含一个枚举类型,通过下面的代码可以看到,Object类存在一个TypeIndex类型的成员变量。

/*!
* \brief Namespace for the list of type index.
* \note Use struct so that we have to use TypeIndex::ENumName to refer to
* the constant, but still able to use enum.
*/
struct TypeIndex {
enum {
/*! \brief Root object type. */
kRoot = 0,
// Standard static index assignments,
// Frontends can take benefit of these constants.
/*! \brief runtime::Module. */
kRuntimeModule = 1,
/*! \brief runtime::NDArray. */
kRuntimeNDArray = 2,
/*! \brief runtime::String. */
kRuntimeString = 3,
/*! \brief runtime::Array. */
kRuntimeArray = 4,
/*! \brief runtime::Map. */
kRuntimeMap = 5,
/*! \brief runtime::ShapeTuple. */
kRuntimeShapeTuple = 6,
/*! \brief runtime::PackedFunc. */
kRuntimePackedFunc = 7,
// static assignments that may subject to change.
kRuntimeClosure,
kRuntimeADT,
kStaticIndexEnd,
/*! \brief Type index is allocated during runtime. */
kDynamic = kStaticIndexEnd
};
}; // namespace TypeIndex

为什么要将enum类型放在一个struct结构体中呢?

避免命名冲突

包含在struct的{}中,相当于在一个命名空间下,这样已经能够避免命名冲突的问题,而且使用起来比较方便TypeIndex::ENumName。同样也可以将其放在类中,但由于enum中的类型信息本就是对外部开放的,因此struct相较于class更为简洁方便。

参考:C++ enum枚举型

在TypeIndex中可以看到,共有四种object type:

  • 1.kRoot:root object type
  • 2.前端可以获取的常量:

1.runtime::Module

2.runtime::NDArray

3.runtime::String

4.runtime::Array

5.runtime::Map

6.runtime::ShapeTuple

7.runtime::PackedFunc

  • 3.static assignments that may subject to change 可能发生变化的静态分配
  • 4.Type index is allocated during runtime.运行时分配的Type Index

kDynamic

Class Object

成员变量:

tvm::runtime::Object
+ _type_key
+ _type_final
+ _type_child_slots
+ _type_child_slots_can_overflow
+ _type_has_method_visit_attrs
+ _type_has_method_sequal_reduce
+ _type_has_method_shash_reduce
+ _type_index
# type_index_
# ref_counter_
# deleter_

可以看到,除了类的回收器deleter_和引用计数ref_counter外,其余成员变量都是关于type_index的标志位或子类插槽(slots)等信息。由于作为多有容器对象的基类(base class of all object containers.)所以主要提供了一系列的操作接口。但最重要的成员变量是type_index_。

成员函数:

成员函数主要是类相关的构造函数,拷贝构造、拷贝复制、move构造、move赋值函数

其次是type_index_相关的函数

剩下的为引用计数相关函数。

类相关

// 构造函数
// Default constructor and copy constructor
Object() {}

// 拷贝构造
// Override the copy and assign constructors to do nothing.
// This is to make sure only contents, but not deleter and ref_counter
// are copied when a child class copies itself.
// This will enable us to use make_object<ObjectClass>(*obj_ptr)
// to copy an existing object.
Object(const Object& other) { // NOLINT(*)
}

// 移动构造(move)
Object(Object&& other) { // NOLINT(*)
}

// 拷贝赋值
Object& operator=(const Object& other) { // NOLINT(*)
return *this;
}

// 移动构造(move)
Object& operator=(Object&& other) { // NOLINT(*)
return *this;
}

// 析构器(FDeleter函数指针)
typedef void (*FDeleter)(Object* self);

type_index_相关

uint32_t type_index() const { return type_index_; }

std::string GetTypeKey() const { return TypeIndex2Key(type_index_); }

std::string GetTypeKey() const { return TypeIndex2Key(type_index_); }

static std::string TypeIndex2Key(uint32_t tindex);

static size_t TypeIndex2KeyHash(uint32_t tindex);

static uint32_t TypeKey2Index(const std::string& key);

template <typename TargetType>
inline bool IsInstance() const; static uint32_t _GetOrAllocRuntimeTypeIndex() { return TypeIndex::kRoot; } static uint32_t RuntimeTypeIndex() { return TypeIndex::kRoot; } static uint32_t GetOrAllocRuntimeTypeIndex(const std::string& key, uint32_t static_tindex,
uint32_t parent_tindex, uint32_t type_child_slots,
bool type_child_slots_can_overflow);

继承、引用计数相关

void IncRef();

void DecRef();

int use_count() const;

DerivedFrom(uint32_t parent_tindex) const;

友元类

template <typename>
friend class ObjAllocatorBase; template <typename>
friend class ObjectPtr; friend class TVMRetValue; friend class ObjectInternal;

class ObjectPtr

注释中将这个类描述为 A custom smart pointer for Object.一个用户自定义的指向Object类的智能指针。

其中最重要的成员变量和成员函数为:

 private:
/*! \brief internal pointer field */
Object* data_{nullptr};
/*!
* \brief constructor from Object
* \param data The data pointer
*/
explicit ObjectPtr(Object* data) : data_(data) {
if (data != nullptr) {
data_->IncRef();
}
}

可以看到,该类的成员变量中包含一个指向Object对象的指针 data_,以及一个私有的构造函数,接收一个指向Object对象的指针,初始化data_并增加 data_的引用计数

该类中的其余函数主要是类的多种构造函数,以及重载了多个运算符,供用户将该类的对象作为指针使用。

总结:因此可以将ObjectPtr看作是一个指向Object对象的指针的包装器,其本质依旧是Object类型的指针。经过包装后我们可以根据其提供的各种接口,更加方便地对指针进行操作。值得注意的是,该类是一个模板类,因此该类的对象包含一个描述Object对象的类型

class ObjectRef

注释中将该类描述为 Base class of all object reference所有对象引用的基类。

其中最重要的成员变量和成员函数为:

 protected:
/*! \brief Internal pointer that backs the reference. */
ObjectPtr<Object> data_;

该类中包含了一个ObjectPtr的对象。因此可以看做是ObjectPtr的包装器。除该对象外,ObjectRef类也提供了多种函数接口,方便用户操作。

Object、ObjectPtr、ObjectRef关系

ObjectPtr类是封装的、指向Object类的一个智能指针类

/*!
* \brief A custom smart pointer for Object.
* \tparam T the content data type.
* \sa make_object
*/
template <typename T>
class ObjectPtr {
public:
ObjectPtr() {}
ObjectPtr(std::nullptr_t) {} // NOLINT(*)
ObjectPtr(const ObjectPtr<T>& other) // NOLINT(*)
: ObjectPtr(other.data_) {} template <typename U>
ObjectPtr(const ObjectPtr<U>& other) // NOLINT(*)
: ObjectPtr(other.data_) {
static_assert(std::is_base_of<T, U>::value,
"can only assign of child class ObjectPtr to parent");
}
......
// 关键数据成员,一个指向Object对象的指针
Object *data_{nullptr};
// 几个关键的运算符重载接口,用于获取指向Object的指针或者引用
T* get() const { return static_cast<T*>(data_); }
T* operator->() const { return get(); }
T& operator*() const { return *get(); }

包含了智能指针应该有的:拷贝构造、移动构造、swap函数、运算符重载等的实现,可参考C++智能指针

使用自定义的智能指针管理Object对象生命周期,便于管理,防止内存泄漏

ObjectRef类为所有对象引用的基类( Base class of all object reference)

它的关键数据成员和几个运算符重载接口如下:

// 关键数据成员
ObjectPtr<Object> data_;
// 关键运算符重载接口
const Object* get() const { return data_.get(); }
const Object* operator->() const { return get(); }

在具体的使用中,Object机制有两套继承体系,一套继承自Object用于表示实际的类, 一套继承自ObjectRef,它就像是指向实际类对象的智能指针,用于操作实际的类对象,虽然实际上没有shared_ptr,但我们可以用下图来帮助理解这两套继承体系:

Object的所有子类基本上都遵循了 NameNode 继承 Object,Name继承 ObjectRef;,例如:

/*! \brief Base node of all statements. */
class StmtNode : public Object /*! \brief Container of all statements */
class Stmt : public ObjectRef

而 ObjectPtr作为模板类,记录有指向Object类对象的类型,在使用过程中,会出现指针的向下转型(downcast)以及类型转换等操作,因此其作用主要做转型和检查。

使用场景:对Object的子类做修改

SumExpr ToSumExpr(PrimExpr expr) {
// Ref对象调用.as<>()函数返回一个类型为<SumExprNode>的Ptr
if (const auto* op = expr.as<SumExprNode>()) {
// 通过Ptr构造Ref
return GetRef<SumExpr>(op);
}
// 通过make_object创建<>类型对象,并返回指向该对象的指针。
ObjectPtr<SumExprNode> n = make_object<SumExprNode>();
n->dtype = expr.dtype();
// Ref对象调用.as<>()函数返回一个类型为<>的Ptr
if (const auto* op = expr.as<IntImmNode>()) {
// 通过Ref对内容进行操作
n->base = op->value;
// 通过Ptr构造Ref对象
return SumExpr(n);
} else {
n->args.emplace_back(ToSplitExpr(expr));
return SumExpr(n);
}
}

ObjectPtr:用于记录类型,类型检查(.as()),对Object实体内容进行操作,还可以作为构造引用的参数。

Object:为对象实体。

ObjectRef:作为函数间传递和处理的形式。

如果拿Object、ObjectPtr、ObjectRef这三个类和shared_ptr类比的话:

  • Object相当于控制块,可以通过引用计数ref_counter_来控制对象的生命周期,对象的析构函数也可以通过delete_这个函数指针指定

  • Object的子类的除去Object基类的部分相当于数据块,里面保存有类的真实数据

  • ObjectRef就像是shared_ptr这个wrapper,自身不包含实际数据,但是可以操作实际的数据

  • ObjectPtr的作用在使用的角度有点类似ObjectRef,不同的是数据类型,ObjectPtr<T>是一个模板

参考:

深入理解TVM:Object家族(二)

TVM源码品读:万物基石——Object类(1)

TVM:Object家族的更多相关文章

  1. 深入C#数据类型

    一:值类型与引用类型 值类型源于System.ValueType家族,值类型包括基本数据类型,结构类型和枚举类型. 值类型:在栈上储存的真实的值. 引用类型源于System.Object家族,在C#中 ...

  2. 深入.net平台和c#编程 学习笔记

    深入.net平台和c#编程 一:理解.nteFramwork与c# 1.1,:Microsoft.net框架概述 1.2:.net框架结构 1.3.:c#语言概述 1.4:体验框架类库的强大功能 二: ...

  3. 深入C#.NET数据类型

    深入C#数据类型 --不同类型的参数传递使用值传递,在方法中对参数的更改在调用后不能保留.使用ref方式传递,可以保留对参数值的更改. ---值方式参数传递和引用方式传递使用值方式(不用ref修饰)传 ...

  4. 第二章 深入C#数据类型

    深入C#数据类型       巧记:值(无ref)+值=不变 值(无ref)+引=变     引(有ref)+值/引=变     1.值类型和引用类型 1.引用类型 源于system.object家族 ...

  5. 加深对C#数据类型的认识

    值类型: 值类型源于System.Value家族,每个值类型的对象都有一个独立的内存区域用于保存自己的值,值类型 所在的内存区域称之为栈(Stack),只要在代码中修改它,就会在内存区域保存这个值. ...

  6. [Machine Learning & Algorithm]CAML机器学习系列1:深入浅出ML之Regression家族

    声明:本博客整理自博友@zhouyong计算广告与机器学习-技术共享平台,尊重原创,欢迎感兴趣的博友查看原文. 符号定义 这里定义<深入浅出ML>系列中涉及到的公式符号,如无特殊说明,符号 ...

  7. java中Array/List/Map/Object与Json互相转换详解(转载)

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.易于人阅读和编写.同时也易于机器解析和生成.它基于JavaScript Programming Langu ...

  8. 走进Java Map家族 (1) - HashMap实现原理分析

    在Java世界里,有一个古老而神秘的家族——Map.从底层架构到上层应用,他们活跃于世界的每一个角落.但是,每次出现时,他们都戴着一张冷硬的面具(接口),深深隐藏着自己的内心.所有人都认识他们,却并非 ...

  9. JVM家族史考【转】

    说起Java虚拟机,许多Java程序员都会潜意识地把它与Sun(虽然太阳已然西落,但永远值得被记忆) HotSpot虚拟机等同看待,也许还有一些程序员会注意到BEA JRockit和IBM J9,但大 ...

  10. js中对象的一些特性,JSON,scroll家族

    一.js中对象的一些特性 对象的动态特性 1.当对象有这个属性时,会对属性的值重写 2.当对象没有这个属性时,会为对象创建一个新属性,并赋值 获得对象的属性的方式 为元素设置DOM0级事件 二.JSO ...

随机推荐

  1. 批量删除MySQL生产环境数据库表或表字段注释脚本

    本文提供了一种批量删除MySQL生产环境中数据库表的注释或表字段注释的方法,通过脚本实现高效维护表结构的清晰性. 一.表注释修改 1.获取删除MySQL数据库表注释脚本select concat('A ...

  2. QT5笔记: 19. QFileSystemModel 联动 QListView QTableView QTreeView

    Model 指的是数据 View 指的是界面,View不用设置,只需要和Model进行绑定,绑定完成之后就是Model的格式了 例子:*本例子中QListView QTableView QTreeVi ...

  3. 离线环境安装nodejs及npm库i5ting_toc(超详细,手把手教学一通百通)

    一.离线环境先安装nodejs   1.在可联网的电脑上下载特定版本的 Node.js: 访问 Node.js 官方下载页面(https://nodejs.org/download/release/) ...

  4. Azkaban的job从创建到执行

    单一 job Step1: 创建 job 描述文件 xxx.job: job 的描述文件 type =  command command =  echo 'hello, this is my firs ...

  5. 他来了,为大模型量身定制的响应式编程范式(1) —— 从接入 DeepSeek 开始吧

    哒哒哒,他来了! 今天我们要介绍一种新型的 Java 响应式大模型编程范式 -- FEL.你可能听说过 langchain,那么你暂且可以把 FEL 看作是 Java 版本的 langchain. 话 ...

  6. php实现地址跳转的方式

    在PHP中,实现地址跳转主要有以下几种方式: 1. 使用 header() 函数 header() 函数用于发送原始的 HTTP 头信息,常用于实现页面跳转. <?php header(&quo ...

  7. 什么是CPU?

    当你用手机刷短视频.用电脑玩游戏,或是使用智能手表查看健康数据时,这些设备的核心"大脑"--CPU(中央处理器)正在默默工作.它是现代计算设备的核心,但很多人对它一知半解.今天我们 ...

  8. 【Python】尝试切换py版本

    失败 问chatgpt,怎么把abaqus python 版本切换到py3.6,结果失败. chatgpt给出的建议: 修改abaqus_v6.env,明显扯淡!我就尝试在custom_v6.env中 ...

  9. 红日复现为什么失败之struct-046流量分析加msf特征总结

    struts2漏洞 一.指纹识别 s2的url路径组成(详见struts.xml配置文件):name工程名+namespace命名空间+atcion名称+extends拓展名 部署在根目录下,工程名可 ...

  10. Ubuntu Nvidia driver驱动安装及卸载

    前言 当前英伟达下载的驱动不再是 .run 的 shell文件,所以有了新的文档,如下 Ubuntu Nvidia driver驱动安装(新) 当然如果你有 shell 文件,也可以继续使用本文档安装 ...