查看原文
其他

何处觅得活水来?

格蠹老雷 格友 2023-06-10





如果说人生是用90%的平淡时间等待那10%的精彩,那么上周末在桃花源度过的50多个小时便是我今年一直期待着的那份精彩。从桃花源返回有几天了,但是我的心似乎还留在那里,思绪还常常转移到那里。


有时是回想起几天前看到的真实景象,有时是设想离开那里后它变得如何,连日的春雨过后,山谷中的溪水是不是又大了一些?那里的桃花是否还在盛开?




(一)


这次的桃花源之行,是从今年春节就开始准备的(有一种爱叫桃花源)。上周日我带着一大箱《软件简史》预览本从上海出发,开始了这次朝圣之旅。在南京停留几日后,周四(2023年3月16日)19:25,我乘坐的D3197从南京南站准时发车,桃花源之行真正开始。


我去过庐山多次,但以前大多是从上海出发(也有一次从珠海出发),唯有这次从南京出发,走的路线明显不同,路上经过芜湖、潜山、安庆这些我向往很久但还未曾去过的一些小城。安庆曾经是安徽的省会,说小城可能不合适。车过安庆时,我透着车窗瞭望了一下夜幕下的城市,的确有一些“大”城市的特征。


周四22:20,D3197准时到达庐山站。2013年第一次游庐山就是到的庐山站,说起来刚好10年了。那次同行的主要是Intel的同事。下了车后,我才意识到,虽然名字没有变,现在的庐山站和10年前的庐山站已经完全不同。


更准确的说,新的庐山站还没有完全建好,东西两个出口只投入使用一个,而且使用的是与我希望相反的西出口。


考虑到桃花源的山路比较窄,晚上上山不方便,我事先便在山下订了个酒店。根据地图订在了庐山站附近。但没有想到的是,可以选的酒店都是在高铁站的东出口附近。酒店标的距离也是按东出口算的。而事实上,东出口还没有建好。


所以当我走出高铁大厅,打开高德,确认了一下位置后,本来可以步行到酒店的想法成为泡影。有黑车司机上来搭话,被我拒绝。在高德里下单后,有司机很快接单,2分钟后上车。车子开了大约10分钟,从高铁的西出口绕道了东出口附近的酒店。这个小波折证明了那句经典的话:“纸上得来终觉浅,绝知此事要躬行。”换到这个时代,这句话便是:“网上得来终觉浅,绝知此事要躬行。”



到了酒店后,我听到窗外的雨声,雨比之前大了。


周五一早六点多,我便自然醒了,看窗外,仍有些阴天,但是雨已经停了,地面被雨水洗的干干净净。


早上七点多,我出宾馆买水果,准备带上山,课间休息时给大家吃。此时,与我相同目的地的格友们也开始忙碌,特别是选在在九江站乘坐接站车的。九江站的计划接站时间是8:00。


上午8:21,九江站的格友集齐,接站中巴出发。


上午9:11左右,小巴到达庐山站附近接这里的格友们,但是却没想到发生了两个维也纳酒店的“乌龙”事件。在一个维也纳酒店门口始终少一人的情况下,才发现少的人在另一个维也纳酒店。


上午9:40,终于接到了最后一位格友,中巴开始沿着庐山西面的环山公路向桃花源景区前进。


上午10:30,中巴到了桃花源景区大门。与我2017年夏季来时相比,景区大门有了比较大的变化,建设的更好了。



因为桃花源景区内部道路狭窄,不允许7座以上车辆进入,所以我们不得不下车,改换景区里的车辆。


开车的司机很健谈,一边开车,一边给大家介绍庐山和桃花源的历史。



车子缘溪而上,路两边春花盛开,一派早春的景色。


大约20多分钟后,车子已经开到了桃花源深处,经过我上次曾写代码的大樟树时,我和大家说,我曾在这里写代码,大家都笑了。

大约11:00,车子停在了我们即将上课的谦竹居下面。


沿着一段斜坡,走进一个小院,里面便是我们本次研习班的大本营,前两批到的小伙伴已经等在里面了。









至此,本次研习班的所有现场参会者(19人)全部到齐,出发地如下:


东莞:1;珠海:2;成都:4;长沙:2;武汉:3;上海:2;南京:1;北京:1;福建:1;合肥:1;杭州:1。




(二)


这次研习班的主题是LINUX内核,第一讲的题目是《LINUX内核大局观》。这个内容我每年都讲很多次。但是每一次都讲的不一样。改变的目标是追求新颖,把代码讲活,不要陈词滥调。


这一次,在桃花源深处,我又换了一种讲法,几句简单的开场后,便让大家直接打开课前准备好的6.1.16源代码。



6.1.16是版本6的第一个长期支持版本(LTS),刚好在研习班的前几天发布。可以想见,这个版本将是未来10年中的一个重要版本,所以在庐山讲这个版本,至少可以让大家对这个版本有个深刻的印象。


每次讲arch目录时,我都会结合着CPU厂商的历史和发展潮流来讲,在IT巨头们“群雄逐鹿”的故事中,让大家感受到CPU领域的激烈竞争,认识到在Linux的arch目录中有一套代码意味着什么。



提高学习效果的另一个关键是互动。在这个内容时,有人问了一个非常好的问题,为什么arm架构的32位和64位分两个目录,而x86是一个目录。


这个看似简单的问题,其实非常耐人寻味。里面也有着安腾64和x64的故事。简单说,AMD当年推出x64就是打着“兼容”这张牌而把安腾64搬下马的,既然无缝兼容,也就不需要分为两个目录,一个x86目录就够了。


而arm64是著名的armv8引入的,arm借此机会丢掉了以前的很多包袱,硬件方面大修大改,软件方面也另起炉灶,开了一个新的目录,迎接新的时代。


如果从这个意义上看,arm的两个目录代表着锐意进取,而x86的单一目录代表着固步自封……




(三)


把大局观部分讲的差不多就到了午饭时间。午饭过后略作休息后,13:30下午的课开始。我没有按讲义的顺序讲,跳过很多内容,直接跳到挥码枪一讲,带着大家上手内核调试。


与以前使用虚拟机做内核调试不同,这次研习班为每一位参加者准备了一套GDK8和一个挥码枪(基于CoreSight技术的硬件调试器)。



我做了简单示范后,很多格友都在两分钟内成功将内核中断到调试器。成功的满脸喜悦,没成功的则非常投入地操作着。


NT内核之父大卫·卡特勒在分享他的人生经验时曾说他是个喜欢“hands on”的人。我非常赞同这个观点,要把软件学好,经常动手是必须的,一定要多写代码,多调试。


几分钟后,几乎每个人的内核调试器都工作起来了(除了带Mac电脑的1位)。有了这个强大的帮手后,我讲后面内容时也轻松很多,常常带着大家一起把内核中断下来,设断点在某个位置,g,然后命中在感兴趣的位置,一起体会分析。




(四)


完成挥码枪一讲后,我折回头来讲大局观的后半部分,即用户空间的GNU世界,自然讲了斯托曼的故事。


看大家的热情已起,兴致很高,我便顺势鼓励大家提出自己最想听的内容,鼓励大家提问。打印出的讲义有1000多页,逐页讲不仅讲不完,而且太枯燥乏味。所以我改为按大家的提问来讲。


这个方法果然效果不错,我顺着大家的提问,讲了追踪机制,包括eBPF的基本原理,以及长期看可能产生的稳定性问题。



周五晚饭后,继续根据大家的兴趣做了ftrace的一些动手试验。


八点半下课后,一些格友回自己的住处了,但还留下几位不舍得离开。来自北京的老朋友问了一个很有意义的问题,Linux驱动(LKM)的init函数是谁调用的,父函数叫啥名?


听了这个问题后,我回想起多年前曾在庐山秀峰带着大家跟踪Windows的rootkit,在DriverEntry的父函数设置断点。


为了演示解决问题的思路,我在llaolao驱动的init函数里,加了个10秒钟的延迟:


mdelay(10000)


然后加载llaolao驱动,再用挥码枪中断下来,切换CPU,找到对应的线程后,k,答案便出来了。



亲眼目睹了我的调试器“解题法”后,小伙伴们开心不已。




(五)


我们住的地方三面环山,打开地图,都是绿色。在这样的天然氧吧里,睡眠质量非常高。早上五点多,我便自然醒了,耳边不时传来公鸡打鸣的声音。


这个熟悉的声音唤起了我的许多童年记忆。多么熟悉的声音啊,很多年没有听到了。打开阳台的门,走到一楼的屋顶,看四周云雾缭绕。对面的房屋大多建在山坡之上,房屋之间,一些树木正盛开着花朵,粉红的是桃花,白色的可能是梨花。





(六)


第二天早上,早饭过后,大约8:10开始上课。上午的重点内容是内存管理。我以我习惯的比喻开场:“内存问题是软件世界的住房问题。


NUMA,页机制,页表结构,页错误,TLB,高速缓存,大矩阵乘法的例子,故事、理论、演示、问答,一上午的时间很快就过去了。


午饭后,大家顺着谦竹居后面的山路步行到了具有天下第一泉之称谷廉泉瀑布下。虽然瀑布的水不大,但是峡谷中溪流清澈,峡谷两侧山势险峻,景色也很不错。



回到教室后,下一个课题是“信号和应用程序崩溃”。我带着大家一起用GDB跟踪一个故意空指针的演示程序,让大家感受CPU的飞行本领,大家也都兴致盎然。


结合着一位格友的提问,我顺势演示了在GDB中修改PC寄存器的“飞针”技巧。




(七)


晚饭时,雨下的更大了,晚饭后,大家又聚到教室。这一晚的预定内容便是“自由谈”,我简单开场后,大家自由发言。我起初还担心冷场,但事实上,每个人都是演说家,讲的动情动理。

有的人分享自己的经历,有的分享对软件的感悟,有的分享职业上的问题…


整个宇宙都是在计算

我7岁时便开始编程…

我十年前便读了张老师的书

看到《在调试器下xxx》这个题目后,我悟了……

只有在调试器下看到的代码才是活代码

可惜,这个晚上的讨论会没有录像,只能靠大家的记忆来保存了。




(八)


第三天上午的重点内容是“任务管理”,继续保持前两天的互动气氛,我一开场就让大家来给“任务管理”做比喻,“如果用人类社会做类别,任务管理是在管什么?”


很快便有同学说:“是管人。”


我觉得很贴切,是的管人,而人是最难管的。


接下来是分辨进程和线程两个概念。我把进程比喻为人类社会的“户”,自古便有户部。


再推进一步,讲到Linux内核任务管理的数据结构体,那自然就讲到了著名的“task_struct”——我常说的“内核第一霸”。


既然有挥码枪,那当然要用它来看一下Linux内核的第一大结构体。把内核中断,!process显示当前进程的task_struct地址,然后dt lk!task_struct <地址>,内核第一霸的一个个字段便逐一登场了。


如果想观察某个字段,那么可以加-y来过滤,比如-y comm便只显示进程的主程序名。


周日下午的主题是优化,继续以大矩阵乘法做例子,使用perf来做试验。特别介绍IPC(instruction per cycle)这个硬指标。


先让大家感受到了不好的跨行访问代码后,又让大家感受了循环交替的神奇功效——一下子速度快了很多倍,IPC也翻了几番。


在返程的高铁上,我回味着三天里的一幕幕景象。三天里我既是老师,也是学生。课堂上的提问,饭桌上的闲聊,还有周六晚上的自由谈,都让我学到很多。特别是那句“只有在调试器下看到的代码才是活代码”让我“脑洞大开”。多年来,我无数次使用“在调试器下xxx”这个题目,算是创造了一个“调试器体”。但是我在论及调试器的好处时,主要是说它的生动性、穿透力、控制力等等。未曾从代码的角度讨论过,而这句“只有在调试器下看到的代码才是活代码”可谓“发我所未发”,让我收获良多。


顺着这句话想开来,如果“只有在调试器下看到的代码才是活代码”,那么很多人很多时候看的都是“死代码”。这不正是他们学不好软件的关键问题么?


想到这个深度后,我自然想起了朱熹的名句(《观书有感·其一》)


观书有感·其一

[宋] 朱熹

半亩方塘一鉴开,

天光云影共徘徊。

问渠哪得清如许?

为有源头活水来。


巨大的代码量让软件太复杂了,要想把它看清楚,那么必须寻得源头活水,用活的工具,活的方法,看活的代码。刚好在谷廉泉的山谷中,不知何人雕刻了两个巨大的字:源来。



研习班结束时,我送给每人两件礼物,一件是2023年的新茶,就产自桃花源;另一件是《软件简史》预览本。我希望大家可以在研习班后,一边品着的茶香,一边读《软件简史》,认识软件的源头。


问渠哪得清如许?为有源头活水来。

要想让我们的思维清澈透明,那么需要源头活水。源头活水在哪里?它可能藏于深山,可能隐于都市,需要我们去寻觅。


对于错过庐山站的朋友,杭州站(【杭州站】LINUX平台高级调试和优化)的时间在4月22-24日。报名后即可观看庐山站的录像。


盛格塾是格蠹科技旗下的知识分享平台,是以“格物致知”为教育理念的现代私塾。


本着为先圣继绝学的思想,盛格塾努力将传统文化中的精华与现代科技密切结合,以传统文化和人文情怀阐释现代科技,用现代科技传播传统文化。


访问方式

手机端:微信小程序搜索“盛格塾”

电脑端:下载Nano Code社区版客户端

https://nanocode.cn/#/download

格友公众号

盛格塾小程序

往期精彩推荐

在调试器下理解RK3588和LINUX5.10

道法自然:我受益最多的老师

好教育和坏教育

内核夜话:32位应用,奈若何?

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存