#国产芯片

今天给你们讲一个低性能芯片极限技术优化的故事 学了这篇推文,即使你不是做低性能芯片的场景也非常有用,操作系统老师傅倾情分享 当时我们面临的问题是这款国产芯片性能非常低,大概只有2000年奔腾处理器的水平,而且没有GPU和OpenGL的支持,内存带宽也非常低,面临的优化挑战非常大。 而现代软件库的开发效率很高,但是库本身的开销也非常大,面临X86这种CPU、GPU、内存带宽、显存带宽都很大的硬件,这些软件库的开销会被硬件的性能忽略掉,感受不出来。 而当年的国产芯片的性能,可以这样说,真实世界的硬件模拟器,任何代码没有极限优化的地方,它就奇慢无比,让你看到幻灯片的动画 我那时心里并不担心,因为我在2005年的时候,用J2ME做游戏,那个手机芯片的性能更弱,内存只有800KB,那个手机都能流畅的跑游戏,国产芯片肯定没问题。 当然,做极限优化肯定不能像原来做游戏那样从底层造图形库,虽然性能可以做到极致,但是长期来可维护性比较差,因为后来的人不懂原创的图形库细节。 遇到极限挑战的时候不要慌张,沉住气,想办法,一定可以解决,下面是我们的武功秘籍,板凳端好了: 1. 首先国产芯片不支持OpenGL,所以最开始的QML全部得用Qt Widget重写了,在有OpenGL显卡的情况下,带OpenGL的图形库要快很多,但是没有OpenGL的芯片运行OpenGL的代码就会非常吃力,因为Linux有Mesa硬件抽象库,当GPU缺乏OpenGL支持的时候,Mesa会自动用CPU去模拟OpenGL调用,这个会极大的增加CPU的负担,也会让系统整体变的很慢 2. 应用程序编写的时候,要仔细分析函数的依赖,在X86芯片上,可以随意写,不用过多考虑函数依赖,因为太快了,但是在国产芯片就要仔细分析函数的调用依赖,把界面显示的代码挪到最前面,先让用户看到界面,然后再是其他的。那时候先要做UX流程分析,代码除了按照底层逻辑顺序走,还要考虑UX流程,这样加载比较慢的代码,可以根据UX流程,一次逐步加载,比如一个控制中心模块,完全加载需要5秒,通过界面流程控制,点击某些地方的时候再执行代码,而不是模块执行就全部执行,这样每个界面可以控制在300~500ms之间展示 3. 函数循环要注意,尽量不要写那种一直等待的函数,用锁或者其他通知机制来替代,这样可以减少很多无谓的性能消耗 4. 其实很多代码慢不在代码本身,而在于加载某些动态库很慢,这种动态库的加载常规优化方法不行,太Hacking,我们就利用了现代CPU都具备的特性,内存缓存。我们会分析整个系统所需的动态库,也会分析用户从登录到进入各个界面的空闲时间。我们做了一个深度的优化,就是利用一切用户发愣的时间,比如输入登录密码的时候,桌面等的时候,不操作的时候......只要用户光标不动一段时间,我们就见缝插针的把动态库内容读取一次到内存。这样的好处是,原来应用程序加载的时候,先要加载动态库3秒,然后绘制界面50ms,总共3秒多的时间,因为动态库已经被预热到内存中去了,再次加载动态库的时候,就不用从磁盘读取到内存,直接去缓存里面调用,这样时间就从3050ms降低到50ms 5. 用户空间到内核空间,很多图形库的代码都在用户态运行,在X86芯片没问题,但是在低性能芯片上,这些用户态的逻辑功能就会变成非常多的syscall,syscall的调用非常多以后,代码就会内核中反复切换,这个切换的代价是非常大的。只要是CPU级别的优化,一定要防止代码在CPU和GPU之间反复搬运、磁盘和内存之间反复搬运、代码在内核态和用户态之间来回切换。所以,我们先上strace等工具,剖析系统调用频繁的代码,把这些代码直接写成内核模块,把原来上百次syscall的逻辑现在换成一次内核层的API,当系统调用从300次降低到一次以后,整个软件的性能就会层质的飞跃 6. 最后就是重写桌面环境后端,原来是Gnome的一部分代码,全部用golang重写后,删掉很多开源社区兼容各种人的代码,精简逻辑,很多都有70%以上的性能提升 好了,喜欢我创业故事的朋友欢迎点赞转发 今天这篇文章这么硬核,老板们不买台懒猫微服支持一下?你的支持是我持续分享硬核技术文章的动力,感谢老板,祝老板们发大财!
你们还是喜欢听故事 我今天给你们讲另外一个Linux系统工程师的故事 还是2015年,我们以前的团队为了适配一款国产芯片,具体芯片的名字我就不讲了 那款芯片就只有三个东西glibc、kernel和gcc,再也没有其他任何东西了,我们要把这款芯片从零撸起来,难度非常高。 很多人说,这不就是LFS嘛,根本没那么简单,一个操作系统ISO预装3000个包,一个仓库要10000个包,这些包如果在X86,确实就是LFS的事情。 但是我们要解决的是,从零构建整个操作系统文件系统,特别是一些底层的软件包,比如数学库、向量库、编程语言相关的库,每个包都有一堆芯片指令集分支,代码里到处都是 ifdef 的宏,用来包括特定CPU平台的平台代码。 我们要移植的工作不光是编译一下,而是要把这个库的X86汇编翻译成国产芯片的汇编语言,这里需要对计算机架构、X86指令集、国产芯片指令集、数学还有对特定编程语言都要了解才能干。 把指令集、国产芯片寄存器和数学算法补齐以后,才能编译,这种级别的编译最大的问题是软件包的循环依赖,因为确实太严重了,比如三个包A、B、C,他的依赖关系不是 A -> B -> C, 他的依赖关系是 A -> B, B -> C, C -> A, A -> C, B -> A。 常规的方法根本无法编译,我们只能把某些包源码分拆了,比如把A分成两部分,伪造了两个A1 A2 的包,先把B依赖A的部分弄好, B1 B2 编译出来,再回头来编译A的缺失部分。 这种底层构建的方法就叫作,多次编译法,多次编译才能解决芯片指令集底层缺失太多包又要从零构建的问题。 30人干了半年,终于干到了X11这一层,可以说所有底层命令行的环境都干好了,这时候已经到合同最后期限了。商务同学说加把劲,我说,这个不是加把劲的问题,你换个团队50人干两年都没法从零启动一个芯片,我们30人干半年到X11已经非常牛逼了,干不了,真干不了,干不动了,赔钱吧,干不了 最后没办法,甲方来武汉,和我们喝一顿酒,问,全部干完要多久? 我说还要给我们半年时间,那半年怎么干的,30人专门移植图形环境的东西,Gtk、Qt、浏览器,浏览器还要移植JavaScriptCore和JIT,浏览器交叉编译要1天1夜,原生芯片编译最少5天一次,错一个参数就要重来,怎么知道参数对没对呢?上一次5天的编译结果会告诉你。 另外一个团队几十人把桌面环境从QML全部用Qt重写,因为国产芯片不支持OpenGL。 最难受的是,干到8个月的时候,GCC有bug,那个bug是生成的汇编代码有问题,会造成我们另外一个桌面环境内存随机崩溃。 哎,就这样一个团队兵分三路:底层包/图形包移植、JIT优化、桌面环境重写,又干了一遍。 一年的时间,从零支持了一款芯片,同时把桌面环境重写了一遍,那一年所有人,包括我,都累垮了。 所以,我从deepin linux出来以后,我记得阿里云一个技术人给我打电话要招募我,炫耀说他们在这款国产芯片用GCC 5.3编译了整个系统,当时我都没理他。 现在这个故事就是当年的答案:整个大树都是我们60人干了一年的工作,底层的数学库、汇编指令集、编译器、桌面环境等等1万个软件包都是我们构建,你们就像余业玩Linux那样,按照LFS的方法重新编译一遍,你也好意思说操作系统是你们做的?这就是国内这些互联网大公司的水平,太low,也是大多数玩Linux的人的现状,水平太差还喜欢攻击人。 好了,喜欢听我创业故事的朋友,欢迎点赞转发 相信我们技术实力的朋友,欢迎私信买懒猫微服,包你满意!