Rainshaw's Blog - 课程作业
type: channel
link: https://blog.gaoruixiao.com/category/homework/
items: 隐蔽通道场景演示——操作系统与虚拟化安全实验三
items: 操作系统信任链扩展——操作系统与虚拟化安全实验二
items: Linux安装和内核编译实践——操作系统与虚拟化安全实验一
items: 计算机组织与体系结构实习Lab4——使用x86 SIMD指令对应用程序进行优化并分析
items: 计算机组织与体系结构实习Lab3——高速缓存的模拟、配置和优化
items: 计算机组织与体系结构实习Lab 2——RISC-V CPU模拟器设计与实现报告
items: 计算机组成与体系结构实习Lab1——处理器性能评测报告
items: TCP协议实验——计算机网络概论实习作业四
items: IPv4 转发实验——计算机网络概论实习作业三
items: 数据库概论——作业SQL上机

隐蔽通道场景演示——操作系统与虚拟化安全实验三
type: item
date: 2020-12-05T10:57:00+08:00
description: 实验目的选择一个已经标识的隐蔽通道，通过在SecLinux环境中进行实际编程（Ｃ语言），完成发送程序、接收程序的编写，并进行收发场景的实际效果演示。实验内容构建测试环境，选择同步机制发送和接收程序的编写、编译及运行演示存在的隐蔽通道场景实验准备使用 root 进入系统，执行 user_auth 命令获得特权发现证书过期，使用 initcert 命令生成证书再次执行 user_auth 获取特权使用 root 用户创建用户并设置安全级，设置用户密码并设置用户主目录安全级$ useradd -m -h SYS_ADMIN -v SYS_ADMIN high $ passwd high $ useradd -m -h SYS_PUBLIC -v SYS_PUBLIC low $ passwd low $ setlevel SYS_ADMIN /home/high $ setlevel SYS_PUBLIC /home/low分别从两个不同终端以 high 和 low 用户登录使用两个用户设置各自的主目录自主访问权限为0777验证 MAC 策略是否正常说明不可上读说明可以下读，但不能下写实验过程、结果同步机制采用 sleep（秒）/usleep（微秒）制造同步。当一个进程 sleep 时，就将 cpu 的控制权交给其他进程，直到 sleep 时间已到，重新获得 cpu 的控制权。实验结果（采用进程标识符信道）如下面两幅图，左侧为发送端，右侧为接收端，可以看到进程标识符信道较易受到噪声的影响导致接受信息出错。实验代码（采用进程标识符信道）发送方代码：#include <stdio.h> #include <sys/types.h> #include <unistd.h> pid_t pid[128]; const int sync_time = 3; void send(char ch){ int i; printf("sending '%c'\n", ch); for(i = 0; i < ch; i++){ pid[i]=fork() if(pid[i]==0){ sleep(1); exit(0); } } printf("\tcreate %d processes!\n", ch); } int main(){ char ch; FILE* f = fopen("in.txt", "r"); ch = fgetc(f); while(1){ send(ch); sleep(sync_time); if(ch=='!') break; ch = fgetc(f); } printf("Send Done!\n"); fclose(f); }接收方代码：#include <stdio.h> #include <sys/types.h> #include <unistd.h> pid_t firstPid, lastPid; const int sync_time = 3; int main(){ int k = 0; char ch; FILE *f = fopen('out.txt', 'w'); if ((firstPid=fork())==0){ exit(0); } sleep(1); while(1){ sleep(sync_time); if((lastPid=fork())==0){ exit(0); } printf('firstPid=%d, lastPid=%d\n', firstPid, lastPid); if(k==0){ ch=lastPid-firstPid-2; }else{ ch=lastPid-firstPid-1; } printf("\tReceive the '%c'\n", ch); fputc(ch, f); firstPid = lastPid; k=1; if(ch == '!') break; } printf("Receive Done!\n"); fclose(f); }流程图（采用进程标识符信道）sequenceDiagram participant Sender participant Receiver Receiver ->> Receiver: start, firstPid, sleep 3 Sender ->> Sender: start loop send message Sender ->> Sender: read char, create int(char) processes Sender ->> Receiver: send the char(char) Receiver ->> Receiver: lastPid, calc char(char), f…

操作系统信任链扩展——操作系统与虚拟化安全实验二
type: item
date: 2020-12-05T10:48:22+08:00
description: 实验目的了解TPM安全芯片的组成和作用掌握计算平台信任链扩展的原理及作用掌握IMA的工作原理及作用实验内容扩展Linux系统增加IMA功能，使信任链由OS层扩展到用户应用层。运行三类程序，观察IMA的作用：用户应用程序、共享库、内核模块。实验过程、结果实验使用的是 Ubuntu16.04 操作系统在该版本内核中，已默认勾选IMA功能，并挂载了 securityfs 文件系统为系统启用 IMA 功能，编辑引导文件 /etc/default/grub，增加启用选项：即在 GRUB_CMDLINE_LINUX 一项中加入 ima_tcb 即可更新引导文件， sudo update-grub2，重启系统查看IMA记录的应用度量值运行程序观察IMA的作用用户应用程序编写任意C应用程序hello.c，编译并运行，观察观察ima securityfs的变化。程序的编译和运行参考如下命令：$ gcc hello.c -o hello $ ./hellohello.c#include <stdio.h> int main() { printf("Hello World\n"); } 运行 cat/sys/kernel/security/ima/ascii_runtime_measurements 命令后，结果如下图所示。可以看到运行应用程序之后 /home/dreamer/codes/hello 出现在 IMA 度量值中。共享库编写任意Linux共享库(*.so)，并编写任意c应用链接此共享库，编译并运行，观察 ima securityfs 的变化，参考以下命令$ gcc -o libhello.so -fPIC -shared hello.c $ cp libhello.so /lib $ gcc -o main -lhello main.c $ ./mainhello.c#include <stdio.h> void print_hello() { printf("Hello World\n"); }main.cextern void print_hello(); int main(int argc, char argv[]) { print_hello(); return 0; }运行 cat /sys/kernel/security/ima/ascii_runtime_measurements 命令后，观察到结果如下图所示，/lib/libhello.so 和 /home/dreamer/codes/2/main 出现在 IMA 度量值中。内核模块编写任意 Linux 内核模块，编译并加载，观察 ima securityfs 的变化。命令参考如下$ make $ insmod hello.ko $ dmesg $ rmmod hello.ko $ dmesghello.c#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> /*用于告诉内核该模块拥有GPL license*/ MODULE_LICENSE("GPL"); /*执行模块初始化工作*/ static int __init hello_init(void) { printk(KERN_INFO "Hello,module\n"); return 0; } /*执行模块析构工作*/ static void __exit hello_exit(void) { printk(KERN_INFO "Goodbye,module\n"); } /*该函数注册模块的构造函数*/ module_init(hello_init); /*该函数注册模块的析构函数*/ module_exit(hello_exit);Makefileobj-m := hello.o all: make -C /lib/modules/$(shell uname –r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname –r)/build M=$(PWD) clean 查看 kernel message 可以发现程序的打印信息。运行 cat /sys/kernel/security/ima/ascii_runtime_measurements 命令后，观察到结果如下图所示 /home/dreamer/codes/3 目录下的各文件出现在 IMA 度量值中。实验总结实验收获学到了IMA方面的知识，对Linux操作系统有了进一步的了解。遇到的问题和解决办法IMA 功能虽默认编译进内核，但默认情况下不会启用，执行 cat /sys/kernel/…

Linux安装和内核编译实践——操作系统与虚拟化安全实验一
type: item
date: 2020-11-24T15:23:00+08:00
description: 实验目的学习 Linux 内核编译和升级的过程，并从中学习 Linux 内核的组成，掌握排错能力。实验内容安装 Parallels Desktop 并初始化 Linux 虚拟机下载新版本 Linux 内核进行编译安装升级实验过程、结果安装 Parallels Desktop，并从网上下载 Ubuntu16.04 镜像（略）使用 Ubuntu16.04 镜像新建虚拟机，并做初始化工作更新系统软件并查看内核版本可以看到Ubuntu16.04默认的内核版本为4.15下载内核并进行编译安装升级到 https://www.kernel.org/ 查看最新的Linux内核版本为4.19，下载压缩包并拷贝到 /usr/src 目录下进入 /usr/src 目录下，解压 cd /usr/src && sudo tar -xvf linux-4.19.149.tar.xz进入 linux-4.19.149 目录，执行 tree -dL 1文件夹简介arch根据cpu架构区分的代码block块设备驱动程序certs内置证书crypto加密，压缩drivers设备驱动程序fs文件系统include头文件lib库函数文件mm内存管理net网络协议代码scripts配置脚本securitySElinux的模块sound音频设备的驱动程序virt内核虚拟化执行 sudo make menuconfig，遇到报错原因是缺少 libncurses-dev 使用命令 sudo apt install libncurses-dev 进行安装后再次运行 sudo make menuconfig，遇到报错可以看到出错的位置是 bison: not found 即缺少 bison ，使用命令 sudo apt install bison 解决，再次运行 sudo make menuconfig，遇到报错可以看到出错的位置是 flex: not found 即缺少 flex， 使用命令 sudo apt install flex 解决， 再次运行 sudo make menuconfig 无报错使用默认配置，选择 Exit 并保存编译内核，执行命令 sudo make -j12，遇到报错可以看出是缺少 libssl-dev 库，使用 sudo apt install libssl-dev 进行安装后再次执行命令 sudo make -j12，没有遇到报错安装内核，依次执行命令sudo make modules_install sudo make install更新 grub 引导后重启sudo update-grub2 && sudo reboot执行 uname -r 查看内核版本实验总结内核升级必要的包需要哪些？答：从排错过程来看，需要libncurses-dev, bison, flex, libssl-dev编译内核的步骤是什么？答：首先使用命令生成配置文件 .config 实验中采用的是 make menuconfig 即采用基于文本菜单的配置命令，除此之外还有make config 也可以生成 .config 文件，后者是基于文本配置界面的配置命令。然后使用命令 make -j12 开始编译。之后使用命令 make modules_install 进行模块的编译和安装。最后进行 make install 进行安装并使用命令 upgrade-grub2 更新引导。在编译过程中可能遇到的问题有哪些，解决的办法是什么？缺少依赖包、库，解决办法是安装这些缺少的依赖项。你具体遇到了什么困难，怎么解决的？没怎么遇到困难。出现的错误都很好解决。本次实验让我学习了 Linux 内核的编译与升级步骤，了解了内核的组成。

计算机组织与体系结构实习Lab4——使用x86 SIMD指令对应用程序进行优化并分析
type: item
date: 2020-05-29T18:13:00+08:00
description: 使用x86 SIMD指令对应用程序进行优化并分析图像格式转化YUV2RGB:$$ \begin{bmatrix} R\\ G\\ B \end{bmatrix} = \begin{bmatrix} 1.164383 & 0 & 1.596027 \\ 1.164383 & -0.391762 & -0.812968 \\ 1.164383 & 2.017232 & 0 \end{bmatrix} \begin{bmatrix} Y-16\\ U-128\\ V-128 \end{bmatrix} $$Alpha 混合:$$ \begin{bmatrix} R^\prime\\G^\prime\\B^\prime \end{bmatrix} = \begin{bmatrix} A/256 & 0 & 0 \\ 0 & A/256 & 0 \\ 0 & 0 & A/256 \\ \end{bmatrix} \begin{bmatrix} R\\G\\B \end{bmatrix} $$RGB2YUV:$$ \begin{bmatrix} Y\\U\\V \end{bmatrix} = \begin{bmatrix} 0.256788 & 0.504129 & 0.097906 \\ -0.148223 & -0.290993 & 0.439216 \\ 0.439216 & -0.367788 & -0.071427 \end{bmatrix} \begin{bmatrix} R^\prime\\G^\prime\\B^\prime \end{bmatrix} + \begin{bmatrix} 16\\128\\128 \end{bmatrix} $$基础ISA直接实现上述矩阵乘法即可。源代码如下：void BasicProcessor() { auto *data = new Pixel[size]; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int offset = i * width + j; int yi = (uint8_t) y[i][j]; int ui = (uint8_t) u[i / 2][j / 2]; int vi = (uint8_t) v[i / 2][j / 2]; int r = 1.164383 * (yi - 16) + 1.596027 * (vi - 128); int b = 1.164383 * (yi - 16) + 2.017232 * (ui - 128); int g = 1.164383 * (yi - 16) - 0.391762 * (ui - 128) - 0.812968 * (vi - 128); data[offset].r = between(r); data[offset].b = between(b); data[offset].g = between(g); } } for (int num = 0; num < frame_num; num++) { int a = num * 3 + 1; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int offset = i * width + j; int r = data[offset].r * a / 256.0; int b = data[offset].b * a / 256.0; int g = data[offset].g * a / 256.0; int yi = 0.256788 * r + 0.504129 * g + 0.097906 * b + 16; int ui = -0.148223 * r - 0.290993 * g + 0.439216 * b + 128; int vi = 0.439216 * r - 0.367788 * g - 0.071427 * b + 128; result[num][0][offset] = yi; result[num][1][(i / 2) * (width / 2) + (j / 2)] = ui; result[num][2][(i / 2) * (width / 2) + (j / 2)] = vi; } } } delete[] data; }MMX扩展指令MMX是一个比较老的指令集，只支持整数运算，使用64位寄存器，在C++中可以通过引用mmintrin.h头文件。由于原本运算都是浮点数运算，这里我参考stackoverflow给出的算法，给出了使…

计算机组织与体系结构实习Lab3——高速缓存的模拟、配置和优化
type: item
date: 2020-05-10T15:19:00+08:00
description: 高速缓存的模拟、配置和优化单级Cache模拟单层Cache模拟器，主程序在source-code/CacheMain.cpp中，主要负责读取trace文件，并执行Cache模拟。由于第二阶段需与CPU模拟器级联，故新编写Cache.cpp文件并修改原有文件使得可以正确运行。MemoryManager模块修改主存在本次试验中是最底层的存储器，故对于主存必然命中。主存对于读取字节的响应延迟应为总线延迟和主存命中延迟之和。主存对于写若干字节的响应延迟应为总线延迟和主存命中延迟之和。将原有get,set函数修改，均加入延迟时间计算。Cache模块设计缓存在运行过程中，会不停接收到读、写请求，根据自身情况，分别响应读命中、读不命中、写命中、写不命中。对于读命中，从存储中取出内容，经过总线延迟和命中延迟完成动作。对于读不命中，首先找到空闲块或待替换的块，若write_back为真，则将被替代块写回下一层存储，再向下一层存储发出读请求替换至准备好的块中，再进行读命中操作，需经过总线延迟和命中延迟再加上下一级的延迟来完成。对于写命中，若write_back为真，则设置dirty为真，之后进行写入操作。若write_back为真，需经总线延迟与命中延迟完成；否则，需向下一级存储发出写请求，等待下一级存储也写入完成，需总线延迟、命中延迟和下一级的延迟完成。对于写不命中，若write_alloc为真，则需先替换块，再根据wirte_back决定写入时的操作。需要总线延迟、命中延迟再加上下一级的延迟完成；否则，直接向下一级传递请求，需总线延迟、命中延迟、下一级延迟完成。Miss Rate 随 Block Size 的变化如图所示为在不同Cache Size的条件下，Miss Rate 随 Block Size的变化趋势，取associativity为8。可以看出，随着Block Size的增大，Miss Rate会逐渐减小至一稳定值。Miss Rate 随 Associativity 的变化如图所示，为固定Block Size 为64Byte，Miss Rate随Associativity的变化趋势。可以看出，绝大多数情况，随着associativity的增大，Miss Rate也会逐渐减小至一稳定值。Write Through, Write Back, Write Allocate和 No-write Allocate访问延时差异如图所示，在不同的写策略时，总访问延时有一定区别。可以看到，Write Back策略访问延时明显低于Write Through；Write Allocate对延时的减小有微弱的帮助。与CPU模拟器级联修改Simulator模块、主程序模块，将Cache加入至流水线模拟之中。这里采用Cache模块计算访存延迟并返回给流水线模拟器，再将该延迟加入到流水线模拟器的周期数中，以便计算CPILevelCapacityAssociativityBlock SizeWrite PolicyHit LatencyL132KB8 ways64Write Back1 CPU CycleL2256KB8 ways64Write Back8 CPU CycleLLC8MB8 ways64Write Back20 CPU Cycle程序运行结果$ ./Sim ../$dir/others/ackermann.riscv Ackermann(0,0) = 1 Ackermann(0,1) = 2 Ackermann(0,2) = 3 Ackermann(0,3) = 4 Ackermann(0,4) = 5 Ackermann(1,0) = 2 Ackermann(1,1) = 3 Ackermann(1,2) = 4 Ackermann(1,3) = 5 Ackermann(1,4) = 6 Ackermann(2,0) = 3 Ackermann(2,1) = 5 Ackermann(2,2) = 7 Ackermann(2,3) = 9 Ackermann(2,4) = 11 Ackermann(3,0) = 5 Ackermann(3,1) = 13 Ackermann(3,2) = 29 Ackermann(3,3) = 61 Ackermann(3,4) = 125 Program exit from exit() system call -------STATISTICS--------- Number of Cycles: 520797 Number of Instructions: 430659 Avg Cycles per Instrcution: 1.2093 Number of JALR Instructions: 13740…

计算机组织与体系结构实习Lab 2——RISC-V CPU模拟器设计与实现报告
type: item
date: 2020-04-11T00:38:00+08:00
description: RISC-V CPU模拟器设计与实现报告一、开发环境1.1 RISCV交叉编译工具的安装和使用为测试模拟器的正确性，必须将源程序编译为基于RISCV指令的可执行程序，而由于个人计算机一般是x86架构的，所以需要交叉编译工具在x86电脑上编译生成RISCV架构可执行程序。为配置环境，执行了以下操作从Github上下载了riscv-tools，从issues中得知，交叉编译工具已移动到riscv-gnu-toolchain项目中，于是执行了以下命令cd ~ && mkdir source-code && cd "$_" git clone --recursive https://github.com/riscv/riscv-gnu-toolchain cd riscv-gnu-toolchain注意到在编译riscv-gnu-toolchain时，默认配置为支持RV64IMAFDC指令集，即RV64GC指令集，如下图，此时使用该工具编译时即使设置参数-Wa, -march=rv64i仍会链接使用扩展指令集的标准函数，其中C指令很多，并且导致我们的模拟器无法从程序入口执行，必须寻找main函数的位置。所以，为了得到只使用RV64I的ELF程序，必须在编译riscv-gnu-toolchain时便指定指令集，于是执行了以下命令# cd riscv-gnu-toolchain mkdir build-rv64i && cd "$_" ../configure --with-arch=rv64i --prefix=$HOME/riscv/riscv64i make -j$(nproc)此时，使用riscv64-unknown-elf-gcc对测试代码编译时，便只会使用RV64I标准集的指令，为了谨慎起见，我仍然在编译命令中加入了相关参数。编译指令示例如下$HOME/riscv/riscv64i/bin/riscv64-unknown-elf-gcc -Wa,-march=rv64i test/matrixmulti.c test/lib.c -o riscv-elf/others/matrixmulti.riscv $HOME/riscv/riscv64i/bin/riscv64-unknown-elf-objdump -D riscv-elf/others/matrixmulti.riscv > riscv-elf/others/matrixmulti.s除RV64I基本指令集外，我还额外实现了M扩展集的部分指令，所以上述命令修改为mkdir build-rv64im && cd "$_" ../configure --with-arch=rv64im --prefix=$HOME/riscv/riscv64i make -j$(nproc) $HOME/riscv/riscv64im/bin/riscv64-unknown-elf-gcc -Wa,-march=rv64im test/matrixmulti.c test/lib.c -o riscv-elf/others/matrixmulti.riscv $HOME/riscv/riscv64im/bin/riscv64-unknown-elf-objdump -D riscv-elf/others/matrixmulti.riscv > riscv-elf/others/matrixmulti.s在我编写的编译测试代码的脚本文件中，均含有以下三句dir=~/riscv/riscv64im/bin rvgcc=$dir/riscv64-unknown-elf-gcc flags='-Wa,-march=rv64im'通过修改dir flags参数可以改变上述命令中的编译器位置和编译选项。脚本中默认为使用--with-arch=rv64im参数编译生成的编译器，并且编译测试代码时的编译选项为-Wa,-march=rv64im。二、设计概述2.1 设计目标首要目标是实现一个流水线的模拟器，能够处理基本指令集，完成程序设计目标，并且程序的鲁棒性必须好，应该能够实现拒绝不正常的内存访问等。其次，由于程序没有实现并行操作，实际上仍然是依次顺序执行5个阶段，所以部分冒险情况可以被简化。此外，本模拟器没有选择兼容Linux的系统调用，而是选择使用自定义的系统调用，因此只能运行专门为此编写的程序（相关源码参见test/文件夹），同时，由于课程作业中提供的测试文件均没有包含特殊的系统调用，因此本模拟器也可以运行它们（相关源码参见test-inclass/文件夹）。2.2 编译与运行本项目提供了一个自动化脚本runme.sh，用于编译本模拟器，并模拟运行测试程序。或者可以采用手动方式，命令如下# cd…

计算机组成与体系结构实习Lab1——处理器性能评测报告
type: item
date: 2020-04-07T10:19:00+08:00
description: 处理器性能评测报告我们针对系统评测的不同角度会采用不同的评测程序。在目前已有的评测程序中，为下列评测目标找到某些合适的评测程序（列出即可）测评目标测评程序测评目标测评程序CPU整点性能SPECint2017CPU浮点性能SPECfp2017计算机事务处理能力TPC-C嵌入式系统计算能力CoreMark2D处理能力3DMark3D处理能力3DMark并行计算性能LINPACK系统响应速度Loadrunner编译优化能力SPECint2017操作系统性能Sysbench多媒体处理能力PassMark SoundCheck™IO处理能力Iozone浏览器性能wrk网络传输速率NetperfJava运行环境性能Specjbb2005邮件服务性能servermark文件服务器性能servermarkWeb服务器性能servermark服务器功耗和性能SPECpower 阅读文献（Reinhold P.Weicker, An Overview of Common Benchmarks, IEEE Computer, December 1990.）并回答下面的问题简述用于性能评测的MIPS指标之含义，以及它是如何被计算的MIPS 有多种含义，使用时必须特别指出Native MIPS, 即每秒执行的百万指令数。由于 RISC 指令系统的精简设计， RISC 在相同情况下是 CISC 的 MIPS 的数倍。Peak MIPS, 指处理器的MIPS峰值，在数值上等于处理器频率。EDN MIPS, Dhrystone MIPS指运行特定程序得到的 Native MIPS 或者 VAX MIPSVAX MIPS, 指定 VAX 11/780 为 1MIPS，规定程序功能、语言、编译器，将待测机器的运行时间与 VAX 11/780 作比，比值就是待测机器的 MIPS 。使用linux下的剖视工具（例如gprof）对dhrystone和whetstone进行剖视，参考论文Table 1形式给出数据，你的结果和该论文是否一致，为什么?使用 -pg -static 进行编译.procedure profile for dhrystone(cc_dry2)从图片中可以看出,我的结果与论文基本相同.猜测原因是整型运算和库函数运行速度目前基本只与处理器频率相关,因此其占比没有很大变化.procedure profile for whetstone3从图片中可以看出, 我的结果与论文中不同, 我认为是计算机能力造成的.我的计算机和论文作者的计算机的浮点运算能力之间存在较大差异,导致了结果的不同.文中讨论了处理器之外可能对性能造成影响的因素，请分别使用两种不同的语言（例如C和Java）使用同一算法实现快速排序、矩阵乘法、求Ackermann函数，验证文中的观点。（请保留你的程序，我们在后面可能还会用到它）我的程序采用了 C 和 Python. 论文中认为除CPU外,编程语言、编译器、动态库、高速缓存以及内存大小都会影响到程序到性能编程语言: 在 C 和 Python 两种语言中, 众所周知 C 语言一般比 Python 语言要快.编译器: 不同到编译选项也会直接影响程序性能,优化选项 -O0 到 -O3 性能一般会增加, -register 选项会要求运算只使用寄存器, -ffast-math 会针对浮点运算进行某些优化.动态库: 通过剖视可以看出, 程序执行过程中总有一部分时间需要调用和执行库函数,不同库有不同实现方式,会对性能有所影响.高速缓冲: 一般缓存越大,性能越快. 这一点同样适用于内存.快排中,对一个长度为$10^5$的整数数列进行快排,该数列事先生成,两种语言各循环100次, C语言耗时15s, Python耗时39s矩阵乘法算法中,采用朴素的$O(n^3)$算法, 对两个 1000*1000 的整数矩阵进行矩阵乘法,各循环100次, C 耗时 54s, Python 不使用 numpy 库函数耗时103s, 利用 numpy 库函数仅耗时 13s求 Ackermann 函数, 对A(40,20)循环$10^6$次, C 耗时2s, python 耗时 1167s (一度以为卡死了...但做了下面的benchmark我又觉得这个时间还行).从以上结果可以看出, C 语言基本上都比 Python 的要快上一个数量级.性能评测 基于某个给定的计算机系统平台，使用dhrystone、whetstone、SPEC CPU2000开展评测、分析、研究并给出报告。工作背景和评测目标本次实验通过使用dhrystone,whetstone,SPEC CPU2000对个人PC进行测评，目标是掌握Benchmark的使用和测评估计办法。经过此次实验，我对Benchmark的…

TCP协议实验——计算机网络概论实习作业四
type: item
date: 2019-05-29T22:03:00+08:00
description: TCP协议实验[TOC]实验目的本实验的主要目的是学习和了解 TCP 协议的原理和设计实现的机制。TCP 协议还要向应用层提供编程接口，即网络编程中所普遍使用的 Socket 函数。通过实现这些接口函数，可以深入了解网络编程的原理，提高网络程序的设计和调试能力。实验要求1) 了解 TCP 协议的主要内容，并针对客户端角色的、“停-等”模式的 TCP 协议，完成对接收和发送流程的设计。2) 实现 TCP 报文的接收流程，重点是报文接收的有限状态机。3) 实现 TCP 报文的发送流程，完成 TCP 报文的封装处理。4) 实现客户端 Socket 函数接口。实验内容实验内容主要包括:1) 设计保存 TCP 连接相关信息的数据结构(一般称为 TCB，Transmission Control Block)。2) TCP 协议的接收处理。3) TCP 协议的封装发送。4) TCP 协议提供的 Socket 函数接口问题记录gSrcPort应该为2007，而非指导书上的2005在stud_tcp_output()中新建的TCB，在stud_tcp_input()中调用要将接收端和发送端互换实验源码代码基于上次作业修改完成，故有较多注释/* * THIS FILE IS FOR TCP TEST */ /* struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; */ #include "sysInclude.h" extern void tcp_DiscardPkt(char *pBuffer, int type); extern void tcp_sendReport(int type); extern void tcp_sendIpPkt(unsigned char *pData, UINT16 len, unsigned int srcAddr, unsigned int dstAddr, UINT8 ttl); extern int waitIpPacket(char *pBuffer, int timeout); extern unsigned int getIpv4Address(); extern unsigned int getServerIpv4Address(); #define BUFFER_SIZE 1024 #define TIMEOUT 10 #define FIN 0x01 #define SYN 0x02 #define ACK 0x10 #define FIN_ACK 0x11 #define SYN_ACK 0x12 #define CLOSED 0 #define LISTEN 1 #define SYN_RCVD 2 #define SYN_SENT 3 #define ESTABLISHED 4 #define FIN_WAIT_1 5 #define FIN_WAIT_2 6 #define TIME_WAIT 7 #define GetSrcPort(p) (ntohs(*(UINT16*)p)) #define GetDstPort(p) (ntohs(*(UINT16*)(p+2))) #define GetSeq(p) (ntohl(*(UINT32*)(p+4))) #define GetACK(p) (ntohl(*(UINT32*)(p+8))) #define GetHeaderLength(p) ((p[12]>>2)&0x3C) #define GetFlags(p) (p[13]&0x13) #define SetSrcPort(p,x) *(UINT16*)p=htons(x) #define SetDstPort(p,x) *(UINT16*)(p+2)=htons(x) #define SetSeq(p,x) *(UINT32*)(p+4)=htonl(x) #define SetACK(p,x) *(UINT32*)(p+8)=htonl(x) #define SetHeaderLength(p,x) p[12]=(x<<2) #define SetFlags(p,x) p[13]=x #define SetWindow(p,x) *(UINT16*)(p+14)=htons(x) #define SetCheckSum(p,x) *(UINT16*)(p+16)=x int gSrcPort = 2007; int gDstPort = 2006; int gSeqNum=1; int gAckNum=1; struc…

IPv4 转发实验——计算机网络概论实习作业三
type: item
date: 2019-05-16T15:10:00+08:00
description: IPv4转发实验实验目的本实验设计模拟实现路由器中的 IPv4 协议，可以在原有 IPv4 分组收发实验的基础上，增加 IPv4 分组的转发功能。对网络的观察视角由主机转移到路由器中，了解路由器是如何为分组选择路由，并逐跳地将分组发送到目的主机。本实验中也会初步接触路由表这一重要的数据结构，认识路由器是如何根据路由表对分组进行转发的。实验要求在前面 IPv4 分组收发实验的基础上，增加分组转发功能。具体来说，对于每一个到达本机的 IPv4 分组，根据其目的 IPv4 地址决定分组的处理行为，对该分组进行如下的几类操作:1) 向上层协议上交目的地址为本机地址的分组;2) 根据路由查找结果，丢弃查不到路由的分组;3) 根据路由查找结果，向相应接口转发不是本机接收的分组。实验内容实验内容主要包括:1) 设计路由表数据结构。2) IPv4 分组的接收和发送。3) IPv4 分组的转发。实验过程路由表维护需要完成下列分组接收处理步骤:1) stud_Route_Init()函数中，对路由表进行初始化。2) stud_route_add()函数中，完成路由的增加。转发处理流程在stud_fwd_deal()函数中，需要完成下列分组接收处理步骤:1) 查找路由表。根据相应路由表项的类型来确定下一步操作，错误分组调用函数 fwd_DiscardPkt()进行丢弃，上交分组调用接口函数 fwd_LocalRcv()提交给上层协议继续处理，转发分组进行转发处理。注意，转发分组还要从路由表项中获取下一跳的 IPv4 地址。2) 转发处理流程。对 IPv4 头部中的 TTL 字段减 1，重新计算校验和，然后调用下层接口 fwd_SendtoLower()进行发送处理。实验源码代码基于上次作业修改完成，故有较多注释#include "sysInclude.h" #include<vector> #include <iostream> // system support extern void fwd_LocalRcv(char *pBuffer, int length); extern void fwd_SendtoLower(char *pBuffer, int length, unsigned int nexthop); extern void fwd_DiscardPkt(char *pBuffer, int type); extern unsigned int getIpv4Address(); using namespace std; typedef struct { unsigned int nexthop; unsigned dest; } routeItem; vector<routeItem> myroute; int stud_fwd_deal(char * pBuffer, int length){ printf("Check IP Version:\n"); unsigned int version=(pBuffer[0]>>4); printf("IP Version is %d\n", version); // if(version!=4){ // ip_DiscardPkt(pBuffer, STUD_IP_TEST_VERSION_ERROR); // return 1; // } printf("Check Header Length:\n"); unsigned int len=(pBuffer[0]&0xF); printf("Header Length is %d\n", len); // if(len<5){ // ip_DiscardPkt(pBuffer, STUD_IP_TEST_HEADLEN_ERROR); // return 1; // } printf("Check CheckSum:\n"); unsigned int sum=0; for(int i=0;i<len*2;i++){ sum+=((unsigned short*)pBuffer)[i]; sum=(sum>>16)+(sum&0xffff); } cout<<sum<<endl<<~sum<<endl; //cout<<bitset<sizeof(short)*8>((unsigned short)sum)<<endl; //ut<<bitset<sizeof(short)*8>(~(unsigned short)sum)<<endl; printf("Check Sum is %d\n", ~sum); printf("CheckSUM is %d\n", ((unsigned short*)pBuffer)[5]); // …

数据库概论——作业SQL上机
type: item
date: 2019-05-10T19:29:00+08:00
description: 数据库SQL上机练习1.求供应了某两种不同目录（自己指定）下的产品的供应商姓名。选择目录1和目录2select distinct companyname from Production.Suppliers where supplierid in ( select A.supplierid from Production.Products A, Production.Products B where A.supplierid = B.supplierid and A.categoryid = 1 and B.categoryid = 2 );查询结果：共4行companySupplier CIYNMSupplier GQRCVSupplier SVIYASupplier SWRXU2.求没有供应某两种不同目录（自己指定）下的产品的供应商姓名。选择目录1和目录2select distinct companyname from Production.Suppliers where supplierid not in ( select distinct A.supplierid from Production.Products A where A.categoryid = 1 or A.categoryid = 2 );查询结果：共17行，列举前5行companySupplier BWGYESupplier EQPNCSupplier ERVYZSupplier FNUXMSupplier JDNUG···3.求只向与自己位于不同城市的顾客供应产品的供应商姓名。select distinct companyname from Production.Suppliers where supplierid not in ( select distinct Suppliers.supplierid from Sales.Orders, Sales.OrderDetails, Production.Products, Production.Suppliers, Sales.Customers where Orders.orderid = OrderDetails.orderid and OrderDetails.productid = Products.productid and Products.supplierid = Suppliers.supplierid and Orders.custid = Customers.custid and Customers.city = Suppliers.city )查询结果：共26行，列举前5行companySupplier BWGYESupplier CIYNMSupplier ELCRNSupplier EQPNCSupplier ERVYZ···4.求每个城市中供应产品数量最多的供应商姓名。select distinct shipcity, companyname, sum(qty) from Production.Suppliers, Production.Products, Sales.OrderDetails, Sales.Orders A where Products.supplierid = Suppliers.supplierid and OrderDetails.productid = Products.productid and A.orderid = OrderDetails.orderid group by shipcity, Products.supplierid, companyname having sum(qty) >= all ( select sum(qty) from Production.Suppliers, Production.Products, Sales.OrderDetails, Sales.Orders where Products.supplierid = Suppliers.supplierid and OrderDetails.productid = Products.productid and OrderDetails.orderid = Orders.orderid and A.shipcity = Orders.shipcity group by Products.supplierid )查询结果：共75行，列举前5行shipcitycompanynamesum(qty)AachenSupplier OAVQT30AlbuquerqueSupplier OGLRK185AnchorageSupplier GQRCV165ÅrhusSu…