「龙蜥开发者说」第 25 期来了!开发者与开源社区相辅相成,相互成就,这些个人在龙蜥社区的使用心得、实践总结和技术成长经历都是宝贵的,我们希望在这里让更多人看见技术的力量。本期故事,我们邀请了龙蜥社区开发者贾庆林来分享「走入龙蜥赛道,推开开源大门」。
欢迎阅读上期故事《那些年,一起守护的网络安全背后》。开发者说系长期活动,对于积极投稿、多次分享的童鞋,我们还有神秘大礼鼓励!诚邀开发者们分享真实体验,以文会友、共同学习、一起进步。
本期故事主角: 贾庆林,2023 全国大学生操作系统大赛龙蜥社区项目参赛者,天津大学智算学部 2020 级本科生,队伍参加赛题“跨体系结构的 benchmark 性能对比分析”,主要负责内容为采用 Top-down 方法在不同 CPU 体系结构下进行性能分析和调优。
大家好,我是天津大学智能与计算学部 2020 级本科生贾庆林。很荣幸能够在 2023 年夏季参加全国大学生操作系统大赛,也很荣幸参加了龙蜥社区赛道,这次我的比赛题目是“跨体系结构的 benchmark 性能对比分析”。
在参加比赛之前,我对操作系统的了解主要来自于书本上的知识。我知道操作系统是计算机系统中至关重要的软件,它负责管理计算机的硬件资源,并为应用程序提供运行环境。作为应用程序与硬件之间的桥梁,操作系统协调和控制着硬件资源的分配和使用,为用户和应用程序提供简化而统一的接口。尽管我对操作系统有一定的热情,但由于个人精力的限制,我到了大学三年级也并没有深入研究操作系统的某些领域。
我“关注”龙蜥社区也很久了,当我在大二上半学期的操作系统课堂上第一次听到赵来平教授介绍龙蜥社区时,便打开了一扇新的认知之门。我对国产操作系统的未来充满好奇,也深知这是一条漫长而值得探索的道路。抱着对国产操作系统的兴趣,很快我就关注了龙蜥社区,翻阅了龙蜥社区内的很多新闻、博客,后续也参加了一些龙蜥社区的学习课程。为了体验一下国产操作系统,我在平常使用虚拟机时会依靠 Anolis OS 的镜像开展课程实验,这种实践也让我对国产操作系统有了更直观的感受。这一阶段虽然对龙蜥社区有了一定了解,但是我一直没有参加过社区的 SIG ,也没有参加过开源社区的工作。
直到 2023 全国大学生操作系统大赛,我才有了首次深度参与开源社区的机会,并对龙蜥社区运作的部分过程得以一窥。非常感激龙蜥社区给予我这个机会,这期间汲取了很多技术知识,让我受益匪浅,尤其是在比赛过程中我受到了天津大学赵来平教授和龙蜥社区常怀鑫老师的指导,知识由此而来,进步也在悄然发生。这次经历不但让我更加明确了自己未来的研究方向——深入学习操作系统,还让我愈发增长学习的信心。
事实上,我的学校一直鼓励学生加入开源社区,希望学生群体积累开源经验,立足开源,展望未来。然而,由于缺乏前辈的指导和个人能力的限制,迈出第一步总是很难。我和身边的同学很少会遇到这样的机会,即使是遇到,也会因为考虑到自身累积不够产生犹豫而错过,但看到这个比赛会提供导师的帮助,保证学生能够完成赛题,我和同学们立即就有了信心。在比赛中接触开源,无疑是我们了解开源效率最高的途径。通过参加这次比赛,开源的概念在我脑中从一团模糊变得逐渐清晰。我还注意到龙蜥社区是很多比赛的合作伙伴,每个龙蜥赛题都会为学生提供专业的指导,很让像我们一样零基础的同学有前进的动力和方向。此外,龙蜥的 SIG 组有丰富的学习资源,也涵盖很多技术方向,包括云原生、AI、eBPF 等当下热门领域。我们随时可以根据个人兴趣加入感兴趣的 SIG 组,开启学习的大门。
这场比赛给队伍的任务是设计一个操作系统性能分析软件,从一个较小的角度切入现代操作系统中。现代 CPU 采用流水线(pipelining)以及硬件线程、乱序执行和指令级并行等技术来尽可能有效地利用资源。尽管如此,一些类型的软件模式和算法仍然会导致效率低下。例如,链接数据结构通常在软件中使用,但这却会导致间接寻址,并且使得硬件预取器(hardware prefetchers)失效 (来自 Intel 的介绍) 。所以 Intel 使用了一种自顶向下的微架构分析方法来对应用程序中的性能瓶颈进行分析,了解这种自顶向下的微架构分析方法和将这种分析方法应用到其他的体系结构下是这次比赛的主要工作。
(图 1:Top-down 方法和四个一级指标)
我们的开发过程是一个逐步深入学习的旅程,几乎是从零开始。我们开始着手学习 CPU 体系结构,迈出了性能优化的初步尝试。在这个过程中,深入了解了 perf 工具,并积极探索了 perf 数据的分析方法。我们不仅努力将 Top-down 方法成功地应用于其他类型的 CPU,还坚持了相当一段时间的学习和实践。最后。我们将所学的知识融入到实际项目中,并最终提交了我们队伍的成果。
在从零开始学习现代 CPU 体系的过程中,我们实际上只涉及了 CPU 流水线的一部分内容。但鉴于我之前的经验有限,学习的难度颇大。现代 CPU 的前端和后端区别,以及前后端问题的根本原因,都需要我们深入学习和理解。尽管我们借助网络上的各种资料努力学习,但感到相当吃力。在一次与常老师进行的讨论会议中,我向老师提出我的问题并获得了解答,进步飞快,在短短一周内,我们团队打下了坚实的基础,继续完成了比赛的剩余任务,这段时间虽然短,但却是是我们成长道路中的浓墨重彩的一步。
实际上,对于 Intel 类型的 CPU,获取 Top-down 性能指标相对来说相当容易,这是因为 Intel 已经拥有一套成熟的性能调优工具——Vtune。这个工具能够对运行在 Intel CPU 上的操作系统下的应用性能进行深入分析。其中,Vtune 的一个强大功能是分析应用程序运行过程中的性能计数器事件,以获得各种性能指标,帮助开发工程师准确定位应用程序性能瓶颈。因此,我们队伍在研究了适用于 Intel 的 CPU 之后,成功获得了一些 Intel CPU 家族的 Top-down 性能指标计算方法,例如 Icelake 和 Skylake 家族。我们通过调整 perf 工具的采样方式以及对函数进行深入分析,成功获得了相对准确的总时间下的 Top-down 性能指标。这个过程基于强大的工具和坚韧的研究,让我们能够更好地理解和优化 Intel CPU 的性能。
(图 2:perf 工具采样模式工作流程)
然而,虽然我们可以在 Intel 的 x86 架构下轻松实现性能分析,但是 AMD 公司设计的 x86 架构 CPU 暂时无法提供类似的分析机会,更不用说将分析扩展到 ARM 架构下的 CPU 了。在队伍试图将 Top-down 方法扩展到 AMD 公司下 Milan 家族的一块 CPU 时,如果是我以及我的同学一起去分析使用 perf 工具得到的 PMU 指标,并且将这些指标扩展到分析 Milan 家族的 CPU 性能指标中,一定会存在很大的理论错误。与 Intel 类型的 CPU 类似,Milan 家族的 CPU 也提供了一系列可监测的 PMU 事件,其中包括正常结束的指令、因错误而重新执行的指令、执行周期总数等等。从这些指标中筛选出来有用的指标,并将其应用到 Top-down 分析中是这一阶段的任务,这一任务是困难的,但是过程是充实的。有一天深夜,常老师邀请我参加一个会议,与我分享有关这个领域的技巧和方法,每每想起,仍觉记忆犹新。45 分钟的线上讨论,坚定了我们队伍的信心。会议结束后,已经是凌晨两点左右,常老师为我们提供了更详细的技术方案,为我们未来的项目开发描绘了更为平稳的道路。
在项目的进展中,"self"和"total"的问题曾让我感到困惑已久。每当我们执行一个函数时,都牵涉到函数调用栈的问题,而实际上,栈中的函数很可能是影响性能指标的重要阻碍。当我们使用火焰图进行性能分析时,我们能够看到函数的总运行时间以及其在调用栈中所占比例。然而,调用栈中的总运行时间实际上并不等同于函数自身的执行时间。要确定一个函数是否成为性能优化的障碍,必须首先确保该函数自身的执行时间对整体运行时间产生了影响。因此,"self"的分析相较于"total"更加准确且明显。尽管现在看来这一点似乎显而易见,但事实上,这个问题曾长时间困扰着我,如果没有专业人士的指导,我想,我们是走不到现在的。
(图3:获奖证书)
在比赛中,思维的转变至关重要。性能分析涉及到的方法,当使用数学方法进行讲解时,通常更容易理解。然而,当我最初遇到那些杂乱的性能指标时,感到困惑重重。那时候的每一步走得都很艰难,一个接着一个,一个比一个难以跨越。但当我真正越过这些障碍,回首望去,每一个难题载着的那一段记忆却闪得像闯关后得到的星星,仿佛是对我进步的嘉奖。在这里,再次感谢常老师和龙蜥社区为我带来的帮助,这次比赛带给我的收获远不止一次荣誉,技能上的成长、思维方式上的变革都让我焕然一新。未来,我将继续怀抱着希望参与开源,期待有机会再次遇见龙蜥~