d的打包位.
2021/11/15 23:12:55
本文主要是介绍d的打包位.,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
D打包位
作者:@deadalnix
.
内存很慢,约300
个周期.
L1
:3~4
周期,L2
:8-14
周期.L3
数十个周期.
缓存线:64字节.
序号 | 打包位好处 |
---|---|
1 | 减少内存浪费 |
2 | 提高缓存利用率 |
3 | 最低的CPU 成本 |
4 | 不能替代更好算法 |
减少实例化
对象可节省大量内存!
对齐
:确保加载/存储
不跨缓存行/跨页边界
.
未对齐
,则cpu
性能差,丢失原子性
,硬件访问2次.SIGBUS
等硬件错误,根据abi
定义.
对齐规则:<size_t
为T.sizeof
.>size_t
的为size_t.sizeof
,由编译器分解访问内存.构
,则是每个字段的最大对齐
.添加填充
来符合对齐.
构 S{ 极 a; 正 b; 极 c; }
4+4+4
.字节.
构 S{ 正 b; 极 a; 极 c; }
则4+4
字节.
填充提示
.从高对齐
字段开始,知道在哪填充,使用静态断言
强制假设alignof/sizeof
,
类像构,但有隐式字段
:虚表/监控
,至少要指针大小对齐
.
信息密度
多少实际信息 极
:1位信息,8位存储.对象
:45位信息,64位存储
.转储内存并压缩它.
用消耗内存,来换CPU
.通常很划算,用整来存储,在1个整中存储多个元素,按位操作
元素std.bitmanip
可帮助.
struct A { mixin(bitfields!( 正, "x", 30, 极, "y", 1, 极, "z", 1)); }
现在x
最大10亿
,总为1个整
.字段不再是原子
的了.
enum ReadMask = (1 << S) - 1; enum WriteMask = ReadMask << N; @property uint entry() { return (data >> N) & ReadMask; } @property void entry(uint val) in { assert(val & ReadMask == val); } body { data = (data & ~WriteMask) | ((val << N) & WriteMask); }
上面是位字段整
,下面是位字段极
.
enum Mask = 1 << N; @property bool entry() { return (data & Mask) != 0; } @property entry(bool val) { if (val) { data = data | Mask; } else { data = data & ~Mask; } }
注意,数据^掩码
会翻转位,有时比置位
更快.
布局位字段
2个特别点:最右边:仅掩码
,最左边:仅移位
.
大元素需要大掩码
,放在最左边.
极值总是用掩码
,最左边用符号<0
检查,除非很热,不要放在特殊地方.
想要:1标志,2位枚,29位整
怎么搞,如何是最佳布局
enum E { E0, E1, E2, E3 } struct S { import std.bitmanip; mixin(bitfield!( E, "e", 2, bool, "flag", 1, uint, "integral", 29, )); }
生成:
e = cast(E) (data & 0x03); flag = (data & 0x04) != 0; integral = data >> 3;
未用位
有时,不需要整个位字段
,用UINT,"",29
创建无名
字段,外部用uint,"_derived",29
调用构/子类
.加上名字
.最好设为私有/受保护
,或在私构元素中用,要手动实现其余字段
要求特征:具显式存储
的位字段.
class Symbol : Node { Name name; Name mangle; import std.bitmanip; mixin(bitfields!( Step, "step", 2, Linkage, "linkage", 3, Visibility, "visibility", 3, InTemplate, "inTemplate", 1, bool, "hasThis", 1, bool, "hasContext", 1, bool, "isPoisoned", 1, bool, "isAbstract", 1, bool, "isProperty", 1, uint, "derived", 18, )); }
接着:
class Field : Symbol { // ... this(..., uint index, ... ) { // ... this.derived = index; // 总真 this.hasThis = true; } @property index() const { // 仅可用262,143字段 return derived; } }
标记针
,@trusted
,已知最低有效位为0,对齐决定多少,Log2(T.alignof)
,对象上至少有3位
(32位系统上2位).
标记针/标记类引用
,编译器时检查对齐约束
,未对齐指针不安全
.
enum Color { Black, Red } struct Link(T) { import std.bitmanip; mixin(taggedPointer!( T*, "child", Color, "color", 1, )); } struct Node(T) { Link!T left; Link!T right; }
实际指针在对象,标记针对象内指向,垃集
知道内部指针.
标记针,@system
,在地址空间低32位
分配,截断指针为32位,限于4Gb
.Jemalloc
可为你这样做.HHVM用于在X86上生成代码
,最高16位为零
.劫持他们!,混淆GC!,不要段错误
.
使用上下文,对冷但常重复使用数据,如,一般不关心实际值的编译器中的标识符
,上下文存储标识符,提供32位与128位
的唯一标识.可用整比较,可为自己的哈希,使GC开心:更少指针,更多不扫描
!
struct Name { private: uint id; this(uint id) { this.id = id; } public: string toString(const Context c) const { return c.names[id] } immutable(char)* toStringz(const Context c) const { auto s = toString(); assert(s.ptr[s.length] == '\0', "期望0结尾串"); return s.ptr; } } //e class Context { private: string[] names; uint[string] lookups; public: auto getName(const(char)[] str) { if (auto id = str in lookups) { return Name(*id); } // 复制时,确保0在尾. import std.string; auto s = str.toStringz()[0 .. str.length]; auto id = lookups[s] = cast(uint) names.length; names ~= s; return Name(id); } }
预填充上下文
,编译时固定些标识很有用,无需查找即可使用,生成标识符,对象.d
,链接/版本/域/属性
enum Prefill = [ // 链接 "C", "D", "C++", "Windows", "System", // 生成 "init", "length", "max", "min", "ptr", "sizeof", "alignof", // 域 "exit", "success", "failure", // 定义在对象 "object", "size_t", "ptrdiff_t", "string", "Object", "TypeInfo", "ClassInfo", "Throwable", "Exception", "Error", // 属性 "property", "safe", "trusted", "system", "nogc", // ... ]; //e auto getNames() { import d.lexer; auto identifiers = [""]; foreach(k, _; getOperatorsMap()) { identifiers ~= k; } foreach(k, _; getKeywordsMap()) { identifiers ~= k; } return identifiers ~ Reserved ~ Prefill; } enum Names = getNames();
接着:
auto getLookups() { uint[string] lookups; foreach(uint i, id; Names) { lookups[id] = i; } return lookups; } enum Lookups = getLookups(); // template BuiltinName( string name, ) { private enum id = Lookups .get(name, uint.max); static assert( id < uint.max, name ~ "非内置名.", ); enum BuiltinName = Name(id); }
更多上下文!编译器中跟踪位置,环境中注册文件,分配从N到N+sizeof(file)
的值域
,对应文件中每个字节位置!为mixin(D)/宏(C++)
加标志,环境中注册扩展
.
用例:发出调试信息
,错误信息.性能与错误无关,调试的访问模式大多可预测,
用元素缓存,线性搜索(8个元素),二分搜索
从位置查找文件/行
.环境存储文件边界
和行位置
.
位置31位+1位
标志:2Gb
源码与2Gb
的宏/mixin
.用于标记/表达式/符号/语句
的一对位置.词分按令牌长
泵位置.
多态
,标签引用
.
封装多种引用
类型,可提供转发到元素
方法:用反射,避免查找虚表/级联加载
.引用对象无通用
布局.
元素数受对齐限制,在X64上轻松达到8个.LLVM
的调用/(invoke)
template TagFields(uint i, U...) { import std.conv; static if (U.length == 0) { enum TagFields = "\n\t" ~ T.stringof ~ " = " ~ to!string(i) ~ ","; } else { enum S = U[0].stringof; static assert( (S[0] & 0x80) == 0, S ~ "不能以统一码开始", ); static assert( U[0].sizeof <= size_t.sizeof, "元素应比指针小", ); import std.ascii; enum Name = (S == "typeof(null)") "Undefined" : toUpper(S[0]) ~ S[1 .. $]; enum TagFields = "\n\t" ~ Name ~ " = " ~ to!string(i) ~ "," ~ TagFields!(i + 1, U[1 .. $]); } } // mixin("enum Tag {" ~ TagFields!(0, U) ~ "\n}"); import std.traits; alias Tags = EnumMembers!Tag; import std.typetuple; alias TagTuple = TypeTuple!(uint, "tag", EnumSize!Tag);
接着:
struct TaggedRef(U...) { private: import std.bitmanip; mixin(taggedPointer!( void*, "ptr", TagTuple)); public: auto get(Tag E)() in { assert(tag == E); } body { static union Helper { void* __ptr; U u; } return Helper(ptr).u[E]; } // template opDispatch(string s, T...) { auto opDispatch(A...)(A args) { final switch(tag) { foreach(T; Tags) { case T: auto r = get!T(); return mixin("r." ~ s)(args); } } } } }
值类型多态
,所有子类型
给定条件下都符合,用标签来区分,用很好的API
包装整个过程,在漂亮外表下隐藏暴行,这是D的力量.示例:表示D类型
template SizeOfBitField(T...) { static if (T.length < 2) { enum SizeOfBitField = 0; } else { enum SizeOfBitField = T[2] + SizeOfBitField!(T[3 .. $]); }//字段大小 } enum EnumSize(E) = computeEnumSize!E(); // size_t computeEnumSize(E)() { size_t size = 0; import std.traits; foreach (m; EnumMembers!E) { size_t ms = 0; while ((m >> ms) != 0) { ms++; } import std.algorithm; size = max(size, ms); } return size; }//计算 // struct TypeDescriptor(K, T...) { enum DataSize = ulong.sizeof * 8 - 3 - EnumSize!K - SizeOfBitField!T; import std.bitmanip; mixin(bitfields!( K, "kind", EnumSize!K, TypeQualifier, "qualifier", 3, ulong, "data", DataSize, T, )); static assert(TypeDescriptor.sizeof == ulong.sizeof); this(K k, TypeQualifier q, ulong d = 0) { kind = k; qualifier = q; data = d; } }
值类型多态
,类型是TypeDescriptor+间接字段
,数据取决于种类,如果不合适,用间接字段
.有多种类型:内置-结构-类-别名-函数...
,切换常见API
来做正确事情.128位.
间接用在:类型
要额外空间(函数)
或引用符号/聚集/别名
,否则null
.替换类层次
,减小内存消耗
,更快运行时(20%)
.
可嵌套
,有效创建层次,类型/表达式/符号
是可标识的.标签用来在上面三样
中消歧.节省标签,在sdc
中可减少70M
模板膨胀.
import d.semantic.identifier; Identifiable i = ...; i.apply!(delegate Expression(identified) { alias T = typeof(identified); static if (is(T : Expression)) { return identified; } else { return getError( identified, location, t.name.toString(pass.context) ~ "不可调用", ); } })();
值类型
,ABI
最多2个字段,直到指针大小
.切片!无浮/整
插件.常见反模式2指针+极值
.std.bigint.BigInt
是切片+极值,在内存而非寄存器中传递(差).>1
指针,最好用2
指针.用1/2
指针大小构.
无类多态
,创建基构
,所有子构将其用作第1字段
.包含描述类型标签
,标签
可是位字段的一部分.在所有子构中用插件
.用静态断言
来检查是否正确.别名该基
.
无类多态
,层次结构每叶有标签
值,非叶
有标签值区间
,根匹配所有值,必须在编译时知道层次,用大量插件模板,加样板,大量静态断言
.
struct Child { mixin Parent!Root; } struct Root { mixin Childs!(Child, SubStruct); } // struct SubStruct { mixin GrandChilds!( Root, SubChild, ); } struct SubChild { mixin Parent!SubStruct; }
无类多态
,子项共享父项部分布局,用别名本
安全上转,下转为叶子:检查标签值,便宜,简单模式匹配.
下转为子结构
:检查标签区间
,便宜,无类型标识
指针.
虚分发
,无虚表
,表中取函数指针:每个方法一张表,每个叶子类型一个项
,按索引用标签.HHVM
用于PHP
数组,创建数据结构,是向量/散列图/集合/元组/任何
.
普通:每类型1虚表,每方法虚表有1项,加载虚表,再加载函数地址.
无类虚分发
:每方法1虚表,每类型虚表有1项.在每函数表
中按索引加载并用它.
本地性更好
,在不同类型对象
上调用相同方法
,比相同类型
对象上调用不同方法
更常见.按类型排序
来解决.无需排序即可获得大部分收益.仍有助于预测分支
,可用D中的反射
生成表.
常规类层次
构需要编译时知道所有方法
,可动态加类型
.无类层次构需要编译时知道所有类型
.可态加方法
,访问者可创建访问方法
表.并用标签来调度,一种方法关闭扩展,用另一方式打开.
这篇关于d的打包位.的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南