ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

d的打包位.

2021-11-15 22:35:11  阅读:163  来源: 互联网

标签:return enum uint mixin data id 打包


D打包位

作者:@deadalnix.
内存很慢,约300个周期.
L1:3~4周期,L2:8-14周期.L3数十个周期.
缓存线:64字节.

序号打包位好处
1减少内存浪费
2提高缓存利用率
3最低的CPU成本
4不能替代更好算法

减少实例化对象可节省大量内存!
对齐:确保加载/存储跨缓存行/跨页边界.
未对齐,则cpu性能差,丢失原子性,硬件访问2次.SIGBUS等硬件错误,根据abi定义.
对齐规则:<size_tT.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中的反射生成表.
常规类层次构需要编译时知道所有方法,可动态加类型.无类层次构需要编译时知道所有类型.可态加方法,访问者可创建访问方法表.并用标签来调度,一种方法关闭扩展,用另一方式打开.

标签:return,enum,uint,mixin,data,id,打包
来源: https://blog.csdn.net/fqbqrr/article/details/121345179

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有