计算机系统基础课程的实验设计与分析

2018-10-25 03:14袁春风陶先平
计算机教育 2018年10期
关键词:计算机系统实验设计理论课

汪 亮,袁春风,苏 丰,唐 杰,路 通,陶先平

(南京大学 计算机科学技术与软件工程实验教学中心,江苏 南京 210023)

0 引 言

随着后PC时代的到来,对于计算机行业相关人员的需求也从顶层软件开发人员转向需要更全面系统知识的系统性人才,而传统的培养体系在这方面仍存在不足[1]。在此大背景下,对于在高校中开展计算机系统教育的需求也显得愈发迫切,涌现出了一系列相关的教学研究工作[1-12]。其中,计算机系统基础作为整个课程体系中的入门课,在整个课程链中起到重要的引领性作用。作为一门面向实际系统的课程,要引导学生将理论和实际相结合深入理解计算机系统,一个有效的方法就是通过实验手段来实践所学到的知识。因此,实验在计算机系统基础教育中占有重要地位。

作为一门面向整个计算机系统的实验课程,如何在有限的教学时间、可控的学生精力投入范围内做到既重点突出又体现系统性和完整性,是实验设计和教学过程中面临的主要挑战。纵观现有计算机系统实验课程设计方案,比较典型的是卡耐基梅隆大学所设计的Lab实验方案[13]。该方案通过9个独立的小实验,重点突出了对学生数据操作、机器指令理解、体系结构等方面的锻炼。然而该实验方案在体现系统的完整性方面仍存在不足,对于引导学生全面系统地理解程序从生成、载入到执行各个阶段所涉及的具体内容无法做到无缝衔接。

1 相关工作

计算机系统实验的相关设计方案可大致分为面向硬件的实验设计和面向程序的实验设计两类。面向硬件的实验设计方案中较为典型的是采用FPGA作为实验平台,通过构建以类MIPS指令集CPU为核心的计算机系统,来引导学生通过实验掌握计算机系统的各个组成成分,实践相关的理论知识[14-15]。这一类面向硬件的实验设计方案有利于引导学生从底层细节入手深入把握计算机系统的各个部件设计与实现原理,在实践过程中取得了很好的教学效果。然而此类面向硬件的实验设计方案对学生前期知识的掌握要求较高。本文所关注的计算机系统基础课程是系统方向的入门课程,其授课时间为本科二年级第一学期,作为一门平台课向所有信息类的学生开设。因此,学生在计算机相关知识的掌握和动手能力方面尚需培养。同时,由于面向硬件的实验设计方案受其实现难度的限制,能够覆盖的主题数量和深度有限,在实验的针对性和系统性之间需要进行仔细权衡。

与我们的工作同属一类的典型实验设计方案是卡耐基梅隆大学所设计的Lab实验方案[13]。该方案的9个小实验中,包括数据实验、二进制炸弹、缓冲区溢出和cache实验都是面向程序执行的,针对性较强。该实验方案的优势在于通过一系列独立的小实验,有针对性地引导学生深入实践相关课题。然而其不足之处在于,对于完整的计算机系统缺乏系统性的实验,从而导致各主题之间的关联不紧密,无法做到程序从生成、装载、执行和输入输出在内完整过程的无缝衔接。

在以上相关工作的基础上,本文提出了一种面向程序的计算机系统基础实验设计方案,即PA实验。该实验方案以构建完整的计算机模拟器为主线,通过各个阶段的逐步展开,以连续、系统的方式,为学生深入学习计算机系统基础创造良好的配套实验过程。

2 PA实验的设计原则

(1)实验设计的系统性和简洁性。实验的各个阶段应当主题突出,同时紧密结合构成一个完整的系统;实验框架应尽可能简洁,屏蔽无关细节并采用简单、直接、易懂的设计和实现方案。

(2)与理论课程的同步配合。与理论课讲授内容和次序的同步配合也是设计课程实验时必须重点考虑的问题。

(3)对于项目开发的实践教育。计算机系统基础实验体现为一个小规模的软件项目。对于学生而言,在实验的过程中掌握项目管理、开发和测试相关的技术,也是在设计实验时需要体现的内容。

(4)与后续课程的衔接。计算机系统基础作为整个系统培养课程体系中的一环,其配套的实验也应该兼顾与后续课程及其实验的衔接。

3 PA实验设计

3.1 PA实验设计

3.1.1 实验总览

PA实验的整体目标是引导学生创建一个简化的x86模拟器并实现相应的上层软件,从而实现对计算机系统基础相关知识的系统性实践教育。图1展示了PA的整体架构。PA项目主要由NEMU(NJU Emulator)、Kernel、用户程序以及内嵌于NEMU中的Monitor四大组件构成。其中,实验的核心内容围绕NEMU展开,可大致分为针对CPU功能、存储管理、异常控制流、I/O外设的模拟四大部分。Kernel为一个精简的操作系统,主要提供包括程序装载、虚存管理、系统调用和中断处理相应的功能。在Kernel的支撑之上,PA能够运行各类测试用例以及样例游戏程序。

图1 PA整体架构图

PA作为一个x86指令集体系结构的软件模拟器,在运行时表现为一个用户程序。通过模拟实现x86系统的各条指令,实现运行x86程序的功能。PA由C语言编写,其目标平台为32位i386平台,目标操作系统位GNU/Linux系统。图2展示了PA实验运行时的系统栈。

本课程选用的教材为袁春风老师的《计算机系统基础》。PA实验与理论课的讲授次序紧密配合,分4个阶段:①数据的表示、存取和运算;②指令的译码和执行;③存储管理;④异常控制流和I/O。

图2 PA运行时系统栈

3.1.2 PA 1:数据的表示、存取和运算

以数据的表示、存取和运算为切入点,介绍计算机系统中整数和浮点数这两种重要类型数据的表示和运算规则。配合理论课第二章的内容,无符号整数采用原码表示,带符号整数采用补码表示,浮点数采用IEEE 754标准。在数据表示的基础上,通过实现ALU和FPU的运算功能,引导学生熟悉掌握数据在计算机中的表示和运算方式;通过设置EFLAGS标志位的练习,指导学生掌握整数运算中可能出现的各种情况。

IEEE 754标准内容较多,学生不容易理解和掌握。PA通过实现软件模拟浮点数,指导学生动手实现包括对阶、规格化、舍入等运算操作,帮助学生深入理解掌握浮点数的表示和运算规则。通过阅读和编写代码,生动地理解包括浮点数阶码溢出、边界值的处理、精度问题等单凭理论课讲授难以切实体会的内容。

在数据表示和运算的基础上,PA 1自然引出计算机存储数据的需求,进而介绍寄存器和主存这两大数据存储部件,引导学生理解其结构和对外提供的存取接口。

3.1.3 PA 2:指令的译码和执行

强调计算机执行程序的能力。配合理论课第三章的内容,介绍x86指令的译码和执行相关内容。在本阶段,我们只关心指令的顺序执行和跳转,不涉及异常控制流的执行。

该阶段首先从宏观角度介绍指令执行的一般过程,通过一个while循环语句,指导学生理解指令循环的实际含义。在译码阶段,通过函数指针数组模拟操作码译码功能;通过实现包括ModR/M、SIB、立即数、寄存器和内存地址寻址等具体的功能性代码,引导学生深入理解指令操作数的编码方式和各类操作数寻址方式;通过实现不同指令的实现函数,帮助学生深入理解并掌握指令功能及其必要的实现细节。

在PA的框架代码中通过提供大量的测试用例来帮助发现指令实现中可能存在的bug。从测试用例程序的装载方式来分,PA 2又可以分为两个小阶段。第一个小阶段中测试用例程序通过内存镜像直接拷贝的方式来加载;第二小阶段则引入Kernel,要求实现ELF文件的解析来装载测试用例程序的代码和数据段。其中第二小阶段配合理论课的授课进度,从测试用例从硬盘文件装载到模拟内存这一需求出发,自然从第三章过渡到第四章的内容。最后作为一个可选任务,通过实现程序调试器的功能,简要介绍表达式求值方法并实现对符号表的解析,对应理论课第四章的内容。

3.1.4 PA 3:存储管理

探讨程序执行过程中的访存效率、安全性和并行性,引出理论课第六章的内容并展开相应的实现。

首先从访存效率的角度出发,介绍cache的组织和替换策略。要求学生通过实现一个简单的模拟cache,深入理解cache的组织方式、结构和替换算法的实现方式;通过引入模拟时钟,来引导学生通过实际运行体会cache的增加对于执行效率的影响,体会访存局部性原理。第二,从存储保护的角度,来引出x86的保护模式和分段机制。通过实现CR0寄存器和lgdt等指令,深入理解机器从实模式到保护模式的切换过程;通过实现地址转换函数,理解段表的构造和从逻辑地址到线性地址的转换过程。最后,从支持程序并行执行的角度,引入虚拟地址空间的概念,通过在Kernel中实现对页表的初始化和管理,并在NEMU中增加从线性地址到物理地址的转换过程,引导学生理解机器和操作系统如何配合完成存储管理的功能。

3.1.5 PA 4:异常控制流和I/O

以时钟中断为切入点,要求学生实现包括int在内的相关指令以及操作系统的中断描述符表和处理函数,深入掌握从硬件到操作系统配合响应异常和中断的过程。

在基本的异常和中断响应功能的基础上,通过提供相应的设备模拟代码并要求学生实现包括端口映射的I/O和内存映射的I/O这两种I/O方式,帮助学生构建一台具备基本I/O功能的计算机,完成按键响应等基本功能,深入理解I/O的基本原理。

在基本测试用例以外,PA还提供了包括打字小游戏和仙剑奇侠传在内的两款小游戏作为最后的测试用例,使得学生在理解计算机运行程序基本原理的基础上获得较高的成就感,激发学习的兴趣。

第四阶段的内容对应理论课的第七和第八两章的内容。

3.1.6 与理论课的同步配合

综上所述,整个计算机系统基础PA实验的设计涵盖了计算机系统基础课程所涉及的绝大部分理论内容。通过构建一个完整的模拟计算机系统,在帮助学生掌握各项知识的同时,由简单到复杂,阶段性、系统性地完成一个功能相对完备的机器,兼顾了对独立知识点和整体系统性这两个方面的训练。整个实验过程紧扣理论课各个章节的授课次序,能够做到与理论课的同步配合,在可控的学习负荷的情况下,做到实验与理论的互相促进和增强效果。表1梳理了PA实验各阶段和理论课的同步对应情况。

表1 PA各实验阶段与计算机系统基础理论课的对应关系

3.2 项目管理、测试与调试训练

作为一个小规模的软件项目,PA实验采用git来进行项目版本管理。通过实际的操作,引导学生学习版本控制的重要性以及掌握git工具的基本使用方式,为未来的项目开发打下基础。

为了有效提高所编写代码的正确性,PA还引入了大量的测试方法并鼓励学生编写测试用例。在PA 1的过程中,展现了所实现程序和内联汇编执行结果的交叉验证技术,属于将实现代码与一个“黄金版本”进行比较的测试方式。在后续的实验过程中,则通过构建测试I/O形式的测试用例方式,来测试代码中可能包含的bug。通过展现两种不同的测试技术,并强调单元测试的重要性,来引导学生了解测试的方法;通过让学生在实现过程中因为测试不充分而导致的各种程序bug,来生动展现测试的重要性。

最后,通过简要介绍gdb和引入monitor调试器,来帮助学生理解使用调试工具的必要性,掌握程序调试的基本技巧。

在上述过程中,我们的设计原则是允许学生犯错,并深刻体会到因各种错误所导致的程序异常行为,通过付出一定的努力进行测试和调试,锻炼相应的能力和技巧。

3.3 与后续课程的衔接

作为计算机系统方向课程链中的一个环节,计算机系统基础课程是一门重要的入门性的课程,与后续包括操作系统、编译原理在内的课程具有很强的关联性。在PA实验的设计中也体现了这一点。

首先,作为一个功能完整的计算机系统,要实现对用户程序的执行设计到机器和操作系统的协作。从PA 2第二小阶段开始,实验引入Kernel并在后续的实验中不断增强Kernel的功能,引导学生初步理解和掌握操作系统的基本功能和实现方式,为后续操作系统的理论学习和实验打下基础。

第二,作为PA 2第三阶段的一个可选功能,实验在monitor组件中实现了表达式求值功能,包含了基本的词法、语法分析功能,为后续编译原理的学习做铺垫。

4 教学实践结果分析与讨论

我们首先分析历年来PA的完成情况来获取学生对PA实验的接受程度;以2016学年秋季学期的成绩数据为样本,通过对比PA实验成绩和期末考试成绩,来分析PA实验与课程成绩之间的关联关系,并结合当年期末展开的开放式问卷和访谈的反馈结果,来直接获取学生对于PA实验有效性的反馈意见。同时,在学习负荷方面,由于PA实验对学生的动手能力和知识掌握程度都提出了较高的要求,因此通过开放式问卷和访谈的方式,就学生的学习负荷展开了调研。调研工作的执行时间为2016学年秋季学期期末开始,为期约两周,共收到反馈74份,其中有效反馈67份。

4.1 历年完成情况统计

在2014年未设置专门的实验辅导课的情况下,PA完成情况并不理想,极少有同学能够完成整个PA实验,有部分同学甚至无法完成第一阶段的实验。自2015年开始设置专门的辅导课程后,完成情况得到大幅改观,在2015年和2016年,绝大多数的同学都完成到了PA的后期,有许多同学能够完成最终阶段,从而实现运行小游戏的目标。

可以看出,除理论课之外开设专门的实验辅导课效果明显。在有专门辅导的情况下,大多数同学通过付出一定的努力,能够在规定的时间内完成实验所要求的基本任务。能力较强的学生可以实现运行游戏等附加任务。

4.2 PA实验设计的有效性

图3展示了2016年PA成绩和期末考试成绩的分布情况,对两项成绩计算皮尔逊相关系数,其结果为0.76。该结果显示PA成绩和期末考试成绩有较强的正相关性,反映出PA成绩能够较大程度反应学生对理论知识掌握情况,同时也从侧面反映出PA实验设计的有效性。

图3 2016学年秋季学期得分统计

除量化的成绩以外,我们还通过开放式调查问卷和访谈的方式获得了学生的相关反馈。在收到的67份有效反馈中,有43人明确表示PA实验对计算机系统基础的学习有积极意义,9人表示没有意义,15人未表态。其中比较典型的反馈包括:

“PA对于理解计算机系统基础,真的帮助很大,比做习题、做lab的帮助都要大的多,不去动手实现,也许我永远都不会明白一个程序是怎么走完的,访问地址的流程又是怎样的。在调BUG、看汇编代码时,我才能明白程序的调用、栈帧的变化等。”

“写PA的过程极大地加深了我对课本上理论知识的理解和掌握,尤其是:FLOAT部分加深了我对课本第二章的理解, PA2阶段二、阶段五加深了我对课本第三章和第四章的理解,cache部分加深了我对cache的理解。”

总体而言,对于PA实验在计算机系统基础课程中的作用,绝大多数同学持肯定的态度。基于以上分析,我们认为PA实验的设计完成了其预期目标,是有效的。同时,通过访谈,我们也意识到PA对于学生而言是较有挑战的一个项目,具有较高的学习负荷。

4.3 学生的学习负荷

4.3.1 时间负荷

通过授课期间的观察和访谈结果,不同学生在完成PA时所体验到的时间负荷因人而异。在收到的67份有效反馈中,50人表示PA实验时间负荷较高,8人表示时间负担不重,9人未表态。其中,最快的学生在2个月的时间内就能够自主完成PA。对于某些能力较强的同学而言,PA平均每周花费的时间在5~6小时,短的只有2小时。因此可以说对于这些同学而言,学习的时间负荷不是很高。而对于其他学生而言,时间负荷是一个不容忽视的因素。在反馈意见中,有部分同学表示PA占据了本学期大多数时间。

从教学实践过程来看,除了平时授课时间以外,经常会遇到学生深夜在线要求答疑的情况,因此如何降低学生在学习过程中的时间负荷,是PA实验设计中应当考虑的问题。

针对该问题,我们在2017年对PA设计做了较大的调整,把部分与课程主线关联不够紧密的部分独立为可选任务,保证了主线任务的简洁性,降低学生在实验过程中的时间开销。

4.3.2 认知负荷

在PA实验过程中,认知负荷表现为实现各阶段实验目标所要付出的对理论知识理解以及代码理解相关的努力。通过分析调研反馈发现,PA实验的认知负荷主要源自两个方面:第一是与理论课程的时间失配问题;第二是框架代码本身的复杂性问题。

针对与理论课的时间失配问题,在收到的67份有效反馈意见中,有24人表示时间失配增加了PA实验的难度,1人表示时间失配没有造成困难,其余42人未明确表态。比较典型的反馈意见是理论课与PA课节奏不搭、不同老师的授课进度匹配不是很好等。

而针对框架代码本身的复杂性问题,43人明确表示框架代码的编码复杂性导致了实验困难,其余24人未明确表态,典型的反馈包括:“指令的编写花了很多时间,涉及许多宏定义,打乱了程序的理解,整体性没把握。”

针对上述调研发现的问题,我们2017年关注并调整了PA实验和理论课的时间同步问题。同时和理论课老师共同研讨规划,整个授课团队在时间安排上已达成一致,避免时间失配。针对框架代码本身的复杂性问题,我们对以往暴露出的复杂难理解的部分作了重构,经过往年学生和助教的审核,均表示代码的可读性有了较大提升,其复杂性得到了控制。

5 总结与展望

通过近3年的教学实践,南京大学计算机科学与技术系在计算机系统基础教育以及其配套的PA实验部分作了较为深入的创新和探讨。本文通过介绍和分析实验设计,给出了PA实验的整体设计思路和各阶段设计方案。对历年的成绩和访谈结果进行分析后,可以得出PA实验的有效性和对于计算机系统基础教学的积极意义。对于在教学实践过程中所暴露出的学生学习负荷较大的问题,在新版的PA实验设计中作了相应的改进。

后续将在持续改进PA实验设计的基础上,开展通过标准化量表来对学生在PA实验过程中的压力和工作负荷进行量化评估的工作。我们希望能够对学生在学习过程中的收获和体验进行更为深入的分析,从而推动PA实验的不断演进。

猜你喜欢
计算机系统实验设计理论课
大数据时代下高校体育理论课教学模式研究
不同的温度
有趣的放大镜
哪个凉得快?
关于不法分子冒充《小型微型计算机系统》名义诈骗的严正声明
IBM推出可与人类“辩论”的计算机系统
关于不法分子冒充《小型微型计算机系统》名义诈骗的严正声明
计算机系统集成实施与项目管理途径分析
浑水变清
独立学院公共体育理论课教学现状研究