冷热字段分离提升程序局部性

2023-12-17 19:15

本文主要是介绍冷热字段分离提升程序局部性,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

突然想起了上学期课堂上的一个提升程序局部性的案例,我觉得非常有意思,写篇博客记录一下。

1 场景

案例场景非常简单,就是遍历访问大结构体数组的某一字段。对应到下图,funcA要访问a[N]的fld3字段,funcB中要访问b[N]的fld5字段。

在这个场景中,程序要访问的结构体数组很大(单个结构体要占用600B内存),然而,要访问的字段却很小,大约1B-4B。总结来说,就是,大结构体数组,按行存储,按列访问。

这段程序的问题是,超过90%进入cache的数据不会被利用。在当前主流架构下,cache line的大小是64B,一次加载的粒度自然也是64B。那么,在这种场景下,缓存到cache的绝大部分数据是无效数据。一方面,这会对程序没有发挥出最好的性能;另一方面,无效的数据移动会带来很大的能量消耗,在嵌入式场景下,application对能耗还是很敏感的。

2 改进

其实,要解决这个问题,思路很简单,就是要把结构体数组中的热字段放在一块,冷字段放在一块。这样的话,cache命中率自然就提升上去了。

2.1 手工调整数据结构

这种方法简单粗暴,理论上没啥问题,就是有点费程序猿。具体来讲,有两种方法。

2.1.1 方法1

这种方法是在结构体内存调整字段顺序,将热字段靠拢放置。就比如,下图struct A中的fld3和fld5是热字段,把两者放在一块就好了。这样一次cache line加载就可以将两个字段同时放入cache。

  • 这种方法存在问题
    • 一个结构体中所有热字段可能不够64B,cache还是会加载很多的无效数据。
    • 结构体中可能会嵌有很多子结构体,不同子结构体的热字段无法并拢。
    • 调整后字段顺序后的代码可读性下降。
2.1.2 方法2

这种方法重构了结构体,将热字段单独成立一个结构体,冷字段成立成另外一个结构体。如下图,struct A被拆分为了struct A hotstruct A cold,这样的话,热字段fld3就可以放在一块了,cache line加载可以最大程度上避免冷数据放入cache。

  • 这种方法存在问题
    • 重构结构体,调整字段顺序,代码可读性大大下降。
    • 源代码改造涉及面广,人工修改工作量巨大,易错。

2.2 自动代码变形

另外一种思路是做自动化工具,也就是做一个编译器,这个编译器自动帮我们进行冷热字段分离,这比手工改的逼格高得多了。具体来讲,也有两种方法。

2.2.1 源到源编译器

这种方法其实就是把手工调整数据结构的方法2进行自动化实现:输入.h\.c源代码文件,输出优化后的.h\.c源代码文件。

  • 这种方法存在问题
    • 源代码中的程序写法千变万化,自动化工具要识别出所有的写法有点不大现实。
2.2.2 IR2IR编译器

这种方法的思路是,既然在源代码层不好做自动化工具,那就考虑改IR,毕竟IR要规整的多。如下图,自动化工具会先运行一遍程序,识别出热字段,然后,在IR层修改,输出优化后的二进制程序。

使用IR2IR编译器优化后的程序,运行时间由6.9ms提升至6.7ms,提速了3%。

这篇关于冷热字段分离提升程序局部性的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/505525

相关文章

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下

ShardingProxy读写分离之原理、配置与实践过程

《ShardingProxy读写分离之原理、配置与实践过程》ShardingProxy是ApacheShardingSphere的数据库中间件,通过三层架构实现读写分离,解决高并发场景下数据库性能瓶... 目录一、ShardingProxy技术定位与读写分离核心价值1.1 技术定位1.2 读写分离核心价值二

深度剖析SpringBoot日志性能提升的原因与解决

《深度剖析SpringBoot日志性能提升的原因与解决》日志记录本该是辅助工具,却为何成了性能瓶颈,SpringBoot如何用代码彻底破解日志导致的高延迟问题,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言第一章:日志性能陷阱的底层原理1.1 日志级别的“双刃剑”效应1.2 同步日志的“吞吐量杀手”

Java利用@SneakyThrows注解提升异常处理效率详解

《Java利用@SneakyThrows注解提升异常处理效率详解》这篇文章将深度剖析@SneakyThrows的原理,用法,适用场景以及隐藏的陷阱,看看它如何让Java异常处理效率飙升50%,感兴趣的... 目录前言一、检查型异常的“诅咒”:为什么Java开发者讨厌它1.1 检查型异常的痛点1.2 为什么说

Spring Security 前后端分离场景下的会话并发管理

《SpringSecurity前后端分离场景下的会话并发管理》本文介绍了在前后端分离架构下实现SpringSecurity会话并发管理的问题,传统Web开发中只需简单配置sessionManage... 目录背景分析传统 web 开发中的 sessionManagement 入口ConcurrentSess

基于Python编写自动化邮件发送程序(进阶版)

《基于Python编写自动化邮件发送程序(进阶版)》在数字化时代,自动化邮件发送功能已成为企业和个人提升工作效率的重要工具,本文将使用Python编写一个简单的自动化邮件发送程序,希望对大家有所帮助... 目录理解SMTP协议基础配置开发环境构建邮件发送函数核心逻辑实现完整发送流程添加附件支持功能实现htm

C#控制台程序同步调用WebApi实现方式

《C#控制台程序同步调用WebApi实现方式》控制台程序作为Job时,需同步调用WebApi以确保获取返回结果后执行后续操作,否则会引发TaskCanceledException异常,同步处理可避免异... 目录同步调用WebApi方法Cls001类里面的写法总结控制台程序一般当作Job使用,有时候需要控制

MySQL中读写分离方案对比分析与选型建议

《MySQL中读写分离方案对比分析与选型建议》MySQL读写分离是提升数据库可用性和性能的常见手段,本文将围绕现实生产环境中常见的几种读写分离模式进行系统对比,希望对大家有所帮助... 目录一、问题背景介绍二、多种解决方案对比2.1 原生mysql主从复制2.2 Proxy层中间件:ProxySQL2.3

在MySQL中实现冷热数据分离的方法及使用场景底层原理解析

《在MySQL中实现冷热数据分离的方法及使用场景底层原理解析》MySQL冷热数据分离通过分表/分区策略、数据归档和索引优化,将频繁访问的热数据与冷数据分开存储,提升查询效率并降低存储成本,适用于高并发... 目录实现冷热数据分离1. 分表策略2. 使用分区表3. 数据归档与迁移在mysql中实现冷热数据分

golang程序打包成脚本部署到Linux系统方式

《golang程序打包成脚本部署到Linux系统方式》Golang程序通过本地编译(设置GOOS为linux生成无后缀二进制文件),上传至Linux服务器后赋权执行,使用nohup命令实现后台运行,完... 目录本地编译golang程序上传Golang二进制文件到linux服务器总结本地编译Golang程序