陈教授来的时候,是个大晴天。
九月初的北京,热浪从地面蒸起来,把远处的楼宇烤得发虚。
一辆草绿色的吉普车停在红星所门口,陈教授从副驾驶下来,手里拎着一个军绿色的帆布包,包带在肩上勒出一道深痕。
他穿着短袖白衬衫,领口的扣子解了一颗,露出晒得黝黑的脖颈。
头发花白,但梳得一丝不苟,眼镜片后面的眼睛不大,却很亮,像两颗打磨过的黑石子。
宋颜教授和吕辰已经等在门口。
“陈教授,辛苦了。”宋颜迎上去,接过帆布包,沉甸甸的,里面全是资料。
陈教授摆摆手,在台阶上站定,抬头看了看主楼上“红星工业研究所”几个大字,然后低头看了看表:“不辛苦,时间紧。机房准备好了?”
“准备好了。”
“数据库的框架写完了,我今天把微程序装上,跑通之后,你们就可以开始填数据了。”
他顿了顿:“另外,汪教授那边的分布式调度微程序也编译好了,存在二维卡里,我一并带过来了。”
他又补了一句:“三百多张卡,装了两个箱子,在后备箱里。”
宋颜眼睛一亮:“微程序也好了?”
“好了。”陈教授一边往车子后面走,一边说,“汪教授带着人熬了六个多月,调度器的核心代码写了1万多条指令。已经在计算机所的模拟环境里跑通了基本功能,任务分发、负载均衡、结果回收。但还没在你们这个16节点的真机上跑过。今天一并试。”
三个人走到后备箱,两个木箱子和那个帆布包,一人抱一个,往右附楼走。
机房的铁门开着,冷气从门缝里溢出来,在走廊里凝成一层薄薄的白雾。
陈教授站在门口,没有立刻进去,而是先透过门上的玻璃窗往里看了几秒。
“好。”他轻轻说了一个字,推门进去。
冷气扑面而来,干燥,带着一种电子设备特有的气味,焊锡、松香、还有一点臭氧。
陈教授把帆布包放在管理员桌上,宋颜教授和吕辰把两个木箱子放在地上,撬开盖子。
里面是码得整整齐齐的二维卡,每一张都用牛皮纸信封封装,信封上贴着标签,写着程序模块名称、版本号、日期和负责人签名,信封里还有具体的指令文本。
字迹工工整整,一丝不苟。
陈教授从帆布包里抽出一沓厚厚的资料,翻开第一页,是一张手绘的系统架构图。
中央是一个大方块,写着“调度器”,周围围着16个小方块,代表16台KJ-0A,线缆连接成星型和环型的混合拓扑。
“我先讲一下整体设计。”他把图纸摊在管理员桌上,宋颜、吕辰、诸葛彪、钱兰、曾祺、陈工都围过来。
“分布式辅助设计系统,分成三层。”
他竖起一根手指:“最底层,是硬件和通信。16台KJ-0A,星型网连存储柜,环状网做协同。这一层你们已经跑通了,我不多说。”
竖起第二根手指:“中间层,是调度器。跑在16台机器中的一台,我们叫它‘主控节点’。它负责任务的接收、分解、分发、监控、回收。工程师坐在任何一台终端上提交一个仿真任务,调度器会根据当前各节点的负载,决定把任务分给哪台机器去算。算完了,结果返回给终端,同时存入存储柜。”
他顿了顿,竖起第三根手指:“最上层,是应用软件。标准单元库的数据库管理程序、版图编辑器的交互程序、仿真器的前端界面。这些是你们红星所要自己写的,理论组只提供底层调用的接口。”
陈教授讲得很细,从任务队列的数据结构,到节点负载的衡量标准,到故障节点的检测与隔离。
吕辰一边听一边在笔记本上记,偶尔提问。
钱兰问的是数据一致性,如果主控节点把同一个任务分给了两台机器怎么办?
陈教授说调度器里有一个“任务去重表”,每个任务有唯一编号,分出去之前先查表,分出去之后立刻写入。
诸葛彪问的是环网通信的可靠性,如果令牌在传输过程中被干扰了怎么办?
陈教授说微程序里实现了超时重传机制,发送方发出令牌后启动定时器,如果在规定时间内没收到应答,就重发。连续三次失败,就判定节点故障,启动隔离流程。
其他人也纷纷提问。
一个小时后,方案讲完了。
陈教授合上资料,看着所有人:“有问题吗?现在提。等装上去了再改,麻烦。”
沉默了几秒。
吕辰说:“有一个问题。如果主控节点自己死机了怎么办?”
陈教授看了他一眼,嘴角微微翘了一下:“这个问题,汪教授想到了。所以调度器不是单点,而是双机热备。两台机器同时运行调度器,一台主用,一台备用。主用每十秒钟向备用发送心跳。如果备用连续三次没收到心跳,就自动接管。工程师终端上的任务提交接口有两个地址,主用连不上就切备用。”
他从资料里抽出一张图,是双机热备的状态转移图,画得清清楚楚。
“还有问题吗?”
没人再问。
“好。那就开始装。”
先装存储柜上的数据库系统。
陈教授从帆布包里拿出一个防静电盒,打开,里面是一块陶瓷封装的只读存储器芯片,银灰色的外壳,表面印着白色的丝印字。
“数据库的内核,固化在这块芯片里。插到中央存储柜的背板上,上电之后会自动加载到指定内存区域。”
吕辰接过芯片,用拇指摩挲了一下封装表面,然后走到中央存储柜后面,找到背板上预留的插槽,小心地插进去。“咔嗒”一声,到位。
陈教授走到管理员桌前,按下监控终端的电源开关。
显示器亮起来,绿色的字符开始跳动。
他敲了几行命令,屏幕上的输出一行一行地滚过:
LOADING DATABASE KERNEL……
KERNEL LOADED AT 0x1000
INITIALIZING BUFFER POOL……
BUFFER POOL SIZE:64KB
INITIALIZING IRUCTURE……
B+ TREE ROOT CREATED
DATABASE READY.
陈教授又敲了一个命令,屏幕上出现了一个简单的提示符:DB>
他回头看了一眼吕辰:“数据库内核跑起来了。接下来装管理工具。”
他从帆布包里拿出一个牛皮纸信封,里面装着厚厚一沓二维卡,每张卡上打满了孔。
他把卡片一张一张地塞进读卡机,每塞一张,读卡机就“咔嗒”一声把卡片吞进去,显示器上逐行显示加载信息:
LOADING DB_MAOOL……DONE
LOADING DB_QUERY_TOOL……DONE
LOADING DB_IMPORT_TOOL……DONE
……
加载了将近二十张卡,最后屏幕上出现了一行提示:ALL TOOLS LOADED. TYPE HELP FOR ANDS.
陈教授敲了“HELP”,屏幕上列出十几个命令:
REATE_TABLE、I、SELECT、UPDATE、DELETE、CREATE_INDEX、DROP_INDEX……
“数据库的表结构我已经建好了。”他切换到另一个界面,屏幕上出现了一个表格状的输出:
TABLE:CELLS
NS:
ID (INT, PRIMARY KEY)
NAME (CHAR(32))
FUN (CHAR(16))
TECH (CHAR(4)) // 5UM OR 2UM
LAYOUT_DATA (BLOB)
SIM_MODEL (BLOB)
TEST_VECTORS (BLOB)
VERSION (INT)
MODIFIED_BY (CHAR(32))
MODIFIED_AT (TIMESTAMP)
“每个标准单元存成一条记录。ID是唯一编号,NAME是单元名称,FUN是逻辑功能,TECH是工艺版本——5微米还是2微米。LAYOUT_DATA存版图的坐标数据,SIM_MODEL存仿真模型的参数,TEST_VECTORS存测试向量。VERSION、MODIFIED_BY、MODIFIED_AT是版本管理用的。”
陈教授转过身,看着吕辰:“你们的人要做的,就是对着手册,把每个单元的这几项数据,用IMPORT工具一条一条地塞进数据库。IMPORT工具支持从文本文件批量导入,你们可以先把数据写成文本文件,再一次性导入,比一条一条敲命令快。”
吕辰点头,在本子上记下来。
数据库装完了,接下来是分布式调度微程序。
陈教授走到一号机前面,打开机柜门,从帆布包里拿出另一个防静电盒,里面是一块只读存储器芯片。
“调度器的微程序,固化在这块芯片里。插到一号机的接口板上。一号机就是主控节点。”
吕辰接过芯片,插到一号机接口板上的预留插槽。
陈教授走到操作台前,按下电源开关,插入引导卡,读卡机“咔嗒”一声。
显示器上的字符开始跳动:
LOADING SCHEDULER MICROCODE……
MICROCODE LOADED AT 0x2000
INITIALIZING TASK QUEUE……
INITIALIZING ABLE……
DETEG NODES……
屏幕上出现了一个表格,16行,每一行对应一台KJ-0A。第一列是节点编号,第二列是状态,第三列是IP地址(他们用简单的数字编号代替IP)。
NODE 0 STATUS:ONLINE ADDR:0
NODE 1 STATUS:ONLINE ADDR:1
……
NODE 15 STATUS:ONLINE ADDR:15
16台机器的状态全是“ONLINE”。
陈教授点了点头,又敲了一个命令:
START HEARTBEAT
屏幕上开始每隔十秒跳出一行:
HEARTBEAT:ALL NODES RESPONDED
HEARTBEAT:ALL NODES RESPONDED
HEARTBEAT:ALL NODES RESPONDED
调度器的主控节点开始向其他十五台机器发送心跳包,每一台都正常响应。
“调度器跑起来了。”陈教授的声音很平静,但吕辰注意到他扶眼镜框的手指微微顿了一下。
“接下来测试任务分发。”陈教授从帆布包里拿出一张二维卡,插进一号机的读卡机,“这是一个简单的测试任务——计算斐波那契数列的前二十项。任务描述写在卡片上,调度器会把它分发给负载最低的节点。”
他按下运行键。
显示器上出现了新的输出:
TASK SUBMITTED:ID=0001, TYPE=FIBONACCI
SCHEDULER:DISPATG TO NODE 7 (LOAD=0.12)
然后,几秒钟后,七号机的显示器上亮起了计算结果,一行一行绿色的数字,从F1=1到F20=6765。
同时,一号机的显示器上出现了:
TASK 0001 PLETED. RESULT STORED.
陈教授又提交了第二个、第三个、第四个任务,调度器分别把它们分给了节点3、节点11、节点14。所有任务都顺利完成。
他转过身,看着吕辰:“基本功能正常。接下来,你们可以把标准单元库的数据导进去,然后在真机上跑一个真实的设计任务,看看调度器在大负载下的表现。”
吕辰点了点头,心里盘算着下一步的工作。
诸葛彪站在旁边,双臂交叉抱在胸前,盯着屏幕上的输出看了好一会儿,忽然说:“陈教授,这个调度器,能同时跑多少个任务?”
陈教授想了想:“理论上是无限的。任务队列用优先级堆实现,内存里最多缓存一百个,超过一百个的会暂存在存储柜的磁盘上。每个任务提交的时候,调度器会估算它的计算量,当然,估算不准,你们用一段时间之后,可以根据实际运行时间反馈调整估算模型。”
钱兰插了一句:“任务的优先级怎么定?”
陈教授翻开资料,找到一页,指着一个表格:“默认是FIFO,先来先服务。但你们可以给任务打标签,紧急任务可以设置高优先级。调度器在处理队列的时候,优先级高的先出队。”
他又补充道:“这个机制还在实验阶段。你们先用着,有什么问题随时反馈。”
吕辰从笔记本上撕下一张纸,写了一行字:“调度器双机热备待测试、优先级机制待验证。”
然后把纸贴在管理员桌旁边的墙上。
陈教授看着那张纸条,笑了一下:“你倒是会抓重点。”
吕辰也笑了:“陈教授教得好。”
陈教授摆摆手,站起来走到中央存储柜前面,把手掌贴在柜子的铁皮外壳上,感受了一下温度和震动。
柜子里的散热风扇在均匀地运转,发出低沉的嗡嗡声。
他站了几秒钟,然后转过身,看着吕辰。
“小吕,数据库和调度器,我交给你们了。这是种子。你们要做的,是让它长出来。”
他顿了顿,声音低了一些:“理论组能做的,就是把地基打牢、把框架搭好。但真正让这个系统活起来的,是里面的数据,400多个标准单元,两个工艺版本,每一个单元的版图、仿真模型、测试向量。这些东西,计算机所的陈工写不出,理论组写不出,只有你们红星所的人能填进去。”
“种子种下去,能不能发芽,看地,看水,看人。”
吕辰沉默了几秒,然后点了点头:“陈教授,我们不会让种子烂在地里的。”
陈教授没再说什么,拍了拍他的肩膀。
他走到机房门口,回过头,又看了一眼那16台墨绿色的机柜和三个铁柜子。
日光灯的光照在他的眼镜片上,反射出一片白茫茫的光,看不清他的眼神。
然后他推门出去了。
走廊里的热浪涌进来,和机房的冷气撞在一起,在地面上凝出一层薄薄的水雾。
吕辰站在机房门口,看着陈教授的背影消失在走廊尽头。
帆布包空了,扁扁地搭在他肩上。
脚步声越来越远,最后被风扇的嗡嗡声吞没。
吕辰回到管理员桌前,看着屏幕上那个绿色的提示符:“DB>”
他敲了一个命令:DB> SHOW TABLES
屏幕上列出了三张表:CELLS、PROJECTS、TASKS。
CELLS是标准单元库,空的。
PROJECTS是项目信息,空的。
TASKS是任务记录,空的。
三张空表,像三块刚翻好的地,等着播种。
吕辰把那个命令记在笔记本上,合上本子,转过身。
诸葛彪和钱兰站在他身后,一个叼着烟,一个抱着笔记本,都看着他。
“明天开始,标准单元库录入。”吕辰说,“12台机器录入,四台机器校验,三班倒。先把最常用的50个门电路,与非门、或非门、反相器、传输门,两个工艺版本,一共一百条记录,优先填进去。两天之内,我要看到数据库里有数据。”
他又补了一句:“有了这一百个门,我们就可以开始设计存储芯片了。”
诸葛彪把烟从嘴里拿下来,弹了弹烟灰:“录入格式呢?手册里那些坐标数据,怎么转换成文本文件?”
“今晚定。钱师姐,你带人写一个录入模板。每个单元的版图坐标按‘图层:起点X,起点Y,终点X,终点Y’的格式写。仿真模型按‘参数名=参数值’的格式写。测试向量按‘输入A,输入B,输出Y’的格式写。统一标准,方便导入。”
钱兰点头,在本子上记下来。
“曾师兄,你负责调度器的日常监控。明天开始,让系统连续跑72小时,记录心跳、任务分发、任务回收的数据。任何异常都要记下来,反馈给陈工。”
曾祺应了一声。
“周建国,你带第一小队的人,把机房的值班表排出来。三班倒,每班八小时,交接班要有记录。谁录入、谁校验、谁复核,每一条数据都要有责任人。”
吕辰把任务一条一条地分配下去,笔记本上的字迹潦草但力道很重。
分配完的时候,已经快中午了。
阳光从机房的窗户照进来,透过双层玻璃,在墨绿色的机柜上投下一片金黄。
16台KJ-0A的显示器都亮着,屏幕上显示着“DB>”的提示符,安静地等待着。
像16个沉默的农夫,等着播种。
吕辰站在机房中央,看着这一切。
锄头已经造好,能翻出什么样的地,接下来就看怎么挖了。