TVM:Object家族
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家族的更多相关文章
- 深入C#数据类型
一:值类型与引用类型 值类型源于System.ValueType家族,值类型包括基本数据类型,结构类型和枚举类型. 值类型:在栈上储存的真实的值. 引用类型源于System.Object家族,在C#中 ...
- 深入.net平台和c#编程 学习笔记
深入.net平台和c#编程 一:理解.nteFramwork与c# 1.1,:Microsoft.net框架概述 1.2:.net框架结构 1.3.:c#语言概述 1.4:体验框架类库的强大功能 二: ...
- 深入C#.NET数据类型
深入C#数据类型 --不同类型的参数传递使用值传递,在方法中对参数的更改在调用后不能保留.使用ref方式传递,可以保留对参数值的更改. ---值方式参数传递和引用方式传递使用值方式(不用ref修饰)传 ...
- 第二章 深入C#数据类型
深入C#数据类型 巧记:值(无ref)+值=不变 值(无ref)+引=变 引(有ref)+值/引=变 1.值类型和引用类型 1.引用类型 源于system.object家族 ...
- 加深对C#数据类型的认识
值类型: 值类型源于System.Value家族,每个值类型的对象都有一个独立的内存区域用于保存自己的值,值类型 所在的内存区域称之为栈(Stack),只要在代码中修改它,就会在内存区域保存这个值. ...
- [Machine Learning & Algorithm]CAML机器学习系列1:深入浅出ML之Regression家族
声明:本博客整理自博友@zhouyong计算广告与机器学习-技术共享平台,尊重原创,欢迎感兴趣的博友查看原文. 符号定义 这里定义<深入浅出ML>系列中涉及到的公式符号,如无特殊说明,符号 ...
- java中Array/List/Map/Object与Json互相转换详解(转载)
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.易于人阅读和编写.同时也易于机器解析和生成.它基于JavaScript Programming Langu ...
- 走进Java Map家族 (1) - HashMap实现原理分析
在Java世界里,有一个古老而神秘的家族——Map.从底层架构到上层应用,他们活跃于世界的每一个角落.但是,每次出现时,他们都戴着一张冷硬的面具(接口),深深隐藏着自己的内心.所有人都认识他们,却并非 ...
- JVM家族史考【转】
说起Java虚拟机,许多Java程序员都会潜意识地把它与Sun(虽然太阳已然西落,但永远值得被记忆) HotSpot虚拟机等同看待,也许还有一些程序员会注意到BEA JRockit和IBM J9,但大 ...
- js中对象的一些特性,JSON,scroll家族
一.js中对象的一些特性 对象的动态特性 1.当对象有这个属性时,会对属性的值重写 2.当对象没有这个属性时,会为对象创建一个新属性,并赋值 获得对象的属性的方式 为元素设置DOM0级事件 二.JSO ...
随机推荐
- 批量删除MySQL生产环境数据库表或表字段注释脚本
本文提供了一种批量删除MySQL生产环境中数据库表的注释或表字段注释的方法,通过脚本实现高效维护表结构的清晰性. 一.表注释修改 1.获取删除MySQL数据库表注释脚本select concat('A ...
- QT5笔记: 19. QFileSystemModel 联动 QListView QTableView QTreeView
Model 指的是数据 View 指的是界面,View不用设置,只需要和Model进行绑定,绑定完成之后就是Model的格式了 例子:*本例子中QListView QTableView QTreeVi ...
- 离线环境安装nodejs及npm库i5ting_toc(超详细,手把手教学一通百通)
一.离线环境先安装nodejs 1.在可联网的电脑上下载特定版本的 Node.js: 访问 Node.js 官方下载页面(https://nodejs.org/download/release/) ...
- Azkaban的job从创建到执行
单一 job Step1: 创建 job 描述文件 xxx.job: job 的描述文件 type = command command = echo 'hello, this is my firs ...
- 他来了,为大模型量身定制的响应式编程范式(1) —— 从接入 DeepSeek 开始吧
哒哒哒,他来了! 今天我们要介绍一种新型的 Java 响应式大模型编程范式 -- FEL.你可能听说过 langchain,那么你暂且可以把 FEL 看作是 Java 版本的 langchain. 话 ...
- php实现地址跳转的方式
在PHP中,实现地址跳转主要有以下几种方式: 1. 使用 header() 函数 header() 函数用于发送原始的 HTTP 头信息,常用于实现页面跳转. <?php header(&quo ...
- 什么是CPU?
当你用手机刷短视频.用电脑玩游戏,或是使用智能手表查看健康数据时,这些设备的核心"大脑"--CPU(中央处理器)正在默默工作.它是现代计算设备的核心,但很多人对它一知半解.今天我们 ...
- 【Python】尝试切换py版本
失败 问chatgpt,怎么把abaqus python 版本切换到py3.6,结果失败. chatgpt给出的建议: 修改abaqus_v6.env,明显扯淡!我就尝试在custom_v6.env中 ...
- 红日复现为什么失败之struct-046流量分析加msf特征总结
struts2漏洞 一.指纹识别 s2的url路径组成(详见struts.xml配置文件):name工程名+namespace命名空间+atcion名称+extends拓展名 部署在根目录下,工程名可 ...
- Ubuntu Nvidia driver驱动安装及卸载
前言 当前英伟达下载的驱动不再是 .run 的 shell文件,所以有了新的文档,如下 Ubuntu Nvidia driver驱动安装(新) 当然如果你有 shell 文件,也可以继续使用本文档安装 ...