拓冰建站拓冰建站
首页 / 资讯中心 / 正文

zstd largeNbDicts 基准测试工具详解:大规模字典场景下的解压性能与缓存优化

zstd largeNbDicts 基准测试工具详解大规模字典场景下的解压性能与缓存优化【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit导读本文深入解析 zstd 压缩库随源码一同发布的largeNbDicts基准测试工具位于 lib/zstd-1.5.7/contrib/largeNbDicts它是 zstd 官方用于研究海量字典解压场景性能的核心工具当字典数量极大且不断轮换时字典始终处于冷状态因 CPU 缓存未命中而产生额外延迟。读完本文你将掌握该工具的全部命令行参数、构建方式、底层基准测试机制CDict/DDict 预生成、地址乱序、Fastest/Median 聚合并能用它量化评估--dedicated-dict-search、--dict-content-type、--dict-attach-pref等字典优化手段的实际收益。该工具也随 zstd 以 lib/zstd-1.5.7 子库形式内置于本仓库其核心 API如ZSTD_createDDict、ZSTD_decompress_usingDDict在 src/flb_zstd.c 的 Fluent Bit zstd 压缩/解压封装中也有实际调用具有直接的工程参考价值。一、工具定位为什么需要 largeNbDictslargeNbDicts是一个专门面向使用极大量字典进行解压这一特定场景的基准测试工具benchmark test tool。其背景问题在 README.md 中有明确表述当字典在不断更换时它们永远是冷的always cold会因cache misses缓存未命中而承受更高的延迟。与传统一个字典长期复用的场景不同某些业务会维护一个规模巨大的字典池每条数据使用其中不同的字典解压。此时字典内容无法驻留在 CPU 缓存中每次解压都需要从主存甚至更低层存储加载字典缓存未命中成为主要性能瓶颈。该工具正是为此类场景而创建用于**调查investigate**该场景下的真实性能表现**实验experiment**各种缓解技术mitigation techniques例如 zstd 提供的前缀字典、CDict 表预取、dedicated dict search 等高级选项。这一目标在源码头部注释中得到印证largeNbDicts.c/* largeNbDicts * This is a benchmark test tool * dedicated to the specific case of dictionary decompression * using a very large nb of dictionaries * thus suffering latency from lots of cache misses. * Its created in a bid to investigate performance and find optimizations. */从仓库结构看该目录是一个独立可构建的 contrib 工具仅包含三个文件README.md使用文档、largeNbDicts.c约 1085 行的完整实现、Makefile构建脚本依赖 zstd 主库libzstd.a以及programs/下的通用基准与工具代码。二、构建方式largeNbDicts通过 Makefile 构建。其构建依赖关系清晰PROGDIR ../../programs复用 zstd CLI 程序目录下的util.o、timefn.o、benchfn.o、datagen.oLIBDIR ../../lib编译 zstd 静态库libzstd.axxhash.o来自lib/common/xxhash.c。largeNbDicts: util.o timefn.o benchfn.o datagen.o xxhash.o largeNbDicts.c $(LIBZSTD) $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $$(LIBZSTD)目标会自动执行$(MAKE) -C $(LIBDIR) libzstd.a因此进入目录后直接执行cd lib/zstd-1.5.7/contrib/largeNbDicts make默认CFLAGS ? -O3-O3优化级别并附带-Wall -Wextra等严格告警选项make clean可清理中间产物与可执行文件。构建成功后即可获得largeNbDicts可执行程序用法为largeNbDicts [Options] filename(s)三、命令行参数全解析README 给出的完整命令行选项如下其中每个参数都能在 main() 的参数解析循环 中找到一一对应的实现参数含义默认值-z基准测试压缩方向默认开启-d基准测试解压方向关-r递归加载子目录中的所有文件关-B#将输入按#大小切分为块不切分-#使用压缩级别#3-D #使用#文件作为字典自动创建-i#基准测试轮数6--nbBlocks#基准测试使用的块数每文件一块--nbDicts#创建#个字典用于测试每块一个字典-h显示帮助—除 README 列出的参数外源码中实际还支持以下等价长选项与额外开关来自 largeNbDicts.c 的参数解析逻辑--dictionaryfile与-D等价--blockSize#与-B等价--clevel#与-#等价-p#指标聚合方式0fastest最快、1median中位数默认0在usage()帮助文本中也有列出见 largeNbDicts.c--prefetch-cdict-tables#CDict 表预取开关取值对应ZSTD_ParamSwitch_e。需要注意-B#与-#中#支持K/M后缀如-B64K、-B1M由readU32FromChar()负责解析largeNbDicts.c。典型用法示例# 1) 默认压缩基准自动为每个输入文件创建 4 KB 字典压缩级别 36 轮 ./largeNbDicts sample1.txt sample2.txt # 2) 解压基准输入按 64 KB 切块每块一个字典 ./largeNbDicts -d -B64K sample1.txt # 3) 使用外部字典文件创建 1000 个字典测试大规模冷字典解压 ./largeNbDicts -d -D mydict.raw --nbDicts1000 sample1.txt # 4) 递归加载目录全部文件压缩级别 9输出每轮中位数 ./largeNbDicts -r -9 -p1 /path/to/dataset关键默认常量源码级实现中定义的默认常量largeNbDicts.c帮助理解工具的默认行为#define KB *(110) #define MB *(120) #define BLOCKSIZE_DEFAULT 0 /* no slicing into blocks */ #define DICTSIZE (4 KB) /* 自动训练字典的目标大小4 KB */ #define CLEVEL_DEFAULT 3 /* 默认压缩级别 3 */ #define DICT_LOAD_METHOD ZSTD_dlm_byCopy /* 字典内容以拷贝方式加载 */ #define BENCH_TIME_DEFAULT_S 6 /* 默认 6 轮 */ #define RUN_TIME_DEFAULT_MS 1000 /* 每轮 1000 ms */ #define BENCH_SIZE_MAX (1200 MB) /* 单次加载输入上限 1200 MB */其中DICT_LOAD_METHOD ZSTD_dlm_byCopy意味着所有字典无论是自动训练的还是外部加载的都会以内容拷贝方式装载进 zstd 上下文这是保证基准可重复性的重要设置。四、字典的生成与装载从 ZDICT 训练到 CDict/DDict 池4.1 字典来源largeNbDicts支持两种字典来源createDictionaryBuffer()largeNbDicts.c外部字典文件-D #/--dictionary#直接按二进制文件读入自动训练默认调用 zstd 的字典训练 APIZDICT_trainFromBuffer()以目标大小DICTSIZE4 KB从输入数据块中训练出字典。若未指定--nbDicts字典数量默认与块数一致每块一个字典见 largeNbDicts.cunsigned const nbDicts nbDictMax ? nbDictMax : nbBlocks;4.2 CDict 与 DDict 池的预生成为了模拟海量字典场景工具会基于同一份字典数据在内存中批量复制生成N 个压缩字典对象ZSTD_CDict与解压字典对象ZSTD_DDictcreateCDictCollection()循环调用ZSTD_createCDict_advanced2()largeNbDicts.c并接受dictContentType与cctxParams后者承载 dedicated dict search、attach pref 等高级参数createDDictCollection()循环调用ZSTD_createDDict()largeNbDicts.c。工具还会打印字典池的内存占用估算压缩侧用ZSTD_sizeof_CDict()解压侧用ZSTD_estimateDDictSize()largeNbDicts.c例如generating 1000 dictionaries, using 32.2 MB of memory这一设计直接复刻了真实业务中内存中维护一个大型字典池、逐个轮换使用的内存足迹。4.3 关键技巧shuffle地址乱序这是本工具模拟真实冷缓存场景的点睛之笔。shuffleCDictionaries()与shuffleDDictionaries()largeNbDicts.c会对字典指针数组做两轮随机置换源码注释明确说明了目的/* mess with addresses, so that linear scanning dictionaries ! linear address scanning */即让按顺序扫描字典下标与实际内存地址访问顺序解耦。这样基准循环中虽然逻辑上按序轮换字典但每次访问的字典对象都落在不同的内存地址上从而真实触发缓存未命中而非因顺序访问获得 CPU 预取带来的虚假提速。五、基准机制benchMem 与每轮计时5.1 被测试的两个核心函数基准的核心是benchMem()它把压缩/解压操作包装成统一的benchFn交给BMK_benchTimedFn()来自programs/benchfn.c定时执行largeNbDicts.c。压缩路径compress()largeNbDicts.c每次使用ZSTD_CCtx_refCDict()引用下一个 CDict再调用ZSTD_compress2()完成压缩随后dictNb递增、到末尾回绕ZSTD_CCtx_refCDict(ci-cctx, ci-dictionaries.cdicts[ci-dictNb]); ZSTD_compress2(ci-cctx, dst, srcSize, src, srcSize); ci-dictNb ci-dictNb 1; if (ci-dictNb ci-nbDicts) ci-dictNb 0;解压路径decompress()largeNbDicts.c则调用ZSTD_decompress_usingDDict()携带对应的 DDict 解压当前块size_t const result ZSTD_decompress_usingDDict(di-dctx, dst, dstCapacity, src, srcSize, di-dictionaries.ddicts[di-dictNb]);这里体现的ZSTD_decompress_usingDDict/ZSTD_createDDict组合正是 Fluent Bit 的 zstd 封装在解压侧所用的同一组 API 家族——src/flb_zstd.c 中的zstd_uncompress_unknown_size()同样通过ZSTD_createDCtx()创建上下文、以 64 KB 分块驱动ZSTD_decompressStream()流式解压并设有 100 MB 的解压上限防护。这从侧面说明largeNbDicts测得的字典装载开销会真实传导到 Fluent Bit 这类使用同一 zstd 库的数据管道中。5.2 计时与指标聚合每轮固定运行RUN_TIME_DEFAULT_MS1000 ms总预算为nbRounds * 1000 ms每轮依据nanoSecPerRun与sumOfReturn处理字节数计算Speed_MBps并实时打印压缩/解压速度单位 MB/s全部轮次结束后aggregateData()对速度数组排序按-p选项取Fastest最快单轮或Median中位数输出largeNbDicts.cCompression Speed : 450.2 MB/s Fastest Speed : 452.1 MB/s5.3 CSV 结果导出每次基准结束后工具会把结果追加写入exeName.csv即largeNbDicts.csv表头为largeNbDicts.cCompression/Decompression,Level,nbDicts,dictAttachPref,metricAggregatePref,Speed每条记录含方向、压缩级别、字典数量、dictAttachPref、聚合方式与最终速度。这意味着你可以通过多组参数连续运行同一工具把不同优化配置如不同--dict-attach-pref、不同--nbDicts的实验结果累积到同一 CSV 中再用任意数据分析工具绘制对比曲线——这正是该工具作为性能调查与缓解技术实验平台的落地形态。六、高级选项zstd.h 中的字典优化机制README 标注这三个高级选项详见 zstd.h 文档其底层对应 lib/zstd-1.5.7/lib/zstd.h 中的实验性参数与枚举。main()中通过ZSTD_CCtxParams_setParameter()注入largeNbDicts.cZSTD_CCtxParams_setParameter(cctxParams, ZSTD_c_enableDedicatedDictSearch, dedicatedDictSearch); ZSTD_CCtxParams_setParameter(cctxParams, ZSTD_c_nbWorkers, 0); ZSTD_CCtxParams_setParameter(cctxParams, ZSTD_c_forceAttachDict, dictAttachPref); ZSTD_CCtxParams_setParameter(cctxParams, ZSTD_c_prefetchCDictTables, prefetchCDictTables);6.1--dedicated-dict-search对应ZSTD_c_enableDedicatedDictSearchZSTD_c_experimentalParam8见 zstd.h。开启后zstd 会为字典建立专门的索引结构以更大内存占用换取更快的字典匹配搜索。在字典大、块多的规模化场景下这是最常见的调优对象之一largeNbDicts正是用于量化其收益的工具。6.2--dict-content-type#对应ZSTD_dictContentType_e枚举zstd.h值名称含义0ZSTD_dct_auto自动判定以ZSTD_MAGIC_DICTIONARY开头按完整字典处理否则按原始内容rawContent处理1ZSTD_dct_rawContent强制按原始内容加载即使内容恰好以字典魔数开头2ZSTD_dct_fullDict拒绝加载不符合 zstd 字典规范的输入必须以字典魔数开头默认ZSTD_dct_auto。注意ZSTD_dct_rawContent模式本质对应 zstd 的另一项特性——前缀字典prefix dictionary即不要求字典是经过训练/格式化的完整字典任意原始前缀均可参与匹配。6.3--dict-attach-pref#对应ZSTD_dictAttachPref_e枚举zstd.h控制压缩时 CDict 与工作上下文working context的融合方式这是影响冷字典延迟的关键参数值名称行为0ZSTD_dictDefaultAttach使用 zstd 内置启发式自动选择1ZSTD_dictForceAttach绝不拷贝字典原地引用CDict 的表无启动拷贝开销但逐字节压缩较慢2ZSTD_dictForceCopy总是把 CDict 内容拷贝进工作上下文压缩更快但每次开始时有固定拷贝成本3ZSTD_dictForceLoad总是重新加载字典zstd.h 对三种 CDict 使用方式的代价权衡有精辟论述拷贝模式在**小输入 8 KB**时初始拷贝成本可能主导总开销原地引用模式则适合小输入、可复用工作上下文表的场景。在海量冷字典 小数据块的组合下dictAttachPref的选择会直接改变每次解压/压缩的固定开销这正是largeNbDicts的核心实验变量之一该值也会随结果写入 CSV 便于对照。6.4 附加隐藏开关--prefetch-cdict-tables#源码还支持ZSTD_c_prefetchCDictTablesZSTD_c_experimentalParam16zstd.h取值对应ZSTD_ParamSwitch_e0auto、1enable、2disable用于在压缩开始前预取 CDict 表到缓存属于缓解缓存未命中方向的直接实验手段。七、输出解读与实验建议一次完整的largeNbDicts运行其 stdout 输出大致为loading 4 files... created src buffer of size 128.0 MB split input into 2048 blocks compressing at level 3 without dictionary : Ratio1.85 (69258000 bytes) compressed using a 4096 bytes dictionary : Ratio2.91 (43986000 bytes) generating 2048 dictionaries, using 65.5 MB of memory Compression Speed : 412.3 MB/s Fastest Speed : 415.7 MB/s关键信息依次为加载规模与分块数 →无字典 vs 带字典的压缩比对比直接量化 4 KB 字典对压缩率的贡献→ 字典池内存占用 → 各轮速度与聚合速度。实验设计建议基于工具机制推断固定变量用-B#控制块大小对应真实业务中的单条记录大小用--nbDicts控制字典池规模让块数 × 字典数可独立调节对照基线同一数据集分别跑-d解压与-z压缩并记录无字典压缩比作为对照参数扫描对--dict-content-type0/1/2、--dict-attach-pref0/1/2/3、--dedicated-dict-search、--prefetch-cdict-tables0/1/2做组合实验结果追加进largeNbDicts.csv后汇总分析稳健性用-i提高轮数、-p1采用中位数降低单轮波动对结论的影响。八、与 Fluent Bit 项目的关联本仓库以子库方式内嵌了 zstd 1.5.7lib/zstd-1.5.7并在 src/flb_zstd.c 中封装了 Fluent Bit 侧的 zstd 压缩/解压能力flb_zstd_compress()以压缩级别 1 调用ZSTD_compress()src/flb_zstd.c用于数据压缩通道flb_zstd_uncompress()/zstd_uncompress_unknown_size()使用ZSTD_DCtxZSTD_decompressStream()做流式解压支持未知输出大小并设 100 MB 上限src/flb_zstd.c。虽然 Fluent Bit 当前封装未直接使用字典模式但若在 Fluent Bit 插件或自定义输出中引入字典池式解压例如为不同租户/数据源维护各自字典largeNbDicts所量化的冷字典缓存开销、ZSTD_createDDict/ZSTD_decompress_usingDDict的池化用法以及ZSTD_dictAttachPref_e的取舍都是直接的参考依据。该工具可作为引入字典功能前的性能预研的标准实验手段。总结largeNbDicts是 zstd 官方针对大规模轮换字典 缓存未命中场景设计的精悍基准工具它通过批量预生成 CDict/DDict 池、地址乱序打散、定时多轮测量与CSV 结果导出把抽象的冷字典延迟转化为可对比的 MB/s 数据并内置了对 dedicated dict search、dict content type、dict attach pref 等缓解技术的实验支持。无论是评估 zstd 字典特性、设计字典池式解压架构还是为 Fluent Bit 类数据管道引入字典压缩该工具都是一把开箱即用的性能标尺。延伸阅读仓库内路径使用文档lib/zstd-1.5.7/contrib/largeNbDicts/README.md完整实现lib/zstd-1.5.7/contrib/largeNbDicts/largeNbDicts.c构建脚本lib/zstd-1.5.7/contrib/largeNbDicts/Makefile字典 API 与枚举定义lib/zstd-1.5.7/lib/zstd.h字典训练 APIlib/zstd-1.5.7/lib/zdict.h基准计时框架lib/zstd-1.5.7/programs/benchfn.cFluent Bit 的 zstd 封装src/flb_zstd.c【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门