Compare commits

...

No commits in common. 'main' and 'homework5' have entirely different histories.

40 changed files with 837342 additions and 2374 deletions
Split View
  1. +0
    -52
      .gitignore
  2. +391
    -0
      Cache Lab.md
  3. +0
    -12
      LAB1/Driverhdrs.pm
  4. +0
    -138
      LAB1/Driverlib.pm
  5. +0
    -33
      LAB1/Makefile
  6. +0
    -140
      LAB1/README
  7. +0
    -388
      LAB1/bits.c
  8. +0
    -65
      LAB1/bits.h
  9. +0
    -583
      LAB1/btest.c
  10. +0
    -32
      LAB1/btest.h
  11. +0
    -86
      LAB1/decl.c
  12. +0
    -0
      LAB1/dlc
  13. +0
    -439
      LAB1/driver.pl
  14. +0
    -151
      LAB1/fshow.c
  15. +0
    -75
      LAB1/ishow.c
  16. +0
    -124
      LAB1/tests.c
  17. +0
    -21
      LICENSE
  18. +33
    -0
      Makefile
  19. +27
    -0
      README
  20. +0
    -35
      README.md
  21. BIN
      aqua-handin.tar
  22. +83
    -0
      cachelab.c
  23. +37
    -0
      cachelab.h
  24. BIN
      csim
  25. BIN
      csim-ref
  26. +152
    -0
      csim.c
  27. BIN
      test-csim
  28. BIN
      test-trans
  29. +261
    -0
      test-trans.c
  30. +567064
    -0
      trace.tmp
  31. BIN
      tracegen
  32. +108
    -0
      tracegen.c
  33. +5
    -0
      traces/dave.trace
  34. +267988
    -0
      traces/long.trace
  35. +596
    -0
      traces/trans.trace
  36. +7
    -0
      traces/yi.trace
  37. +16
    -0
      traces/yi2.trace
  38. +183
    -0
      trans.c
  39. BIN
      trans.o
  40. +391
    -0
      实验报告.md

+ 0
- 52
.gitignore View File

@ -1,52 +0,0 @@
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf

+ 391
- 0
Cache Lab.md View File

@ -0,0 +1,391 @@
# Cache Lab
10225501432 邓博昊
## Part A
要求:实现一个缓存模拟器,根据给定的 trace 文件来输出对应的操作
讲义提供了一个程序示例,在安装valgrind后,使用如下命令
```bash
valgrind --log-fd=1 --tool=lackey -v --trace-mem=yes ls -l
```
输出的trace文件内容如下
```bash
I 04ead900,3
I 04ead903,3
I 04ead906,5
I 04ead838,3
I 04ead83b,3
I 04ead83e,5
L 1ffefff968,8
I 04ead843,3
I 04ead846,3
I 04ead849,5
L 1ffefff960,8
I 04ead84e,3
I 04ead851,3
......
```
trace文件中记载着每一次对内存的操作,前面的字母代表操作类型,统一的格式是:
```
[空格][操作类型][空格][内存地址][逗号][大小]
```
在此过程中,如若第一个字符并非空格而为I,则意指执行加载操作,并无实质意义。
操作类型主要分布于以下三种:
1. L:读取,从内存中检索
2. S:存储,向内存中写入
3. M:修改,此过程包括一次读取及一次存储操作
地址则指向一个64位16进制内存地址;而大小则用以表示该操作所需访问的内存字节数。需要注意的是,I指令无需插入空格,而M/S/L指令之前需添加一个空格用于解析指令。
随后,实验为我们提供了一个名为csim-ref的程序,任务便是撰写一份与之功能一致的程序。
```bash
Usage: ./csim-ref [-hv] -s <num> -E <num> -b <num> -t <file>
Options:
-h Print this help message.
-v Optional verbose flag.
-s <num> Number of set index bits.
-E <num> Number of lines per set.
-b <num> Number of block offset bits.
-t <file> Trace file.
Examples:
linux> ./csim-ref -s 4 -E 1 -b 4 -t traces/yi.trace
linux> ./csim-ref -v -s 8 -E 2 -b 4 -t traces/yi.trace
```
**分析**
`getopt`获取命令行参数
`fscanf`读入trace文件内容
`malloc`分配空间给cache
数据访问带来的miss:
* L:Load,数据载入,可能发生1次miss
* S:Store,可能发生1次miss
* M:store后再load,两次访存。1 miss & 1 hit + 可能eviction
所以L/S指令结果是miss或者hit或者miss+eviction;而M指令结果是hit+hit或者miss+hit 或者 miss+eviction+hit
### Cache结构
设计Cache基本单元为 `block`,cache由cacheblock组成
```c
typedef struct
{
unsigned tag;
unsigned usedtime;
} block;
block *cache;
```
其中`usedtime`是判断LRU cache行。初始值为0表示没有用过,相当于invalid。非零值越小代表越少使用,`usedtime`最大代表刚使用。
### 命令行参数解析
首先对命令行参数进行解析
```C
int getOpt(int argc,char **argv,int *s,int *E,int *b,int *verbose,char *tracefile)
{
int oc;
while((oc=getopt(argc,argv,"hvs:E:b:t:"))!=-1){
switch(oc){
case 'h': printHelpMenu();break; // print usage
case 'v': *verbose=1;break;
case 's': *s = atoi(optarg);break;
case 'E': *E = atoi(optarg);break;
case 'b': *b = atoi(optarg);break;
case 't': strcpy(tracefile,optarg);break;
default : printf("input error\n");break;
}
}
return 0;
}
```
### 初始化cache
然后初始化cache
```C
cache = (block *)malloc(sizeof(block)* E<<s);
memset(cache,0,sizeof(block)* E<<s);
```
### 读取文件参数
`fscanf`读取trace文件中的指令、地址
```c
fp = fopen (tracefile,"r");
while(fscanf(fp,"%s%x,%d\n",op,&addr,&size) > 0){
if(verbose)
printf("%s %x,%d ",op,addr,size);
switch(op[0]){
case 'M': hit++;
case 'L':
case 'S': find(op[0],addr,size,++t);
}
}
```
### 数据访问
获取`tag`和 `set index`
```C
unsigned tag = addr >>b >>s ;
unsigned set_index = addr >> b &((1<<s) -1);
```
找到对应的set
```c
block *cache_set = cache + E * set_index ; // set address
block *eviction_block = cache_set; // LRU cacheline
```
进行数据查找,其中eviction_block表示查询过程中LRU的cache行,也就是usedtime最小的(但是非0)在一个set里面遍历cache行
* 如果`usedtime`!=0且tag匹配:hit
* 如果`usedtime`=0,是个空block,使用这个block:miss
* 如果`usedtime`!=0,tag不匹配,跟`eviction_block.usedtime`比较,如果时间更小,更新`eviction_block`=该cacheblock
如果循环结束,也就证明该set的所有cache行都满了,就替换LRU cache行。
```c
void find(char op, unsigned addr,unsigned size,int time){
int i;
unsigned tag = addr >>b >>s ;
unsigned set_index = addr >> b &((1<<s) -1);
block *cache_set = cache + E * set_index ; // set address
block *eviction_block = cache_set; // LRU cacheline
for(i = 0;i<E;i++){
if(cache_set[i].usedtime>0 && cache_set[i].tag ==tag){ //hit
cache_set[i].usedtime = time;
hit++;
if(verbose) cacheStateOut(op,0);
return;
}
else if(!cache_set[i].usedtime){ // empty block
miss++;
cache_set[i].tag = tag;
cache_set[i].usedtime = time;
if(verbose) cacheStateOut(op,1);
return;
}
else if(cache_set[i].usedtime < eviction_block->usedtime) // !=tag , current block is older
eviction_block = cache_set+i;
}
miss ++;
eviction ++;
eviction_block->tag = tag; // replace sacrifice cacheline
eviction_block->usedtime = time;
if(verbose) cacheStateOut(op,2);
return ;
}
```
## Part B
Part B 要我们实作矩阵转置,并将 cache miss 尽可能降低,Part B 的程序限制如下
- 在 stack 中至多 12 个整数型态的局部变量
- 不得使用 long 或位操作,将 2 个整数型态变量存在 1 个变量中
- 不得使用递归
- 不得修改矩阵 A ,但可以修改矩阵 B
- 不得自定义矩阵或使用 对变量动态配置内存空间`malloc`
缓存参数
- 缓存取大小 1KB
- 采用直映射(E=1)
- Block 大小为 32 Byte(b=5)
- Set 共 32 组(s=5)
Eviction 的策略
- 矩阵 A & B 的第一行在 cache 中为同一组
- 对角线元素互相 evict
测试矩阵大小及分数
- 32 x 32: cache miss < 300 满分
- 64 x 64: cache miss < 1300 满分
- 61 x 67: cache miss < 2000 满分
**分析:**
在该实验中,缓存采用的是直接映射高速缓存,s = 5,b = 5,E = 1。对于该缓存,总共存在32个组,每个组共32个字节,可以装入8个int型变量,是非常有限的缓存,矩阵大小>cache大小。
主要需要解决以下两个问题:
* 直接映射缓存所带来的冲突不命中。观察程序中矩阵存储的位置即可以发现,矩阵A和矩阵B的同一行实际上被映射到了同一个缓存组。当进行对角线的引用时,一定会发生缓存的冲突不命中。需要仔细地处理对角线上的元素。
* 所需优化的矩阵的总大小超出了缓存的总大小。必然导致程序的访存效率低下。
为了解决第一个问题,我们需要仔细地考虑对于矩阵访问顺序;第二个问题,采用矩阵的分块(Blocking)方法降低miss
### 32 * 32
缓存一个块的大小为 32 Bytes,可放入 8 个整数类型,又整个缓存有 32 组,代表缓存一次可以存放 32 x 8 = 256 个连续位置的整数。 对于32 x 32的矩阵来说,等于每8列(256/32)就会发生冲突,因此理想的分块大小应该为**8 x 8**
另外,因为假设为直接映射,每组都只有一行,等于说只要发生冲突一定有 eviction,代表我们必需尽可能降低行替换的次数。 作业特别说明对角线元素互相evict,我们画图观察转置对角线元素会发生什么情况,为了简化以4 x 4的状况来呈现
- T1: 第一次置换,都是 cache miss
- T2: 第二次置换,A 是 cache hit,但 B 矩阵第二行不在快取中为 cache miss
- T3: 第二次置换,为了将 B 矩阵第二行读进快取,必需将 A 矩阵第二行替换掉
- T4: 第三次置换,因为 T3 替换了 A 矩阵第二行,在 T4 又必需加载回来
从以上分析可以发现,快取在A &B**对角线**元素的那一行发生**冲突**,所以对角线元素的替换会产生2次的miss及eviction。
简单`8 * 8`分块:
```c
if(M == 32){
for (i = 0; i < N; i+=8) {
for (j = 0; j < M; j+=8) {
for(k = i ;k < i + 8 && k<N;k++){
for(l = j ; l < j + 8 && l < M;l++)
{
a0 = A[k][l];
B[l][k] = a0;
}
}
}
}
}
```
测试结果超过了300miss,原因是**对角线访问冲突问题**
#### 对角线访问冲突问题
矩阵A和矩阵B的同一行实际上被映射到了同一个cache block。当进行对角线的引用时,一定会发生缓存的冲突不命中。并且,由于A和B的元素时一个一个处理的,必定会造成反复多次的冲突不命中。(如下图A第一个元素读miss,B第一个元素存miss,A读第二个元素miss)
**解决方法:通过变量一次性读出A的一整行,再存入B**
```c
for (i = 0; i < N; i+=8) {
for (j = 0; j < M; j+=8) {
if(i == j){
for(k = i ;k < i + 8 && k<N;k++){
a0 = A[k][j];
a1 = A[k][j+1];
a2 = A[k][j+2];
a3 = A[k][j+3];
a4 = A[k][j+4];
a5 = A[k][j+5];
a6 = A[k][j+6];
a7 = A[k][j+7];
B[j][k] = a0;
B[j+1][k] = a1;
B[j+2][k] = a2;
B[j+3][k] = a3;
B[j+4][k] = a4;
B[j+5][k] = a5;
B[j+6][k] = a6;
B[j+7][k] = a7;
}
}
else{
for(k = i ;k < i + 8 && k<N;k++){
for(l = j ; l < j + 8 && l < M;l++)
B[l][k] = A[k][l];
}
}
}
}
```
### 64 * 64
方法:将8 * 8 块再分成4个4 * 4的块进一步处理
* 首先对左上角和右上角进行处理:
1. B左上角 = A左上角转置。B右上角=A右上角转置。
2. 我们最后只需要把这部分平移到B的左下角就好。
* 现在B左上角完成
1. 首先用四个变量存储A的左下角的一列。
2. 再用四个变量存储B的右上角的一行。
3. 把四个变量存储的A的左下角的一列移动到B右上角的一行
4. 把四个变量存储的B的右上角的一行平移到B左下角的一列
5. B的右下角=A的右下角转置
```c
for (i = 0; i < N; i += 8) {
for (j = 0; j < M; j += 8) {
for (k = i; k < i + 4; k++) {
a0 = A[k][j];
a1 = A[k][j + 1];
a2 = A[k][j + 2];
a3 = A[k][j + 3];
a4 = A[k][j + 4];
a5 = A[k][j + 5];
a6 = A[k][j + 6];
a7 = A[k][j + 7];
B[j][k] = a0;
B[j + 1][k] = a1;
B[j + 2][k] = a2;
B[j + 3][k] = a3;
B[j][k + 4] = a4;
B[j + 1][k + 4] = a5;
B[j + 2][k + 4] = a6;
B[j + 3][k + 4] = a7;
}
for (l = j + 4; l < j + 8; l++) {
a4 = A[i + 4][l - 4]; // A left-down col
a5 = A[i + 5][l - 4];
a6 = A[i + 6][l - 4];
a7 = A[i + 7][l - 4];
a0 = B[l - 4][i + 4]; // B right-above line
a1 = B[l - 4][i + 5];
a2 = B[l - 4][i + 6];
a3 = B[l - 4][i + 7];
B[l - 4][i + 4] = a4; // set B right-above line
B[l - 4][i + 5] = a5;
B[l - 4][i + 6] = a6;
B[l - 4][i + 7] = a7;
B[l][i] = a0; // set B left-down col
B[l][i + 1] = a1;
B[l][i + 2] = a2;
B[l][i + 3] = a3;
B[l][i + 4] = A[i + 4][l];
B[l][i + 5] = A[i + 5][l];
B[l][i + 6] = A[i + 6][l];
B[l][i + 7] = A[i + 7][l];
}
}
}
```
### 61 * 67
对于不规则的矩阵,其核心依然是通过分块的方式优化Cache的读写效率。然而,要找到非常明显的规律来判断何时能填满一个Cache却并非易事。鉴于要求较为宽松,我们无需考虑处理对角线的情况,而是直接执行转置操作。只需尝试并更换不同的边长分块就能达到期望效果。实际上,采用16 × 16的分块规模就足以确保获得满分。

+ 0
- 12
LAB1/Driverhdrs.pm View File

@ -1,12 +0,0 @@
#
# This file contains configuration variables for drivers.
# It was generated by genhdrs.pl. Do not modify it.
#
package Driverhdrs;
$LAB = "datalab";
$SERVER_NAME = "changeme.ics.cs.cmu.edu";
$SERVER_PORT = 8081;
$COURSE_NAME = "csapp";
$AUTOGRADE_TIMEOUT = 0;
1;

+ 0
- 138
LAB1/Driverlib.pm View File

@ -1,138 +0,0 @@
###############################################################
# Driverlib.pm - A package of helper functions for Perl drivers
#
# Copyright (c) 2005 David R. O'Hallaron, All rights reserved.
###############################################################
package Driverlib;
use Socket;
# Autogenerated header file with lab-specific constants
use lib ".";
use Driverhdrs;
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(
driver_post
);
use strict;
#####
# Public functions
#
#
# driver_post - This is the routine that a driver calls when
# it needs to transmit an autoresult string to the result server.
#
sub driver_post ($$) {
my $userid = shift; # User id for this submission
my $result = shift; # Autoresult string
my $autograded = shift; # Set if called by an autograder
# Echo the autoresult string to stdout if the driver was called
# by an autograder
if ($autograded) {
print "\n";
print "AUTORESULT_STRING=$result\n";
return;
}
# If the driver was called with a specific userid, then submit
# the autoresult string to the result server over the Internet.
if ($userid) {
my $status = submitr($Driverhdrs::SERVER_NAME,
$Driverhdrs::SERVER_PORT,
$Driverhdrs::COURSE_NAME,
$userid,
$Driverhdrs::LAB,
$result);
# Print the status of the transfer
if (!($status =~ /OK/)) {
print "$status\n";
print "Did not send autoresult string to the result server.\n";
exit(1);
}
print "Success: Sent autoresult string for $userid to the result server.\n";
}
}
#####
# Private functions
#
#
# submitr - Sends an autoresult string to the result server
#
sub submitr ($$$$$$) {
my $hostname = shift;
my $port = shift;
my $course = shift;
my $userid = shift;
my $lab = shift;
my $result = shift;
my $internet_addr;
my $enc_result;
my $paddr;
my $line;
my $http_version;
my $errcode;
my $errmsg;
# Establish the connection to the server
socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
$internet_addr = inet_aton($hostname)
or die "Could not convert $hostname to an internet address: $!\n";
$paddr = sockaddr_in($port, $internet_addr);
connect(SERVER, $paddr)
or die "Could not connect to $hostname:$port:$!\n";
select((select(SERVER), $| = 1)[0]); # enable command buffering
# Send HTTP request to server
$enc_result = url_encode($result);
print SERVER "GET /$course/submitr.pl/?userid=$userid&lab=$lab&result=$enc_result&submit=submit HTTP/1.0\r\n\r\n";
# Get first HTTP response line
$line = <SERVER>;
chomp($line);
($http_version, $errcode, $errmsg) = split(/\s+/, $line);
if ($errcode != 200) {
return "Error: HTTP request failed with error $errcode: $errmsg";
}
# Read the remaining HTTP response header lines
while ($line = <SERVER>) {
if ($line =~ /^\r\n/) {
last;
}
}
# Read and return the response from the result server
$line = <SERVER>;
chomp($line);
close SERVER;
return $line;
}
#
# url_encode - Encode text string so it can be included in URI of GET request
#
sub url_encode ($) {
my $value = shift;
$value =~s/([^a-zA-Z0-9_\-.])/uc sprintf("%%%02x",ord($1))/eg;
return $value;
}
# Always end a module with a 1 so that it returns TRUE
1;

+ 0
- 33
LAB1/Makefile View File

@ -1,33 +0,0 @@
#
# Makefile that builds btest and other helper programs for the CS:APP data lab
#
CC = gcc
CFLAGS = -O -Wall -m32
LIBS = -lm
all: btest fshow ishow
btest: btest.c bits.c decl.c tests.c btest.h bits.h
$(CC) $(CFLAGS) $(LIBS) -o btest bits.c btest.c decl.c tests.c
fshow: fshow.c
$(CC) $(CFLAGS) -o fshow fshow.c
ishow: ishow.c
$(CC) $(CFLAGS) -o ishow ishow.c
# Forces a recompile. Used by the driver program.
btestexplicit:
$(CC) $(CFLAGS) $(LIBS) -o btest bits.c btest.c decl.c tests.c
clean:
rm -f *.o btest fshow ishow *~
oneshoot:
make clean; \
./dlc bits.c; \
make btest; \
./btest bits.c; \
make clean \

+ 0
- 140
LAB1/README View File

@ -1,140 +0,0 @@
***********************
The CS:APP Data Lab
Directions to Students
***********************
Your goal is to modify your copy of bits.c so that it passes all the
tests in btest without violating any of the coding guidelines.
*********
0. Files:
*********
Makefile - Makes btest, fshow, and ishow
README - This file
bits.c - The file you will be modifying and handing in
bits.h - Header file
btest.c - The main btest program
btest.h - Used to build btest
decl.c - Used to build btest
tests.c - Used to build btest
tests-header.c- Used to build btest
dlc* - Rule checking compiler binary (data lab compiler)
driver.pl* - Driver program that uses btest and dlc to autograde bits.c
Driverhdrs.pm - Header file for optional "Beat the Prof" contest
fshow.c - Utility for examining floating-point representations
ishow.c - Utility for examining integer representations
***********************************************************
1. Modifying bits.c and checking it for compliance with dlc
***********************************************************
IMPORTANT: Carefully read the instructions in the bits.c file before
you start. These give the coding rules that you will need to follow if
you want full credit.
Use the dlc compiler (./dlc) to automatically check your version of
bits.c for compliance with the coding guidelines:
unix> ./dlc bits.c
dlc returns silently if there are no problems with your code.
Otherwise it prints messages that flag any problems. Running dlc with
the -e switch:
unix> ./dlc -e bits.c
causes dlc to print counts of the number of operators used by each function.
Once you have a legal solution, you can test it for correctness using
the ./btest program.
*********************
2. Testing with btest
*********************
The Makefile in this directory compiles your version of bits.c with
additional code to create a program (or test harness) named btest.
To compile and run the btest program, type:
unix> make btest
unix> ./btest [optional cmd line args]
You will need to recompile btest each time you change your bits.c
program. When moving from one platform to another, you will want to
get rid of the old version of btest and generate a new one. Use the
commands:
unix> make clean
unix> make btest
Btest tests your code for correctness by running millions of test
cases on each function. It tests wide swaths around well known corner
cases such as Tmin and zero for integer puzzles, and zero, inf, and
the boundary between denormalized and normalized numbers for floating
point puzzles. When btest detects an error in one of your functions,
it prints out the test that failed, the incorrect result, and the
expected result, and then terminates the testing for that function.
Here are the command line options for btest:
unix> ./btest -h
Usage: ./btest [-hg] [-r <n>] [-f <name> [-1|-2|-3 <val>]*] [-T <time limit>]
-1 <val> Specify first function argument
-2 <val> Specify second function argument
-3 <val> Specify third function argument
-f <name> Test only the named function
-g Format output for autograding with no error messages
-h Print this message
-r <n> Give uniform weight of n for all problems
-T <lim> Set timeout limit to lim
Examples:
Test all functions for correctness and print out error messages:
unix> ./btest
Test all functions in a compact form with no error messages:
unix> ./btest -g
Test function foo for correctness:
unix> ./btest -f foo
Test function foo for correctness with specific arguments:
unix> ./btest -f foo -1 27 -2 0xf
Btest does not check your code for compliance with the coding
guidelines. Use dlc to do that.
*******************
3. Helper Programs
*******************
We have included the ishow and fshow programs to help you decipher
integer and floating point representations respectively. Each takes a
single decimal or hex number as an argument. To build them type:
unix> make
Example usages:
unix> ./ishow 0x27
Hex = 0x00000027, Signed = 39, Unsigned = 39
unix> ./ishow 27
Hex = 0x0000001b, Signed = 27, Unsigned = 27
unix> ./fshow 0x15213243
Floating point value 3.255334057e-26
Bit Representation 0x15213243, sign = 0, exponent = 0x2a, fraction = 0x213243
Normalized. +1.2593463659 X 2^(-85)
linux> ./fshow 15213243
Floating point value 2.131829405e-38
Bit Representation 0x00e822bb, sign = 0, exponent = 0x01, fraction = 0x6822bb
Normalized. +1.8135598898 X 2^(-126)

+ 0
- 388
LAB1/bits.c View File

@ -1,388 +0,0 @@
/*
* CS:APP Data Lab
*
* <Please put your name and userid here>
*
* bits.c - Source file with your solutions to the Lab.
* This is the file you will hand in to your instructor.
*
* WARNING: Do not include the <stdio.h> header; it confuses the dlc
* compiler. You can still use printf for debugging without including
* <stdio.h>, although you might get a compiler warning. In general,
* it's not good practice to ignore compiler warnings, but in this
* case it's OK.
*/
#if 0
/*
* Instructions to Students:
*
* STEP 1: Read the following instructions carefully.
*/
You will provide your solution to the Data Lab by
editing the collection of functions in this source file.
INTEGER CODING RULES:
Replace the "return" statement in each function with one
or more lines of C code that implements the function. Your code
must conform to the following style:
int Funct(arg1, arg2, ...) {
/* brief description of how your implementation works */
int var1 = Expr1;
...
int varM = ExprM;
varJ = ExprJ;
...
varN = ExprN;
return ExprR;
}
Each "Expr" is an expression using ONLY the following:
1. Integer constants 0 through 255 (0xFF), inclusive. You are
not allowed to use big constants such as 0xffffffff.
2. Function arguments and local variables (no global variables).
3. Unary integer operations ! ~
4. Binary integer operations & ^ | + << >>
Some of the problems restrict the set of allowed operators even further.
Each "Expr" may consist of multiple operators. You are not restricted to
one operator per line.
You are expressly forbidden to:
1. Use any control constructs such as if, do, while, for, switch, etc.
2. Define or use any macros.
3. Define any additional functions in this file.
4. Call any functions.
5. Use any other operations, such as &&, ||, -, or ?:
6. Use any form of casting.
7. Use any data type other than int. This implies that you
cannot use arrays, structs, or unions.
You may assume that your machine:
1. Uses 2s complement, 32-bit representations of integers.
2. Performs right shifts arithmetically.
3. Has unpredictable behavior when shifting if the shift amount
is less than 0 or greater than 31.
EXAMPLES OF ACCEPTABLE CODING STYLE:
/*
* pow2plus1 - returns 2^x + 1, where 0 <= x <= 31
*/
int pow2plus1(int x) {
/* exploit ability of shifts to compute powers of 2 */
return (1 << x) + 1;
}
/*
* pow2plus4 - returns 2^x + 4, where 0 <= x <= 31
*/
int pow2plus4(int x) {
/* exploit ability of shifts to compute powers of 2 */
int result = (1 << x);
result += 4;
return result;
}
FLOATING POINT CODING RULES
For the problems that require you to implement floating-point operations,
the coding rules are less strict. You are allowed to use looping and
conditional control. You are allowed to use both ints and unsigneds.
You can use arbitrary integer and unsigned constants. You can use any arithmetic,
logical, or comparison operations on int or unsigned data.
You are expressly forbidden to:
1. Define or use any macros.
2. Define any additional functions in this file.
3. Call any functions.
4. Use any form of casting.
5. Use any data type other than int or unsigned. This means that you
cannot use arrays, structs, or unions.
6. Use any floating point data types, operations, or constants.
NOTES:
1. Use the dlc (data lab checker) compiler (described in the handout) to
check the legality of your solutions.
2. Each function has a maximum number of operations (integer, logical,
or comparison) that you are allowed to use for your implementation
of the function. The max operator count is checked by dlc.
Note that assignment ('=') is not counted; you may use as many of
these as you want without penalty.
3. Use the btest test harness to check your functions for correctness.
4. Use the BDD checker to formally verify your functions
5. The maximum number of ops for each function is given in the
header comment for each function. If there are any inconsistencies
between the maximum ops in the writeup and in this file, consider
this file the authoritative source.
/*
* STEP 2: Modify the following functions according the coding rules.
*
* IMPORTANT. TO AVOID GRADING SURPRISES:
* 1. Use the dlc compiler to check that your solutions conform
* to the coding rules.
* 2. Use the BDD checker to formally verify that your solutions produce
* the correct answers.
*/
#endif
/* Copyright (C) 1991-2020 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* This header is separate from features.h so that the compiler can
include it implicitly at the start of every compilation. It must
not itself include <features.h> or any other header that includes
<features.h> because the implicit include comes before any feature
test macros that may be defined in a source file before it first
explicitly includes a system header. GCC knows the name of this
header in order to preinclude it. */
/* glibc's intent is to support the IEC 559 math functionality, real
and complex. If the GCC (4.9 and later) predefined macros
specifying compiler intent are available, use them to determine
whether the overall intent is to support these features; otherwise,
presume an older compiler has intent to support these features and
define these macros by default. */
/* wchar_t uses Unicode 10.0.0. Version 10.0 of the Unicode Standard is
synchronized with ISO/IEC 10646:2017, fifth edition, plus
the following additions from Amendment 1 to the fifth edition:
- 56 emoji characters
- 285 hentaigana
- 3 additional Zanabazar Square characters */
//1
/*
* bitXor - x^y using only ~ and &
* Example: bitXor(4, 5) = 1
* Legal ops: ~ &
* Max ops: 14
* Rating: 1
*/
int bitXor(int x, int y) {
return ~(~x&~y)&~(x&y);
}
/*
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmin(void) {
return 0x1<<31;
}
//2
/*
* isTmax - returns 1 if x is the maximum, two's complement number,
* and 0 otherwise
* Legal ops: ! ~ & ^ | +
* Max ops: 10
* Rating: 1
*/
int isTmax(int x) {
int i =x+1;
x = x+i;
x = ~x;
i = !i;
x = x+i;
return !x;
}
/*
* allOddBits - return 1 if all odd-numbered bits in word set to 1
* where bits are numbered from 0 (least significant) to 31 (most significant)
* Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 12
* Rating: 2
*/
int allOddBits(int x) {
int a = 0xaaaaaaaa;
return !((a&x)^a);
}
/*
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int negate(int x) {
return ~x+1;
}
//3
/*
* isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters '0' to '9')
* Example: isAsciiDigit(0x35) = 1.
* isAsciiDigit(0x3a) = 0.
* isAsciiDigit(0x05) = 0.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 15
* Rating: 3
*/
int isAsciiDigit(int x) {
//
//
int downstream = ~0x30+1;
int upstream = ~0x39;
int leftside = !((downstream+x)>>31); //0x300
int rightside = !!((upstream+x)>>31); //0x391
return leftside&rightside;
}
/*
* conditional - same as x ? y : z
* Example: conditional(2,4,5) = 4
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 16
* Rating: 3
*/
int conditional(int x, int y, int z) {
x = !!(x);
x = ~x+1;
return (x&y)|(~x&z);
}
/*
* isLessOrEqual - if x <= y then return 1, else return 0
* Example: isLessOrEqual(4,5) = 1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 24
* Rating: 3
*/
int isLessOrEqual(int x, int y) {
int tmp = ~y+1;
tmp = tmp+x-1;
tmp = tmp >> 31;//y大0y小等于1
return !!tmp;
}
//4
/*
* logicalNeg - implement the ! operator, using all of
* the legal operators except !
* Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
* Legal ops: ~ & ^ | + << >>
* Max ops: 12
* Rating: 4
*/
int logicalNeg(int x) {
return ((x|(~x+1))>>31)+1;
}
/* howManyBits - return the minimum number of bits required to represent x in
* two's complement
* Examples: howManyBits(12) = 5
* howManyBits(298) = 10
* howManyBits(-5) = 4
* howManyBits(0) = 1
* howManyBits(-1) = 1
* howManyBits(0x80000000) = 32
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 90
* Rating: 4
*/
int howManyBits(int x) {
x = ((~(x>>31))&x)|(x>>31&~x);//
//
int tf = !!(x>>16); //1601
int b16 = tf << 4; //16b16为16016
x = x>>b16; //b16位16161616
tf = !!(x>>8); //8,
int b8 = tf << 3;//8b8为808
x = x>>b8;
tf = !!(x>>4);
int b4 = tf << 2 ; //84,4b4为404
x = x>>b4;
tf = !!(x>>2);
int b2 = tf << 1; //42,2b2为202
x = x>>b2;
tf = !!(x>>1); //211b1为101
int b1 = tf << 0;
x = x>>b1;
int b0 = x;//,1,0
return b0+b1+b2+b4+b8+b16+1; //+11
}
//float
/*
* floatScale2 - Return bit-level equivalent of expression 2*f for
* floating point argument f.
* Both the argument and result are passed as unsigned int's, but
* they are to be interpreted as the bit-level representation of
* single-precision floating point values.
* When argument is NaN, return argument
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 30
* Rating: 4
*/
unsigned floatScale2(unsigned uf) {
unsigned sign = (0x80000000)&uf;
unsigned exp = (0x7f800000)&uf;
unsigned frac = (0x007fffff)&uf;
if(exp == 0x7f800000)
return uf; //exp全为255,frac全是0就是无穷NaNreturn
if(exp == 0x00000000){
if(frac == 0x00000000)
return uf; //exp全为0,frac全为000*2=0
return (frac<<1)|sign|exp;//exp全为0,frac不全为0frac第一位为1时exp变为非全0
}
return (exp+0x00800000)|sign|frac;
}
/*
* floatFloat2Int - Return bit-level equivalent of expression (int) f
* for floating point argument f.
* Argument is passed as unsigned int, but
* it is to be interpreted as the bit-level representation of a
* single-precision floating point value.
* Anything out of range (including NaN and infinity) should return
* 0x80000000u.
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 30
* Rating: 4
*/
int floatFloat2Int(unsigned uf) {
unsigned sign = ((0x80000000)&uf)>>31;
unsigned exp = ((0x7f800000)&uf)>>23;
unsigned frac = (0x007fffff)&uf;
unsigned base = (frac+0x00800000);//1
int bias = (exp-127)-23;//
if(sign==0)
sign = 1;
else
sign = -1;
if(exp == 255)
return 0x80000000u;//
if(exp == 0)
return 0;//
if(bias <=0){
if(bias<=-24)
bias = -24;
return sign*(base>>(-bias));
}
else{
if(bias>=9)
return 0x80000000u;
return sign*(base<<bias);
}
}
// #include "floatPower2.c"

+ 0
- 65
LAB1/bits.h View File

@ -1,65 +0,0 @@
/* Copyright (C) 1991-2020 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* This header is separate from features.h so that the compiler can
include it implicitly at the start of every compilation. It must
not itself include <features.h> or any other header that includes
<features.h> because the implicit include comes before any feature
test macros that may be defined in a source file before it first
explicitly includes a system header. GCC knows the name of this
header in order to preinclude it. */
/* glibc's intent is to support the IEC 559 math functionality, real
and complex. If the GCC (4.9 and later) predefined macros
specifying compiler intent are available, use them to determine
whether the overall intent is to support these features; otherwise,
presume an older compiler has intent to support these features and
define these macros by default. */
/* wchar_t uses Unicode 10.0.0. Version 10.0 of the Unicode Standard is
synchronized with ISO/IEC 10646:2017, fifth edition, plus
the following additions from Amendment 1 to the fifth edition:
- 56 emoji characters
- 285 hentaigana
- 3 additional Zanabazar Square characters */
//1
int bitXor(int, int);
int test_bitXor(int, int);
int tmin();
int test_tmin();
//2
int isTmax(int);
int test_isTmax(int);
int allOddBits();
int test_allOddBits();
int negate(int);
int test_negate(int);
//3
int isAsciiDigit(int);
int test_isAsciiDigit(int);
int conditional(int, int, int);
int test_conditional(int, int, int);
int isLessOrEqual(int, int);
int test_isLessOrEqual(int, int);
//4
int logicalNeg(int);
int test_logicalNeg(int);
int howManyBits(int);
int test_howManyBits(int);
//float
unsigned floatScale2(unsigned);
unsigned test_floatScale2(unsigned);
int floatFloat2Int(unsigned);
int test_floatFloat2Int(unsigned);
// #include "floatPower2.c"

+ 0
- 583
LAB1/btest.c View File

@ -1,583 +0,0 @@
/*
* CS:APP Data Lab
*
* btest.c - A test harness that checks a student's solution in bits.c
* for correctness.
*
* Copyright (c) 2001-2011, R. Bryant and D. O'Hallaron, All rights
* reserved. May not be used, modified, or copied without permission.
*
* This is an improved version of btest that tests large windows
* around zero and tmin and tmax for integer puzzles, and zero, norm,
* and denorm boundaries for floating point puzzles.
*
* Note: not 64-bit safe. Always compile with gcc -m32 option.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <signal.h>
#include <setjmp.h>
#include <math.h>
#include "btest.h"
/* Not declared in some stdlib.h files, so define here */
float strtof(const char *nptr, char **endptr);
/*************************
* Configuration Constants
*************************/
/* Handle infinite loops by setting upper limit on execution time, in
seconds */
#define TIMEOUT_LIMIT 10
/* For functions with a single argument, generate TEST_RANGE values
above and below the min and max test values, and above and below
zero. Functions with two or three args will use square and cube
roots of this value, respectively, to avoid combinatorial
explosion */
#define TEST_RANGE 500000
/* This defines the maximum size of any test value array. The
gen_vals() routine creates k test values for each value of
TEST_RANGE, thus MAX_TEST_VALS must be at least k*TEST_RANGE */
#define MAX_TEST_VALS 13*TEST_RANGE
/**********************************
* Globals defined in other modules
**********************************/
/* This characterizes the set of puzzles to test.
Defined in decl.c and generated from templates in ./puzzles dir */
extern test_rec test_set[];
/************************************************
* Write-once globals defined by command line args
************************************************/
/* Emit results in a format for autograding, without showing
and counter-examples */
static int grade = 0;
/* Time out after this number of seconds */
static int timeout_limit = TIMEOUT_LIMIT; /* -T */
/* If non-NULL, test only one function (-f) */
static char* test_fname = NULL;
/* Special case when only use fixed argument(s) (-1, -2, or -3) */
static int has_arg[3] = {0,0,0};
static unsigned argval[3] = {0,0,0};
/* Use fixed weight for rating, and if so, what should it be? (-r) */
static int global_rating = 0;
/******************
* Helper functions
******************/
/*
* Signal - installs a signal handler
*/
typedef void handler_t(int);
handler_t *Signal(int signum, handler_t *handler)
{
struct sigaction action, old_action;
action.sa_handler = handler;
sigemptyset(&action.sa_mask); /* block sigs of type being handled */
action.sa_flags = SA_RESTART; /* restart syscalls if possible */
if (sigaction(signum, &action, &old_action) < 0)
perror("Signal error");
return (old_action.sa_handler);
}
/*
* timeout_handler - SIGALARM hander
*/
sigjmp_buf envbuf;
void timeout_handler(int sig) {
siglongjmp(envbuf, 1);
}
/*
* random_val - Return random integer value between min and max
*/
static int random_val(int min, int max)
{
double weight = rand()/(double) RAND_MAX;
int result = min * (1-weight) + max * weight;
return result;
}
/*
* gen_vals - Generate the integer values we'll use to test a function
*/
static int gen_vals(int test_vals[], int min, int max, int test_range, int arg)
{
int i;
int test_count = 0;
/* Special case: If the user has specified a specific function
argument using the -1, -2, or -3 flags, then simply use this
argument and return */
if (has_arg[arg]) {
test_vals[0] = argval[arg];
return 1;
}
/*
* Special case: Generate test vals for floating point functions
* where the input argument is an unsigned bit-level
* representation of a float. For this case we want to test the
* regions around zero, the smallest normalized and largest
* denormalized numbers, one, and the largest normalized number,
* as well as inf and nan.
*/
if ((min == 1 && max == 1)) {
unsigned smallest_norm = 0x00800000;
unsigned one = 0x3f800000;
unsigned largest_norm = 0x7f000000;
unsigned inf = 0x7f800000;
unsigned nan = 0x7fc00000;
unsigned sign = 0x80000000;
/* Test range should be at most 1/2 the range of one exponent
value */
if (test_range > (1 << 23)) {
test_range = 1 << 23;
}
/* Functions where the input argument is an unsigned bit-level
representation of a float. The number of tests generated
inside this loop body is the value k referenced in the
comment for the global variable MAX_TEST_VALS. */
for (i = 0; i < test_range; i++) {
/* Denorms around zero */
test_vals[test_count++] = i;
test_vals[test_count++] = sign | i;
/* Region around norm to denorm transition */
test_vals[test_count++] = smallest_norm + i;
test_vals[test_count++] = smallest_norm - i;
test_vals[test_count++] = sign | (smallest_norm + i);
test_vals[test_count++] = sign | (smallest_norm - i);
/* Region around one */
test_vals[test_count++] = one + i;
test_vals[test_count++] = one - i;
test_vals[test_count++] = sign | (one + i);
test_vals[test_count++] = sign | (one - i);
/* Region below largest norm */
test_vals[test_count++] = largest_norm - i;
test_vals[test_count++] = sign | (largest_norm - i);
}
/* special vals */
test_vals[test_count++] = inf; /* inf */
test_vals[test_count++] = sign | inf; /* -inf */
test_vals[test_count++] = nan; /* nan */
test_vals[test_count++] = sign | nan; /* -nan */
return test_count;
}
/*
* Normal case: Generate test vals for integer functions
*/
/* If the range is small enough, then do exhaustively */
if (max - MAX_TEST_VALS <= min) {
for (i = min; i <= max; i++)
test_vals[test_count++] = i;
return test_count;
}
/* Otherwise, need to sample. Do so near the boundaries, around
zero, and for some random cases. */
for (i = 0; i < test_range; i++) {
/* Test around the boundaries */
test_vals[test_count++] = min + i;
test_vals[test_count++] = max - i;
/* If zero falls between min and max, then also test around zero */
if (i >= min && i <= max)
test_vals[test_count++] = i;
if (-i >= min && -i <= max)
test_vals[test_count++] = -i;
/* Random case between min and max */
test_vals[test_count++] = random_val(min, max);
}
return test_count;
}
/*
* test_0_arg - Test a function with zero arguments
*/
static int test_0_arg(funct_t f, funct_t ft, char *name)
{
int r = f();
int rt = ft();
int error = (r != rt);
if (error && !grade)
printf("ERROR: Test %s() failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, r, r, rt, rt);
return error;
}
/*
* test_1_arg - Test a function with one argument
*/
static int test_1_arg(funct_t f, funct_t ft, int arg1, char *name)
{
funct1_t f1 = (funct1_t) f;
funct1_t f1t = (funct1_t) ft;
int r, rt, error;
r = f1(arg1);
rt = f1t(arg1);
error = (r != rt);
if (error && !grade)
printf("ERROR: Test %s(%d[0x%x]) failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, arg1, arg1, r, r, rt, rt);
return error;
}
/*
* test_2_arg - Test a function with two arguments
*/
static int test_2_arg(funct_t f, funct_t ft, int arg1, int arg2, char *name)
{
funct2_t f2 = (funct2_t) f;
funct2_t f2t = (funct2_t) ft;
int r = f2(arg1, arg2);
int rt = f2t(arg1, arg2);
int error = (r != rt);
if (error && !grade)
printf("ERROR: Test %s(%d[0x%x],%d[0x%x]) failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, arg1, arg1, arg2, arg2, r, r, rt, rt);
return error;
}
/*
* test_3_arg - Test a function with three arguments
*/
static int test_3_arg(funct_t f, funct_t ft,
int arg1, int arg2, int arg3, char *name)
{
funct3_t f3 = (funct3_t) f;
funct3_t f3t = (funct3_t) ft;
int r = f3(arg1, arg2, arg3);
int rt = f3t(arg1, arg2, arg3);
int error = (r != rt);
if (error && !grade)
printf("ERROR: Test %s(%d[0x%x],%d[0x%x],%d[0x%x]) failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, arg1, arg1, arg2, arg2, arg3, arg3, r, r, rt, rt);
return error;
}
/*
* test_function - Test a function. Return number of errors
*/
static int test_function(test_ptr t) {
int test_counts[3]; /* number of test values for each arg */
int args = t->args; /* number of function arguments */
int arg_test_range[3]; /* test range for each argument */
int i, a1, a2, a3;
int errors = 0;
/* These are the test values for each arg. Declared with the
static attribute so that the array will be allocated in bss
rather than the stack */
static int arg_test_vals[3][MAX_TEST_VALS];
/* Sanity check on the number of args */
if (args < 0 || args > 3) {
printf("Configuration error: invalid number of args (%d) for function %s\n", args, t->name);
exit(1);
}
/* Assign range of argument test vals so as to conserve the total
number of tests, independent of the number of arguments */
if (args == 1) {
arg_test_range[0] = TEST_RANGE;
}
else if (args == 2) {
arg_test_range[0] = pow((double)TEST_RANGE, 0.5); /* sqrt */
arg_test_range[1] = arg_test_range[0];
}
else {
arg_test_range[0] = pow((double)TEST_RANGE, 0.333); /* cbrt */
arg_test_range[1] = arg_test_range[0];
arg_test_range[2] = arg_test_range[0];
}
/* Sanity check on the ranges */
if (arg_test_range[0] < 1)
arg_test_range[0] = 1;
if (arg_test_range[1] < 1)
arg_test_range[1] = 1;
if (arg_test_range[2] < 1)
arg_test_range[2] = 1;
/* Create a test set for each argument */
for (i = 0; i < args; i++) {
test_counts[i] = gen_vals(arg_test_vals[i],
t->arg_ranges[i][0], /* min */
t->arg_ranges[i][1], /* max */
arg_test_range[i],
i);
}
/* Handle timeouts in the test code */
if (timeout_limit > 0) {
int rc;
rc = sigsetjmp(envbuf, 1);
if (rc) {
/* control will reach here if there is a timeout */
errors = 1;
printf("ERROR: Test %s failed.\n Timed out after %d secs (probably infinite loop)\n", t->name, timeout_limit);
return errors;
}
alarm(timeout_limit);
}
/* Test function has no arguments */
if (args == 0) {
errors += test_0_arg(t->solution_funct, t->test_funct, t->name);
return errors;
}
/*
* Test function has at least one argument
*/
/* Iterate over the values for first argument */
for (a1 = 0; a1 < test_counts[0]; a1++) {
if (args == 1) {
errors += test_1_arg(t->solution_funct,
t->test_funct,
arg_test_vals[0][a1],
t->name);
/* Stop testing if there is an error */
if (errors)
return errors;
}
else {
/* if necessary, iterate over values for second argument */
for (a2 = 0; a2 < test_counts[1]; a2++) {
if (args == 2) {
errors += test_2_arg(t->solution_funct,
t->test_funct,
arg_test_vals[0][a1],
arg_test_vals[1][a2],
t->name);
/* Stop testing if there is an error */
if (errors)
return errors;
}
else {
/* if necessary, iterate over vals for third arg */
for (a3 = 0; a3 < test_counts[2]; a3++) {
errors += test_3_arg(t->solution_funct,
t->test_funct,
arg_test_vals[0][a1],
arg_test_vals[1][a2],
arg_test_vals[2][a3],
t->name);
/* Stop testing if there is an error */
if (errors)
return errors;
} /* a3 */
}
} /* a2 */
}
} /* a1 */
return errors;
}
/*
* run_tests - Run series of tests. Return number of errors
*/
static int run_tests()
{
int i;
int errors = 0;
double points = 0.0;
double max_points = 0.0;
printf("Score\tRating\tErrors\tFunction\n");
for (i = 0; test_set[i].solution_funct; i++) {
int terrors;
double tscore;
double tpoints;
if (!test_fname || strcmp(test_set[i].name,test_fname) == 0) {
int rating = global_rating ? global_rating : test_set[i].rating;
terrors = test_function(&test_set[i]);
errors += terrors;
tscore = terrors == 0 ? 1.0 : 0.0;
tpoints = rating * tscore;
points += tpoints;
max_points += rating;
if (grade || terrors < 1)
printf(" %.0f\t%d\t%d\t%s\n",
tpoints, rating, terrors, test_set[i].name);
}
}
printf("Total points: %.0f/%.0f\n", points, max_points);
return errors;
}
/*
* get_num_val - Extract hex/decimal/or float value from string
*/
static int get_num_val(char *sval, unsigned *valp) {
char *endp;
/* See if it's an integer or floating point */
int ishex = 0;
int isfloat = 0;
int i;
for (i = 0; sval[i]; i++) {
switch (sval[i]) {
case 'x':
case 'X':
ishex = 1;
break;
case 'e':
case 'E':
if (!ishex)
isfloat = 1;
break;
case '.':
isfloat = 1;
break;
default:
break;
}
}
if (isfloat) {
float fval = strtof(sval, &endp);
if (!*endp) {
*valp = *(unsigned *) &fval;
return 1;
}
return 0;
} else {
long long int llval = strtoll(sval, &endp, 0);
long long int upperbits = llval >> 31;
/* will give -1 for negative, 0 or 1 for positive */
if (!*valp && (upperbits == 0 || upperbits == -1 || upperbits == 1)) {
*valp = (unsigned) llval;
return 1;
}
return 0;
}
}
/*
* usage - Display usage info
*/
static void usage(char *cmd) {
printf("Usage: %s [-hg] [-r <n>] [-f <name> [-1|-2|-3 <val>]*] [-T <time limit>]\n", cmd);
printf(" -1 <val> Specify first function argument\n");
printf(" -2 <val> Specify second function argument\n");
printf(" -3 <val> Specify third function argument\n");
printf(" -f <name> Test only the named function\n");
printf(" -g Compact output for grading (with no error msgs)\n");
printf(" -h Print this message\n");
printf(" -r <n> Give uniform weight of n for all problems\n");
printf(" -T <lim> Set timeout limit to lim\n");
exit(1);
}
/**************
* Main routine
**************/
int main(int argc, char *argv[])
{
char c;
/* parse command line args */
while ((c = getopt(argc, argv, "hgf:r:T:1:2:3:")) != -1)
switch (c) {
case 'h': /* help */
usage(argv[0]);
break;
case 'g': /* grading option for autograder */
grade = 1;
break;
case 'f': /* test only one function */
test_fname = strdup(optarg);
break;
case 'r': /* set global rating for each problem */
global_rating = atoi(optarg);
if (global_rating < 0)
usage(argv[0]);
break;
case '1': /* Get first argument */
has_arg[0] = get_num_val(optarg, &argval[0]);
if (!has_arg[0]) {
printf("Bad argument '%s'\n", optarg);
exit(0);
}
break;
case '2': /* Get first argument */
has_arg[1] = get_num_val(optarg, &argval[1]);
if (!has_arg[1]) {
printf("Bad argument '%s'\n", optarg);
exit(0);
}
break;
case '3': /* Get first argument */
has_arg[2] = get_num_val(optarg, &argval[2]);
if (!has_arg[2]) {
printf("Bad argument '%s'\n", optarg);
exit(0);
}
break;
case 'T': /* Set timeout limit */
timeout_limit = atoi(optarg);
break;
default:
usage(argv[0]);
}
if (timeout_limit > 0) {
Signal(SIGALRM, timeout_handler);
}
/* test each function */
run_tests();
return 0;
}

+ 0
- 32
LAB1/btest.h View File

@ -1,32 +0,0 @@
/*
* CS:APP Data Lab
*/
/* Declare different function types */
typedef int (*funct_t) (void);
typedef int (*funct1_t)(int);
typedef int (*funct2_t)(int, int);
typedef int (*funct3_t)(int, int, int);
/* Combine all the information about a function and its tests as structure */
typedef struct {
char *name; /* String name */
funct_t solution_funct; /* Function */
funct_t test_funct; /* Test function */
int args; /* Number of function arguments */
char *ops; /* List of legal operators. Special case: "$" for floating point */
int op_limit; /* Max number of ops allowed in solution */
int rating; /* Problem rating (1 -- 4) */
int arg_ranges[3][2]; /* Argument ranges. Always defined for 3 args, even if */
/* the function takes fewer. Special case: First arg */
/* must be set to {1,1} for f.p. puzzles */
} test_rec, *test_ptr;
extern test_rec test_set[];

+ 0
- 86
LAB1/decl.c View File

@ -1,86 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define TMin INT_MIN
#define TMax INT_MAX
#include "btest.h"
#include "bits.h"
test_rec test_set[] = {
/* Copyright (C) 1991-2020 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* This header is separate from features.h so that the compiler can
include it implicitly at the start of every compilation. It must
not itself include <features.h> or any other header that includes
<features.h> because the implicit include comes before any feature
test macros that may be defined in a source file before it first
explicitly includes a system header. GCC knows the name of this
header in order to preinclude it. */
/* glibc's intent is to support the IEC 559 math functionality, real
and complex. If the GCC (4.9 and later) predefined macros
specifying compiler intent are available, use them to determine
whether the overall intent is to support these features; otherwise,
presume an older compiler has intent to support these features and
define these macros by default. */
/* wchar_t uses Unicode 10.0.0. Version 10.0 of the Unicode Standard is
synchronized with ISO/IEC 10646:2017, fifth edition, plus
the following additions from Amendment 1 to the fifth edition:
- 56 emoji characters
- 285 hentaigana
- 3 additional Zanabazar Square characters */
//1
{"bitXor", (funct_t) bitXor, (funct_t) test_bitXor, 2, "& ~", 14, 1,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
{"tmin", (funct_t) tmin, (funct_t) test_tmin, 0, "! ~ & ^ | + << >>", 4, 1,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
//2
{"isTmax", (funct_t) isTmax, (funct_t) test_isTmax, 1, "! ~ & ^ | +", 10, 1,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
{"allOddBits", (funct_t) allOddBits, (funct_t) test_allOddBits, 1,
"! ~ & ^ | + << >>", 12, 2,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
{"negate", (funct_t) negate, (funct_t) test_negate, 1,
"! ~ & ^ | + << >>", 5, 2,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
//3
{"isAsciiDigit", (funct_t) isAsciiDigit, (funct_t) test_isAsciiDigit, 1,
"! ~ & ^ | + << >>", 15, 3,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
{"conditional", (funct_t) conditional, (funct_t) test_conditional, 3, "! ~ & ^ | << >>", 16, 3,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
{"isLessOrEqual", (funct_t) isLessOrEqual, (funct_t) test_isLessOrEqual, 2,
"! ~ & ^ | + << >>", 24, 3,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
//4
{"logicalNeg", (funct_t) logicalNeg, (funct_t) test_logicalNeg, 1,
"~ & ^ | + << >>", 12, 4,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
{"howManyBits", (funct_t) howManyBits, (funct_t) test_howManyBits, 1, "! ~ & ^ | + << >>", 90, 4,
{{TMin, TMax},{TMin,TMax},{TMin,TMax}}},
//float
{"floatScale2", (funct_t) floatScale2, (funct_t) test_floatScale2, 1,
"$", 30, 4,
{{1, 1},{1,1},{1,1}}},
{"floatFloat2Int", (funct_t) floatFloat2Int, (funct_t) test_floatFloat2Int, 1,
"$", 30, 4,
{{1, 1},{1,1},{1,1}}},
// #include "floatPower2.c"
{"", NULL, NULL, 0, "", 0, 0,
{{0, 0},{0,0},{0,0}}}
};

+ 0
- 0
LAB1/dlc View File


+ 0
- 439
LAB1/driver.pl View File

@ -1,439 +0,0 @@
#!/usr/bin/perl
#######################################################################
# driver.pl - CS:APP Data Lab driver
#
# Copyright (c) 2004-2011, R. Bryant and D. O'Hallaron, All rights
# reserved. May not be used, modified, or copied without permission.
#
# Note: The driver can use either btest or the BDD checker to check
# puzzles for correctness. This version of the lab uses btest, which
# has been extended to do better testing of both integer and
# floating-point puzzles.
#
#######################################################################
use strict 'vars';
use Getopt::Std;
use lib ".";
use Driverlib;
# Set to 1 to use btest, 0 to use the BDD checker.
my $USE_BTEST = 1;
# Generic settings
$| = 1; # Flush stdout each time
umask(0077); # Files created by the user in tmp readable only by that user
$ENV{PATH} = "/usr/local/bin:/usr/bin:/bin";
#
# usage - print help message and terminate
#
sub usage {
printf STDERR "$_[0]\n";
printf STDERR "Usage: $0 [-h] [-u \"nickname\"]\n";
printf STDERR "Options:\n";
printf STDERR " -h Print this message.\n";
printf STDERR " -u \"nickname\" Send autoresult to server, using nickname on scoreboard)\n";
die "\n";
}
##############
# Main routine
##############
my $login = getlogin() || (getpwuid($<))[0] || "unknown";
my $tmpdir = "/var/tmp/datalab.$login.$$";
my $diemsg = "The files are in $tmpdir.";
my $driverfiles;
my $infile;
my $autograded;
my $status;
my $inpuzzles;
my $puzzlecnt;
my $line;
my $blank;
my $name;
my $c_points;
my $c_rating;
my $c_errors;
my $p_points;
my $p_rating;
my $p_errors;
my $total_c_points;
my $total_c_rating;
my $total_p_points;
my $total_p_rating;
my $tops;
my $tpoints;
my $trating;
my $foo;
my $name;
my $msg;
my $nickname;
my $autoresult;
my %puzzle_c_points;
my %puzzle_c_rating;
my %puzzle_c_errors;
my %puzzle_p_points;
my %puzzle_p_ops;
my %puzzle_p_maxops;
my %puzzle_number;
# Parse the command line arguments
no strict;
getopts('hu:f:A');
if ($opt_h) {
usage();
}
# The default input file is bits.c (change with -f)
$infile = "bits.c";
$nickname = "";
#####
# These are command line args that every driver must support
#
# Causes the driver to send an autoresult to the server on behalf of user
if ($opt_u) {
$nickname = $opt_u;
check_nickname($nickname);
}
# Hidden flag that indicates that the driver was invoked by an autograder
if ($opt_A) {
$autograded = $opt_A;
}
#####
# Drivers can also define an arbitary number of other command line args
#
# Optional hidden flag used by the autograder
if ($opt_f) {
$infile = $opt_f;
}
use strict 'vars';
################################################
# Compute the correctness and performance scores
################################################
# Make sure that an executable dlc (data lab compiler) exists
(-e "./dlc" and -x "./dlc")
or die "$0: ERROR: No executable dlc binary.\n";
# If using the bdd checker, then make sure it exists
if (!$USE_BTEST) {
(-e "./bddcheck/cbit/cbit" and -x "./bddcheck/cbit/cbit")
or die "$0: ERROR: No executable cbit binary.\n";
}
#
# Set up the contents of the scratch directory
#
system("mkdir $tmpdir") == 0
or die "$0: Could not make scratch directory $tmpdir.\n";
# Copy the student's work to the scratch directory
unless (system("cp $infile $tmpdir/bits.c") == 0) {
clean($tmpdir);
die "$0: Could not copy file $infile to scratch directory $tmpdir.\n";
}
# Copy the various autograding files to the scratch directory
if ($USE_BTEST) {
$driverfiles = "Makefile dlc btest.c decl.c tests.c btest.h bits.h";
unless (system("cp -r $driverfiles $tmpdir") == 0) {
clean($tmpdir);
die "$0: Could not copy autogradingfiles to $tmpdir.\n";
}
}
else {
$driverfiles = "dlc tests.c bddcheck";
unless (system("cp -r $driverfiles $tmpdir") == 0) {
clean($tmpdir);
die "$0: Could not copy support files to $tmpdir.\n";
}
}
# Change the current working directory to the scratch directory
unless (chdir($tmpdir)) {
clean($tmpdir);
die "$0: Could not change directory to $tmpdir.\n";
}
#
# Generate a zapped (for coding rules) version of bits.c. In this
# zapped version of bits.c, any functions with illegal operators are
# transformed to have empty function bodies.
#
print "1. Running './dlc -z' to identify coding rules violations.\n";
system("cp bits.c save-bits.c") == 0
or die "$0: ERROR: Could not create backup copy of bits.c. $diemsg\n";
system("./dlc -z -o zap-bits.c bits.c") == 0
or die "$0: ERROR: zapped bits.c did not compile. $diemsg\n";
#
# Run btest or BDD checker to determine correctness score
#
if ($USE_BTEST) {
print "\n2. Compiling and running './btest -g' to determine correctness score.\n";
system("cp zap-bits.c bits.c");
# Compile btest
system("make btestexplicit") == 0
or die "$0: Could not make btest in $tmpdir. $diemsg\n";
# Run btest
$status = system("./btest -g > btest-zapped.out 2>&1");
if ($status != 0) {
die "$0: ERROR: btest check failed. $diemsg\n";
}
}
else {
print "\n2. Running './bddcheck/check.pl -g' to determine correctness score.\n";
system("cp zap-bits.c bits.c");
$status = system("./bddcheck/check.pl -g > btest-zapped.out 2>&1");
if ($status != 0) {
die "$0: ERROR: BDD check failed. $diemsg\n";
}
}
#
# Run dlc to identify operator count violations.
#
print "\n3. Running './dlc -Z' to identify operator count violations.\n";
system("./dlc -Z -o Zap-bits.c save-bits.c") == 0
or die "$0: ERROR: dlc unable to generated Zapped bits.c file.\n";
#
# Run btest or the bdd checker to compute performance score
#
if ($USE_BTEST) {
print "\n4. Compiling and running './btest -g -r 2' to determine performance score.\n";
system("cp Zap-bits.c bits.c");
# Compile btest
system("make btestexplicit") == 0
or die "$0: Could not make btest in $tmpdir. $diemsg\n";
print "\n";
# Run btest
$status = system("./btest -g -r 2 > btest-Zapped.out 2>&1");
if ($status != 0) {
die "$0: ERROR: Zapped btest failed. $diemsg\n";
}
}
else {
print "\n4. Running './bddcheck/check.pl -g -r 2' to determine performance score.\n";
system("cp Zap-bits.c bits.c");
$status = system("./bddcheck/check.pl -g -r 2 > btest-Zapped.out 2>&1");
if ($status != 0) {
die "$0: ERROR: Zapped bdd checker failed. $diemsg\n";
}
}
#
# Run dlc to get the operator counts on the zapped input file
#
print "\n5. Running './dlc -e' to get operator count of each function.\n";
$status = system("./dlc -W1 -e zap-bits.c > dlc-opcount.out 2>&1");
if ($status != 0) {
die "$0: ERROR: bits.c did not compile. $diemsg\n";
}
#################################################################
# Collect the correctness and performance results for each puzzle
#################################################################
#
# Collect the correctness results
#
%puzzle_c_points = (); # Correctness score computed by btest
%puzzle_c_errors = (); # Correctness error discovered by btest
%puzzle_c_rating = (); # Correctness puzzle rating (max points)
$inpuzzles = 0; # Becomes true when we start reading puzzle results
$puzzlecnt = 0; # Each puzzle gets a unique number
$total_c_points = 0;
$total_c_rating = 0;
open(INFILE, "$tmpdir/btest-zapped.out")
or die "$0: ERROR: could not open input file $tmpdir/btest-zapped.out\n";
while ($line = <INFILE>) {
chomp($line);
# Notice that we're ready to read the puzzle scores
if ($line =~ /^Score/) {
$inpuzzles = 1;
next;
}
# Notice that we're through reading the puzzle scores
if ($line =~ /^Total/) {
$inpuzzles = 0;
next;
}
# Read and record a puzzle's name and score
if ($inpuzzles) {
($blank, $c_points, $c_rating, $c_errors, $name) = split(/\s+/, $line);
$puzzle_c_points{$name} = $c_points;
$puzzle_c_errors{$name} = $c_errors;
$puzzle_c_rating{$name} = $c_rating;
$puzzle_number{$name} = $puzzlecnt++;
$total_c_points += $c_points;
$total_c_rating += $c_rating;
}
}
close(INFILE);
#
# Collect the performance results
#
%puzzle_p_points = (); # Performance points
$inpuzzles = 0; # Becomes true when we start reading puzzle results
$total_p_points = 0;
$total_p_rating = 0;
open(INFILE, "$tmpdir/btest-Zapped.out")
or die "$0: ERROR: could not open input file $tmpdir/btest-Zapped.out\n";
while ($line = <INFILE>) {
chomp($line);
# Notice that we're ready to read the puzzle scores
if ($line =~ /^Score/) {
$inpuzzles = 1;
next;
}
# Notice that we're through reading the puzzle scores
if ($line =~ /^Total/) {
$inpuzzles = 0;
next;
}
# Read and record a puzzle's name and score
if ($inpuzzles) {
($blank, $p_points, $p_rating, $p_errors, $name) = split(/\s+/, $line);
$puzzle_p_points{$name} = $p_points;
$total_p_points += $p_points;
$total_p_rating += $p_rating;
}
}
close(INFILE);
#
# Collect the operator counts generated by dlc
#
open(INFILE, "$tmpdir/dlc-opcount.out")
or die "$0: ERROR: could not open input file $tmpdir/dlc-opcount.out\n";
$tops = 0;
while ($line = <INFILE>) {
chomp($line);
if ($line =~ /(\d+) operators/) {
($foo, $foo, $foo, $name, $msg) = split(/:/, $line);
$puzzle_p_ops{$name} = $1;
$tops += $1;
}
}
close(INFILE);
#
# Print a table of results sorted by puzzle number
#
print "\n";
printf("%s\t%s\n", "Correctness Results", "Perf Results");
printf("%s\t%s\t%s\t%s\t%s\t%s\n", "Points", "Rating", "Errors",
"Points", "Ops", "Puzzle");
foreach $name (sort {$puzzle_number{$a} <=> $puzzle_number{$b}}
keys %puzzle_number) {
printf("%d\t%d\t%d\t%d\t%d\t\%s\n",
$puzzle_c_points{$name},
$puzzle_c_rating{$name},
$puzzle_c_errors{$name},
$puzzle_p_points{$name},
$puzzle_p_ops{$name},
$name);
}
$tpoints = $total_c_points + $total_p_points;
$trating = $total_c_rating + $total_p_rating;
print "\nScore = $tpoints/$trating [$total_c_points/$total_c_rating Corr + $total_p_points/$total_p_rating Perf] ($tops total operators)\n";
#
# Optionally send the autoresult to the contest server if the driver
# was called with the -u command line flag.
#
if ($nickname) {
# Generate the autoresult
$autoresult = "$tpoints|$total_c_points|$total_p_points|$tops";
foreach $name (sort {$puzzle_number{$a} <=> $puzzle_number{$b}}
keys %puzzle_number) {
$autoresult .= " |$name:$puzzle_c_points{$name}:$puzzle_c_rating{$name}:$puzzle_p_points{$name}:$puzzle_p_ops{$name}";
}
# Post the autoresult to the server. The Linux login id is
# concatenated with the user-supplied nickname for some (very) loose
# authentication of submissions.
&Driverlib::driver_post("$login:$nickname", $autoresult, $autograded);
}
# Clean up and exit
clean ($tmpdir);
exit;
##################
# Helper functions
#
#
# check_nickname - Check a nickname for legality
#
sub check_nickname {
my $nickname = shift;
# Nicknames can't be empty
if (length($nickname) < 1) {
die "$0: Error: Empty nickname.\n";
}
# Nicknames can't be too long
if (length($nickname) > 35) {
die "$0: Error: Nickname exceeds 35 characters.\n";
}
# Nicknames can have restricted set of metacharacters (e.g., no #
# HTML tags)
if (!($nickname =~ /^[_-\w.,'@ ]+$/)) {
die "$0: Error: Illegal character in nickname. Only alphanumerics, apostrophes, commas, periods, dashes, underscores, and ampersands are allowed.\n";
}
# Nicknames can't be all whitespace
if ($nickname =~ /^\s*$/) {
die "$0: Error: Nickname is all whitespace.\n";
}
}
#
# clean - remove the scratch directory
#
sub clean {
my $tmpdir = shift;
system("rm -rf $tmpdir");
}

+ 0
- 151
LAB1/fshow.c View File

@ -1,151 +0,0 @@
/* Display structure of floating-point numbers */
#include <stdio.h>
#include <stdlib.h>
float strtof(const char *nptr, char **endptr);
#define FLOAT_SIZE 32
#define FRAC_SIZE 23
#define EXP_SIZE 8
#define BIAS ((1<<(EXP_SIZE-1))-1)
#define FRAC_MASK ((1<<FRAC_SIZE)-1)
#define EXP_MASK ((1<<EXP_SIZE)-1)
/* Floating point helpers */
unsigned f2u(float f)
{
union {
unsigned u;
float f;
} v;
v.u = 0;
v.f = f;
return v.u;
}
static float u2f(unsigned u)
{
union {
unsigned u;
float f;
} v;
v.u = u;
return v.f;
}
/* Get exponent */
unsigned get_exp(unsigned uf)
{
return (uf>>FRAC_SIZE) & EXP_MASK;
}
/* Get fraction */
unsigned get_frac(unsigned uf)
{
return uf & FRAC_MASK;
}
/* Get sign */
unsigned get_sign(unsigned uf)
{
return (uf>>(FLOAT_SIZE-1)) & 0x1;
}
void show_float(unsigned uf)
{
float f = u2f(uf);
unsigned exp = get_exp(uf);
unsigned frac = get_frac(uf);
unsigned sign = get_sign(uf);
printf("\nFloating point value %.10g\n", f);
printf("Bit Representation 0x%.8x, sign = %x, exponent = 0x%.2x, fraction = 0x%.6x\n",
uf, sign, exp, frac);
if (exp == EXP_MASK) {
if (frac == 0) {
printf("%cInfinity\n", sign ? '-' : '+');
} else
printf("Not-A-Number\n");
} else {
int denorm = (exp == 0);
int uexp = denorm ? 1-BIAS : exp - BIAS;
int mantissa = denorm ? frac : frac + (1<<FRAC_SIZE);
float fman = (float) mantissa / (float) (1<<FRAC_SIZE);
printf("%s. %c%.10f X 2^(%d)\n",
denorm ? "Denormalized" : "Normalized",
sign ? '-' : '+',
fman, uexp);
}
}
/* Extract hex/decimal/or float value from string */
static int get_num_val(char *sval, unsigned *valp) {
char *endp;
/* See if it's an integer or floating point */
int ishex = 0;
int isfloat = 0;
int i;
for (i = 0; sval[i]; i++) {
switch (sval[i]) {
case 'x':
case 'X':
ishex = 1;
break;
case 'e':
case 'E':
if (!ishex)
isfloat = 1;
break;
case '.':
isfloat = 1;
break;
default:
break;
}
}
if (isfloat) {
float fval = strtof(sval, &endp);
if (!*endp) {
*valp = *(unsigned *) &fval;
return 1;
}
return 0;
} else {
long long int llval = strtoll(sval, &endp, 0);
long long int upperbits = llval >> 31;
/* will give -1 for negative, 0 or 1 for positive */
if (valp && (upperbits == 0 || upperbits == -1 || upperbits == 1)) {
*valp = (unsigned) llval;
return 1;
}
return 0;
}
}
void usage(char *fname) {
printf("Usage: %s val1 val2 ...\n", fname);
printf("Values may be given as hex patterns or as floating point numbers\n");
exit(0);
}
int main(int argc, char *argv[])
{
int i;
unsigned uf;
if (argc < 2)
usage(argv[0]);
for (i = 1; i < argc; i++) {
char *sval = argv[i];
if (get_num_val(sval, &uf)) {
show_float(uf);
} else {
printf("Invalid 32-bit number: '%s'\n", sval);
usage(argv[0]);
}
}
return 0;
}

+ 0
- 75
LAB1/ishow.c View File

@ -1,75 +0,0 @@
/* Display value of fixed point numbers */
#include <stdlib.h>
#include <stdio.h>
/* Extract hex/decimal/or float value from string */
static int get_num_val(char *sval, unsigned *valp) {
char *endp;
/* See if it's an integer or floating point */
int ishex = 0;
int isfloat = 0;
int i;
for (i = 0; sval[i]; i++) {
switch (sval[i]) {
case 'x':
case 'X':
ishex = 1;
break;
case 'e':
case 'E':
if (!ishex)
isfloat = 1;
break;
case '.':
isfloat = 1;
break;
default:
break;
}
}
if (isfloat) {
return 0; /* Not supposed to have a float here */
} else {
long long int llval = strtoll(sval, &endp, 0);
long long int upperbits = llval >> 31;
/* will give -1 for negative, 0 or 1 for positive */
if (valp && (upperbits == 0 || upperbits == -1 || upperbits == 1)) {
*valp = (unsigned) llval;
return 1;
}
return 0;
}
}
void show_int(unsigned uf)
{
printf("Hex = 0x%.8x,\tSigned = %d,\tUnsigned = %u\n",
uf, (int) uf, uf);
}
void usage(char *fname) {
printf("Usage: %s val1 val2 ...\n", fname);
printf("Values may be given in hex or decimal\n");
exit(0);
}
int main(int argc, char *argv[])
{
int i;
unsigned uf;
if (argc < 2)
usage(argv[0]);
for (i = 1; i < argc; i++) {
char *sval = argv[i];
if (get_num_val(sval, &uf)) {
show_int(uf);
} else {
printf("Cannot convert '%s' to 32-bit number\n", sval);
}
}
return 0;
}

+ 0
- 124
LAB1/tests.c View File

@ -1,124 +0,0 @@
/* Testing Code */
#include <limits.h>
#include <math.h>
/* Routines used by floation point test code */
/* Convert from bit level representation to floating point number */
float u2f(unsigned u) {
union {
unsigned u;
float f;
} a;
a.u = u;
return a.f;
}
/* Convert from floating point number to bit-level representation */
unsigned f2u(float f) {
union {
unsigned u;
float f;
} a;
a.f = f;
return a.u;
}
/* Copyright (C) 1991-2020 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* This header is separate from features.h so that the compiler can
include it implicitly at the start of every compilation. It must
not itself include <features.h> or any other header that includes
<features.h> because the implicit include comes before any feature
test macros that may be defined in a source file before it first
explicitly includes a system header. GCC knows the name of this
header in order to preinclude it. */
/* glibc's intent is to support the IEC 559 math functionality, real
and complex. If the GCC (4.9 and later) predefined macros
specifying compiler intent are available, use them to determine
whether the overall intent is to support these features; otherwise,
presume an older compiler has intent to support these features and
define these macros by default. */
/* wchar_t uses Unicode 10.0.0. Version 10.0 of the Unicode Standard is
synchronized with ISO/IEC 10646:2017, fifth edition, plus
the following additions from Amendment 1 to the fifth edition:
- 56 emoji characters
- 285 hentaigana
- 3 additional Zanabazar Square characters */
//1
int test_bitXor(int x, int y)
{
return x^y;
}
int test_tmin(void) {
return 0x80000000;
}
//2
int test_isTmax(int x) {
return x == 0x7FFFFFFF;
}
int test_allOddBits(int x) {
int i;
for (i = 1; i < 32; i+=2)
if ((x & (1<<i)) == 0)
return 0;
return 1;
}
int test_negate(int x) {
return -x;
}
//3
int test_isAsciiDigit(int x) {
return (0x30 <= x) && (x <= 0x39);
}
int test_conditional(int x, int y, int z)
{
return x?y:z;
}
int test_isLessOrEqual(int x, int y)
{
return x <= y;
}
//4
int test_logicalNeg(int x)
{
return !x;
}
int test_howManyBits(int x) {
unsigned int a, cnt;
x = x<0 ? -x-1 : x;
a = (unsigned int)x;
for (cnt=0; a; a>>=1, cnt++)
;
return (int)(cnt + 1);
}
//float
unsigned test_floatScale2(unsigned uf) {
float f = u2f(uf);
float tf = 2*f;
if (isnan(f))
return uf;
else
return f2u(tf);
}
int test_floatFloat2Int(unsigned uf) {
float f = u2f(uf);
int x = (int) f;
return x;
}
// #include "floatPower2.c"

+ 0
- 21
LICENSE View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 AquaOH
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

+ 33
- 0
Makefile View File

@ -0,0 +1,33 @@
#
# Student makefile for Cache Lab
# Note: requires a 64-bit x86-64 system
#
CC = gcc
CFLAGS = -g -Wall -Werror -std=c99 -m64
all: csim test-trans tracegen
# Generate a handin tar file each time you compile
-tar -cvf ${USER}-handin.tar csim.c trans.c
csim: csim.c cachelab.c cachelab.h
$(CC) $(CFLAGS) -o csim csim.c cachelab.c -lm
test-trans: test-trans.c trans.o cachelab.c cachelab.h
$(CC) $(CFLAGS) -o test-trans test-trans.c cachelab.c trans.o
tracegen: tracegen.c trans.o cachelab.c
$(CC) $(CFLAGS) -O0 -o tracegen tracegen.c trans.o cachelab.c
trans.o: trans.c
$(CC) $(CFLAGS) -O0 -c trans.c
#
# Clean the src dirctory
#
clean:
rm -rf *.o
rm -f *.tar
rm -f csim
rm -f test-trans tracegen
rm -f trace.all trace.f*
rm -f .csim_results .marker

+ 27
- 0
README View File

@ -0,0 +1,27 @@
This is the handout directory for the CS:APP Cache Lab.
************************
Running the autograders:
************************
Before running the autograders, compile your code:
linux> make
Check the correctness of your simulator:
linux> ./test-csim
******
Files:
******
# You will modifying and handing in the file
csim.c Your cache simulator
# Tools for evaluating your simulator and transpose function
Makefile Builds the simulator and tools
README This file
cachelab.c Required helper functions
cachelab.h Required header file
csim-ref* The executable reference cache simulator
test-csim* Tests your cache simulator
traces/ Trace files used by test-csim.c

+ 0
- 35
README.md View File

@ -1,35 +0,0 @@
### All
A CSAPP LAB
### 2023/10/7 Update:
1. Create A Repo
2. Finish bitXor
3. Finish tmin
### 2023/10/8 Update:
1. Finish isTmax
2. Finish allOddBits
3. Finish negate
4. Finish isAsciiDigit
5. Finish isLessOrEqual
6. Finish logicalNeg
7. Update Makefile
### 2023/10/9 Update:
1. Finish howManyBits
### 2023/10/9 Update:
1. Finish floatScale2
2. Finish floatFloat2Int
3. Congratulations!Finish datalab!

BIN
aqua-handin.tar View File


+ 83
- 0
cachelab.c View File

@ -0,0 +1,83 @@
/*
* cachelab.c - Cache Lab helper functions
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "cachelab.h"
#include <time.h>
trans_func_t func_list[MAX_TRANS_FUNCS];
int func_counter = 0;
/*
* printSummary - Summarize the cache simulation statistics. Student cache simulators
* must call this function in order to be properly autograded.
*/
void printSummary(int hits, int misses, int evictions)
{
printf("hits:%d misses:%d evictions:%d\n", hits, misses, evictions);
FILE* output_fp = fopen(".csim_results", "w");
assert(output_fp);
fprintf(output_fp, "%d %d %d\n", hits, misses, evictions);
fclose(output_fp);
}
/*
* initMatrix - Initialize the given matrix
*/
void initMatrix(int M, int N, int A[N][M], int B[M][N])
{
int i, j;
srand(time(NULL));
for (i = 0; i < N; i++){
for (j = 0; j < M; j++){
// A[i][j] = i+j; /* The matrix created this way is symmetric */
A[i][j]=rand();
B[j][i]=rand();
}
}
}
void randMatrix(int M, int N, int A[N][M]) {
int i, j;
srand(time(NULL));
for (i = 0; i < N; i++){
for (j = 0; j < M; j++){
// A[i][j] = i+j; /* The matrix created this way is symmetric */
A[i][j]=rand();
}
}
}
/*
* correctTrans - baseline transpose function used to evaluate correctness
*/
void correctTrans(int M, int N, int A[N][M], int B[M][N])
{
int i, j, tmp;
for (i = 0; i < N; i++){
for (j = 0; j < M; j++){
tmp = A[i][j];
B[j][i] = tmp;
}
}
}
/*
* registerTransFunction - Add the given trans function into your list
* of functions to be tested
*/
void registerTransFunction(void (*trans)(int M, int N, int[N][M], int[M][N]),
char* desc)
{
func_list[func_counter].func_ptr = trans;
func_list[func_counter].description = desc;
func_list[func_counter].correct = 0;
func_list[func_counter].num_hits = 0;
func_list[func_counter].num_misses = 0;
func_list[func_counter].num_evictions =0;
func_counter++;
}

+ 37
- 0
cachelab.h View File

@ -0,0 +1,37 @@
/*
* cachelab.h - Prototypes for Cache Lab helper functions
*/
#ifndef CACHELAB_TOOLS_H
#define CACHELAB_TOOLS_H
#define MAX_TRANS_FUNCS 100
typedef struct trans_func{
void (*func_ptr)(int M,int N,int[N][M],int[M][N]);
char* description;
char correct;
unsigned int num_hits;
unsigned int num_misses;
unsigned int num_evictions;
} trans_func_t;
/*
* printSummary - This function provides a standard way for your cache
* simulator * to display its final hit and miss statistics
*/
void printSummary(int hits, /* number of hits */
int misses, /* number of misses */
int evictions); /* number of evictions */
/* Fill the matrix with data */
void initMatrix(int M, int N, int A[N][M], int B[M][N]);
/* The baseline trans function that produces correct results. */
void correctTrans(int M, int N, int A[N][M], int B[M][N]);
/* Add the given function to the function list */
void registerTransFunction(
void (*trans)(int M,int N,int[N][M],int[M][N]), char* desc);
#endif /* CACHELAB_TOOLS_H */

BIN
csim View File


BIN
csim-ref View File


+ 152
- 0
csim.c View File

@ -0,0 +1,152 @@
#include "cachelab.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
typedef struct
{
unsigned tag;
unsigned usedtime;
} block;
block *cache;
int getOpt(int argc,char **argv,int *s,int *E,int *b,int *verbose,char *tracefile);
void printHelpMenu();
void cacheStateOut(char op,int type);
void find(char op,unsigned addr,unsigned size,int time);
int hit,miss,eviction;
int verbose;
int s,E,b;
int main(int argc,char **argv)
{
FILE *fp;
char tracefile[100];
char op[10];
unsigned addr,size;
int t;
getOpt(argc,argv,&s,&E,&b,&verbose,tracefile); // get option
if(s<0||E<0||b<1){
printf("Invalid Cache parameter\n\n");
exit(1);
}
cache = (block *)malloc(sizeof(block)* E<<s);
memset(cache,0,sizeof(block)* E<<s);
fp = fopen (tracefile,"r");
while(fscanf(fp,"%s%x,%d\n",op,&addr,&size) > 0){
if(verbose)
printf("%s %x,%d ",op,addr,size);
switch(op[0]){
case 'M': hit++;
case 'L':
case 'S': find(op[0],addr,size,++t);
}
}
printSummary(hit, miss, eviction);
free(cache);
fclose(fp);
return 0;
}
void find(char op, unsigned addr,unsigned size,int time){
int i;
unsigned tag = addr >>b >>s ;
unsigned set_index = addr >> b &((1<<s) -1);
block *cache_set = cache + E * set_index ; // set address
block *eviction_block = cache_set; // LRU cacheline
for(i = 0;i<E;i++){
if(cache_set[i].usedtime>0 && cache_set[i].tag ==tag){ //hit
cache_set[i].usedtime = time;
hit++;
if(verbose) cacheStateOut(op,0);
return;
}
else if(!cache_set[i].usedtime){ // empty block
miss++;
cache_set[i].tag = tag;
cache_set[i].usedtime = time;
if(verbose) cacheStateOut(op,1);
return;
}
else if(cache_set[i].usedtime < eviction_block->usedtime) // !=tag , current block is older
eviction_block = cache_set+i;
}
miss ++;
eviction ++;
eviction_block->tag = tag; // replace sacrifice cacheline
eviction_block->usedtime = time;
if(verbose) cacheStateOut(op,2);
return ;
}
int getOpt(int argc,char **argv,int *s,int *E,int *b,int *verbose,char *tracefile)
{
int oc;
while((oc=getopt(argc,argv,"hvs:E:b:t:"))!=-1){
switch(oc){
case 'h': printHelpMenu();break; // print usage
case 'v': *verbose=1;break;
case 's': *s = atoi(optarg);break;
case 'E': *E = atoi(optarg);break;
case 'b': *b = atoi(optarg);break;
case 't': strcpy(tracefile,optarg);break;
default : printf("input error\n");break;
}
}
return 0;
}
void cacheStateOut(char op,int type){
switch(type){
case 0: //hit
switch(op){
case 'L':
case 'S':printf("hit\n");break;
case 'M':printf("hit hit\n");break;
}break;
case 1: //miss
switch(op){
case 'L':
case 'S':printf("miss\n");break;
case 'M':printf("miss hit\n");break;
}
case 2: //eviction
switch(op){
case 'L':
case 'S':printf("miss eviction\n");break;
case 'M':printf("miss eviction hit\n");break;
}break;
}
}
void printHelpMenu(){
printf("Usage: ./csim [-hv] -s <num> -E <num> -b <num> -t <file>\n");
printf("Options:\n");
printf("-h Print this help message.\n");
printf("-v Optional verbose flag.\n");
printf("-s <num> Number of set index bits.\n");
printf("-E <num> Number of lines per set.\n");
printf("-b <num> Number of block offset bits.\n");
printf("-t <file> Trace file.\n\n\n");
printf("Examples:\n");
printf("linux> ./csim -s 4 -E 1 -b 4 -t traces/yi.trace\n");
printf("linux> ./csim -v -s 8 -E 2 -b 4 -t traces/yi.trace\n");
}
void checkOptarg(char *curOptarg){
if(curOptarg[0]=='-'){
printf("./csim :Missing required command line argument\n");
printHelpMenu();
exit(0);
}
}

BIN
test-csim View File


BIN
test-trans View File


+ 261
- 0
test-trans.c View File

@ -0,0 +1,261 @@
/*
* test-trans.c - Checks the correctness and performance of all of the
* student's transpose functions and records the results for their
* official submitted version as well.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <getopt.h>
#include <sys/types.h>
#include "cachelab.h"
#include <sys/wait.h> // fir WEXITSTATUS
#include <limits.h> // for INT_MAX
/* Maximum array dimension */
#define MAXN 256
/* The description string for the transpose_submit() function that the
student submits for credit */
#define SUBMIT_DESCRIPTION "Transpose submission"
/* External function defined in trans.c */
extern void registerFunctions();
/* External variables defined in cachelab-tools.c */
extern trans_func_t func_list[MAX_TRANS_FUNCS];
extern int func_counter;
/* Globals set on the command line */
static int M = 0;
static int N = 0;
/* The correctness and performance for the submitted transpose function */
struct results {
int funcid;
int correct;
int misses;
};
static struct results results = {-1, 0, INT_MAX};
/*
* eval_perf - Evaluate the performance of the registered transpose functions
*/
void eval_perf(unsigned int s, unsigned int E, unsigned int b)
{
int i,flag;
unsigned int len, hits, misses, evictions;
unsigned long long int marker_start, marker_end, addr;
char buf[1000], cmd[255];
char filename[128];
registerFunctions();
/* Open the complete trace file */
FILE* full_trace_fp;
FILE* part_trace_fp;
/* Evaluate the performance of each registered transpose function */
for (i=0; i<func_counter; i++) {
if (strcmp(func_list[i].description, SUBMIT_DESCRIPTION) == 0 )
results.funcid = i; /* remember which function is the submission */
printf("\nFunction %d (%d total)\nStep 1: Validating and generating memory traces\n",i,func_counter);
/* Use valgrind to generate the trace */
sprintf(cmd, "valgrind --tool=lackey --trace-mem=yes --log-fd=1 -v ./tracegen -M %d -N %d -F %d > trace.tmp", M, N,i);
flag=WEXITSTATUS(system(cmd));
if (0!=flag) {
printf("Validation error at function %d! Run ./tracegen -M %d -N %d -F %d for details.\nSkipping performance evaluation for this function.\n",flag-1,M,N,i);
continue;
}
/* Get the start and end marker addresses */
FILE* marker_fp = fopen(".marker", "r");
assert(marker_fp);
fscanf(marker_fp, "%llx %llx", &marker_start, &marker_end);
fclose(marker_fp);
func_list[i].correct=1;
/* Save the correctness of the transpose submission */
if (results.funcid == i ) {
results.correct = 1;
}
full_trace_fp = fopen("trace.tmp", "r");
assert(full_trace_fp);
/* Filtered trace for each transpose function goes in a separate file */
sprintf(filename, "trace.f%d", i);
part_trace_fp = fopen(filename, "w");
assert(part_trace_fp);
/* Locate trace corresponding to the trans function */
flag = 0;
while (fgets(buf, 1000, full_trace_fp) != NULL) {
/* We are only interested in memory access instructions */
if (buf[0]==' ' && buf[2]==' ' &&
(buf[1]=='S' || buf[1]=='M' || buf[1]=='L' )) {
sscanf(buf+3, "%llx,%u", &addr, &len);
/* If start marker found, set flag */
if (addr == marker_start)
flag = 1;
/* Valgrind creates many spurious accesses to the
stack that have nothing to do with the students
code. At the moment, we are ignoring all stack
accesses by using the simple filter of recording
accesses to only the low 32-bit portion of the
address space. At some point it would be nice to
try to do more informed filtering so that would
eliminate the valgrind stack references while
include the student stack references. */
if (flag && addr < 0xffffffff) {
fputs(buf, part_trace_fp);
}
/* if end marker found, close trace file */
if (addr == marker_end) {
flag = 0;
fclose(part_trace_fp);
break;
}
}
}
fclose(full_trace_fp);
/* Run the reference simulator */
printf("Step 2: Evaluating performance (s=%d, E=%d, b=%d)\n", s, E, b);
char cmd[255];
sprintf(cmd, "./csim-ref -s %u -E %u -b %u -t trace.f%d > /dev/null",
s, E, b, i);
system(cmd);
/* Collect results from the reference simulator */
FILE* in_fp = fopen(".csim_results","r");
assert(in_fp);
fscanf(in_fp, "%u %u %u", &hits, &misses, &evictions);
fclose(in_fp);
func_list[i].num_hits = hits;
func_list[i].num_misses = misses;
func_list[i].num_evictions = evictions;
printf("func %u (%s): hits:%u, misses:%u, evictions:%u\n",
i, func_list[i].description, hits, misses, evictions);
/* If it is transpose_submit(), record number of misses */
if (results.funcid == i) {
results.misses = misses;
}
}
}
/*
* usage - Print usage info
*/
void usage(char *argv[]){
printf("Usage: %s [-h] -M <rows> -N <cols>\n", argv[0]);
printf("Options:\n");
printf(" -h Print this help message.\n");
printf(" -M <rows> Number of matrix rows (max %d)\n", MAXN);
printf(" -N <cols> Number of matrix columns (max %d)\n", MAXN);
printf("Example: %s -M 8 -N 8\n", argv[0]);
}
/*
* sigsegv_handler - SIGSEGV handler
*/
void sigsegv_handler(int signum){
printf("Error: Segmentation Fault.\n");
printf("TEST_TRANS_RESULTS=0:0\n");
fflush(stdout);
exit(1);
}
/*
* sigalrm_handler - SIGALRM handler
*/
void sigalrm_handler(int signum){
printf("Error: Program timed out.\n");
printf("TEST_TRANS_RESULTS=0:0\n");
fflush(stdout);
exit(1);
}
/*
* main - Main routine
*/
int main(int argc, char* argv[])
{
char c;
while ((c = getopt(argc,argv,"M:N:h")) != -1) {
switch(c) {
case 'M':
M = atoi(optarg);
break;
case 'N':
N = atoi(optarg);
break;
case 'h':
usage(argv);
exit(0);
default:
usage(argv);
exit(1);
}
}
if (M == 0 || N == 0) {
printf("Error: Missing required argument\n");
usage(argv);
exit(1);
}
if (M > MAXN || N > MAXN) {
printf("Error: M or N exceeds %d\n", MAXN);
usage(argv);
exit(1);
}
/* Install SIGSEGV and SIGALRM handlers */
if (signal(SIGSEGV, sigsegv_handler) == SIG_ERR) {
fprintf(stderr, "Unable to install SIGALRM handler\n");
exit(1);
}
if (signal(SIGALRM, sigalrm_handler) == SIG_ERR) {
fprintf(stderr, "Unable to install SIGALRM handler\n");
exit(1);
}
/* Time out and give up after a while */
alarm(120);
/* Check the performance of the student's transpose function */
eval_perf(5, 1, 5);
/* Emit the results for this particular test */
if (results.funcid == -1) {
printf("\nError: We could not find your transpose_submit() function\n");
printf("Error: Please ensure that description field is exactly \"%s\"\n",
SUBMIT_DESCRIPTION);
printf("\nTEST_TRANS_RESULTS=0:0\n");
}
else {
printf("\nSummary for official submission (func %d): correctness=%d misses=%d\n",
results.funcid, results.correct, results.misses);
printf("\nTEST_TRANS_RESULTS=%d:%d\n", results.correct, results.misses);
}
return 0;
}

+ 567064
- 0
trace.tmp
File diff suppressed because it is too large
View File


BIN
tracegen View File


+ 108
- 0
tracegen.c View File

@ -0,0 +1,108 @@
/*
* tracegen.c - Running the binary tracegen with valgrind produces
* a memory trace of all of the registered transpose functions.
*
* The beginning and end of each registered transpose function's trace
* is indicated by reading from "marker" addresses. These two marker
* addresses are recorded in file for later use.
*/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <getopt.h>
#include "cachelab.h"
#include <string.h>
/* External variables declared in cachelab.c */
extern trans_func_t func_list[MAX_TRANS_FUNCS];
extern int func_counter;
/* External function from trans.c */
extern void registerFunctions();
/* Markers used to bound trace regions of interest */
volatile char MARKER_START, MARKER_END;
static int A[256][256];
static int B[256][256];
static int M;
static int N;
int validate(int fn,int M, int N, int A[N][M], int B[M][N]) {
int C[M][N];
memset(C,0,sizeof(C));
correctTrans(M,N,A,C);
for(int i=0;i<M;i++) {
for(int j=0;j<N;j++) {
if(B[i][j]!=C[i][j]) {
printf("Validation failed on function %d! Expected %d but got %d at B[%d][%d]\n",fn,C[i][j],B[i][j],i,j);
return 0;
}
}
}
return 1;
}
int main(int argc, char* argv[]){
int i;
char c;
int selectedFunc=-1;
while( (c=getopt(argc,argv,"M:N:F:")) != -1){
switch(c){
case 'M':
M = atoi(optarg);
break;
case 'N':
N = atoi(optarg);
break;
case 'F':
selectedFunc = atoi(optarg);
break;
case '?':
default:
printf("./tracegen failed to parse its options.\n");
exit(1);
}
}
/* Register transpose functions */
registerFunctions();
/* Fill A with data */
initMatrix(M,N, A, B);
/* Record marker addresses */
FILE* marker_fp = fopen(".marker","w");
assert(marker_fp);
fprintf(marker_fp, "%llx %llx",
(unsigned long long int) &MARKER_START,
(unsigned long long int) &MARKER_END );
fclose(marker_fp);
if (-1==selectedFunc) {
/* Invoke registered transpose functions */
for (i=0; i < func_counter; i++) {
MARKER_START = 33;
(*func_list[i].func_ptr)(M, N, A, B);
MARKER_END = 34;
if (!validate(i,M,N,A,B))
return i+1;
}
} else {
MARKER_START = 33;
(*func_list[selectedFunc].func_ptr)(M, N, A, B);
MARKER_END = 34;
if (!validate(selectedFunc,M,N,A,B))
return selectedFunc+1;
}
return 0;
}

+ 5
- 0
traces/dave.trace View File

@ -0,0 +1,5 @@
L 10,4
S 18,4
L 20,4
S 28,4
S 50,4

+ 267988
- 0
traces/long.trace
File diff suppressed because it is too large
View File


+ 596
- 0
traces/trans.trace View File

@ -0,0 +1,596 @@
S 00600aa0,1
I 004005b6,5
I 004005bb,5
I 004005c0,5
S 7ff000398,8
I 0040051e,1
S 7ff000390,8
I 0040051f,3
I 00400522,4
S 7ff000378,8
I 00400526,4
S 7ff000370,8
I 0040052a,7
S 7ff000384,4
I 00400531,2
I 00400581,4
L 7ff000384,4
I 00400585,2
I 00400533,7
S 7ff000388,4
I 0040053a,2
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a20,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a60,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a24,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a70,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a28,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a80,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a2c,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a90,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040057d,4
M 7ff000384,4
I 00400581,4
L 7ff000384,4
I 00400585,2
I 00400533,7
S 7ff000388,4
I 0040053a,2
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a30,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a64,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a34,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a74,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a38,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a84,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a3c,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a94,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040057d,4
M 7ff000384,4
I 00400581,4
L 7ff000384,4
I 00400585,2
I 00400533,7
S 7ff000388,4
I 0040053a,2
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a40,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a68,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a44,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a78,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a48,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a88,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a4c,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a98,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040057d,4
M 7ff000384,4
I 00400581,4
L 7ff000384,4
I 00400585,2
I 00400533,7
S 7ff000388,4
I 0040053a,2
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a50,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a6c,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a54,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a7c,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a58,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a8c,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040053c,3
L 7ff000384,4
I 0040053f,2
I 00400541,4
I 00400545,3
I 00400548,4
L 7ff000378,8
I 0040054c,3
L 7ff000388,4
I 0040054f,2
I 00400551,3
L 00600a5c,4
I 00400554,3
S 7ff00038c,4
I 00400557,3
L 7ff000388,4
I 0040055a,2
I 0040055c,4
I 00400560,3
I 00400563,4
L 7ff000370,8
I 00400567,3
L 7ff000384,4
I 0040056a,3
I 0040056d,3
L 7ff00038c,4
I 00400570,3
S 00600a9c,4
I 00400573,4
M 7ff000388,4
I 00400577,4
L 7ff000388,4
I 0040057b,2
I 0040057d,4
M 7ff000384,4
I 00400581,4
L 7ff000384,4
I 00400585,2
I 00400587,1
L 7ff000390,8
I 00400588,1
L 7ff000398,8
I 004005c5,7
L 00600aa0,1

+ 7
- 0
traces/yi.trace View File

@ -0,0 +1,7 @@
L 10,1
M 20,1
L 22,1
S 18,1
L 110,1
L 210,1
M 12,1

+ 16
- 0
traces/yi2.trace View File

@ -0,0 +1,16 @@
L 0,1
L 1,1
L 2,1
L 3,1
S 4,1
L 5,1
S 6,1
L 7,1
S 8,1
L 9,1
S a,1
L b,1
S c,1
L d,1
S e,1
M f,1

+ 183
- 0
trans.c View File

@ -0,0 +1,183 @@
/*
* trans.c - Matrix transpose B = A^T
*
* Each transpose function must have a prototype of the form:
* void trans(int M, int N, int A[N][M], int B[M][N]);
*
* A transpose function is evaluated by counting the number of misses
* on a 1KB direct mapped cache with a block size of 32 bytes.
*/
#include <stdio.h>
#include "cachelab.h"
int is_transpose(int M, int N, int A[N][M], int B[M][N]);
/*
* transpose_submit - This is the solution transpose function that you
* will be graded on for Part B of the assignment. Do not change
* the description string "Transpose submission", as the driver
* searches for that string to identify the transpose function to
* be graded.
*/
char transpose_submit_desc[] = "Transpose submission";
void transpose_submit(int M, int N, int A[N][M], int B[M][N])
{
int i, j, k, l, a0, a1, a2, a3, a4, a5, a6, a7;
if(M == 32){
for (i = 0; i < N; i+=8) {
for (j = 0; j < M; j+=8) {
if(i == j){
for(k = i ;k < i + 8 && k<N;k++){
a0 = A[k][j];
a1 = A[k][j+1];
a2 = A[k][j+2];
a3 = A[k][j+3];
a4 = A[k][j+4];
a5 = A[k][j+5];
a6 = A[k][j+6];
a7 = A[k][j+7];
B[j][k] = a0;
B[j+1][k] = a1;
B[j+2][k] = a2;
B[j+3][k] = a3;
B[j+4][k] = a4;
B[j+5][k] = a5;
B[j+6][k] = a6;
B[j+7][k] = a7;
}
}
else{
for(k = i ;k < i + 8 && k<N;k++){
for(l = j ; l < j + 8 && l < M;l++)
B[l][k] = A[k][l];
}
}
}
}
}
else if(M == 64){
for (i = 0; i < N; i += 8) {
for (j = 0; j < M; j += 8) {
for (k = i; k < i + 4; k++) {
a0 = A[k][j];
a1 = A[k][j + 1];
a2 = A[k][j + 2];
a3 = A[k][j + 3];
a4 = A[k][j + 4];
a5 = A[k][j + 5];
a6 = A[k][j + 6];
a7 = A[k][j + 7];
B[j][k] = a0;
B[j + 1][k] = a1;
B[j + 2][k] = a2;
B[j + 3][k] = a3;
B[j][k + 4] = a4;
B[j + 1][k + 4] = a5;
B[j + 2][k + 4] = a6;
B[j + 3][k + 4] = a7;
}
for (l = j + 4; l < j + 8; l++) {
a4 = A[i + 4][l - 4]; // A left-down col
a5 = A[i + 5][l - 4];
a6 = A[i + 6][l - 4];
a7 = A[i + 7][l - 4];
a0 = B[l - 4][i + 4]; // B right-above line
a1 = B[l - 4][i + 5];
a2 = B[l - 4][i + 6];
a3 = B[l - 4][i + 7];
B[l - 4][i + 4] = a4; // set B right-above line
B[l - 4][i + 5] = a5;
B[l - 4][i + 6] = a6;
B[l - 4][i + 7] = a7;
B[l][i] = a0; // set B left-down line
B[l][i + 1] = a1;
B[l][i + 2] = a2;
B[l][i + 3] = a3;
B[l][i + 4] = A[i + 4][l];
B[l][i + 5] = A[i + 5][l];
B[l][i + 6] = A[i + 6][l];
B[l][i + 7] = A[i + 7][l];
}
}
}
}
else if (M == 61){
for (i = 0; i < N; i += 16) {
for (j = 0; j < M; j += 16) {
for (k = i; k < i + 16&& k<N; k++) {
for(l =j ;l<j+16&&l<M;l++)
B[l][k] = A[k][l];
}
}
}
}
}
/*
* You can define additional transpose functions below. We've defined
* a simple one below to help you get started.
*/
/*
* trans - A simple baseline transpose function, not optimized for the cache.
*/
char trans_desc[] = "Simple row-wise scan transpose";
void trans(int M, int N, int A[N][M], int B[M][N])
{
int i, j, tmp;
for (i = 0; i < N; i++) {
for (j = 0; j < M; j++) {
tmp = A[i][j];
B[j][i] = tmp;
}
}
}
/*
* registerFunctions - This function registers your transpose
* functions with the driver. At runtime, the driver will
* evaluate each of the registered functions and summarize their
* performance. This is a handy way to experiment with different
* transpose strategies.
*/
void registerFunctions()
{
/* Register your solution function */
registerTransFunction(transpose_submit, transpose_submit_desc);
/* Register any additional transpose functions */
registerTransFunction(trans, trans_desc);
}
/*
* is_transpose - This helper function checks if B is the transpose of
* A. You can check the correctness of your transpose by calling
* it before returning from the transpose function.
*/
int is_transpose(int M, int N, int A[N][M], int B[M][N])
{
int i, j;
for (i = 0; i < N; i++) {
for (j = 0; j < M; ++j) {
if (A[i][j] != B[j][i]) {
return 0;
}
}
}
return 1;
}

BIN
trans.o View File


+ 391
- 0
实验报告.md View File

@ -0,0 +1,391 @@
# Cache Lab
10225501432 邓博昊
## Part A
要求:实现一个缓存模拟器,根据给定的 trace 文件来输出对应的操作
讲义提供了一个程序示例,在安装valgrind后,使用如下命令
```bash
valgrind --log-fd=1 --tool=lackey -v --trace-mem=yes ls -l
```
输出的trace文件内容如下
```bash
I 04ead900,3
I 04ead903,3
I 04ead906,5
I 04ead838,3
I 04ead83b,3
I 04ead83e,5
L 1ffefff968,8
I 04ead843,3
I 04ead846,3
I 04ead849,5
L 1ffefff960,8
I 04ead84e,3
I 04ead851,3
......
```
trace文件中记载着每一次对内存的操作,前面的字母代表操作类型,统一的格式是:
```
[空格][操作类型][空格][内存地址][逗号][大小]
```
在此过程中,如若第一个字符并非空格而为I,则意指执行加载操作,并无实质意义。
操作类型主要分布于以下三种:
1. L:读取,从内存中检索
2. S:存储,向内存中写入
3. M:修改,此过程包括一次读取及一次存储操作
地址则指向一个64位16进制内存地址;而大小则用以表示该操作所需访问的内存字节数。需要注意的是,I指令无需插入空格,而M/S/L指令之前需添加一个空格用于解析指令。
随后,实验为我们提供了一个名为csim-ref的程序,任务便是撰写一份与之功能一致的程序。
```bash
Usage: ./csim-ref [-hv] -s <num> -E <num> -b <num> -t <file>
Options:
-h Print this help message.
-v Optional verbose flag.
-s <num> Number of set index bits.
-E <num> Number of lines per set.
-b <num> Number of block offset bits.
-t <file> Trace file.
Examples:
linux> ./csim-ref -s 4 -E 1 -b 4 -t traces/yi.trace
linux> ./csim-ref -v -s 8 -E 2 -b 4 -t traces/yi.trace
```
**分析**
`getopt`获取命令行参数
`fscanf`读入trace文件内容
`malloc`分配空间给cache
数据访问带来的miss:
* L:Load,数据载入,可能发生1次miss
* S:Store,可能发生1次miss
* M:store后再load,两次访存。1 miss & 1 hit + 可能eviction
所以L/S指令结果是miss或者hit或者miss+eviction;而M指令结果是hit+hit或者miss+hit 或者 miss+eviction+hit
### Cache结构
设计Cache基本单元为 `block`,cache由cacheblock组成
```c
typedef struct
{
unsigned tag;
unsigned usedtime;
} block;
block *cache;
```
其中`usedtime`是判断LRU cache行。初始值为0表示没有用过,相当于invalid。非零值越小代表越少使用,`usedtime`最大代表刚使用。
### 命令行参数解析
首先对命令行参数进行解析
```C
int getOpt(int argc,char **argv,int *s,int *E,int *b,int *verbose,char *tracefile)
{
int oc;
while((oc=getopt(argc,argv,"hvs:E:b:t:"))!=-1){
switch(oc){
case 'h': printHelpMenu();break; // print usage
case 'v': *verbose=1;break;
case 's': *s = atoi(optarg);break;
case 'E': *E = atoi(optarg);break;
case 'b': *b = atoi(optarg);break;
case 't': strcpy(tracefile,optarg);break;
default : printf("input error\n");break;
}
}
return 0;
}
```
### 初始化cache
然后初始化cache
```C
cache = (block *)malloc(sizeof(block)* E<<s);
memset(cache,0,sizeof(block)* E<<s);
```
### 读取文件参数
`fscanf`读取trace文件中的指令、地址
```c
fp = fopen (tracefile,"r");
while(fscanf(fp,"%s%x,%d\n",op,&addr,&size) > 0){
if(verbose)
printf("%s %x,%d ",op,addr,size);
switch(op[0]){
case 'M': hit++;
case 'L':
case 'S': find(op[0],addr,size,++t);
}
}
```
### 数据访问
获取`tag`和 `set index`
```C
unsigned tag = addr >>b >>s ;
unsigned set_index = addr >> b &((1<<s) -1);
```
找到对应的set
```c
block *cache_set = cache + E * set_index ; // set address
block *eviction_block = cache_set; // LRU cacheline
```
进行数据查找,其中eviction_block表示查询过程中LRU的cache行,也就是usedtime最小的(但是非0)在一个set里面遍历cache行
* 如果`usedtime`!=0且tag匹配:hit
* 如果`usedtime`=0,是个空block,使用这个block:miss
* 如果`usedtime`!=0,tag不匹配,跟`eviction_block.usedtime`比较,如果时间更小,更新`eviction_block`=该cacheblock
如果循环结束,也就证明该set的所有cache行都满了,就替换LRU cache行。
```c
void find(char op, unsigned addr,unsigned size,int time){
int i;
unsigned tag = addr >>b >>s ;
unsigned set_index = addr >> b &((1<<s) -1);
block *cache_set = cache + E * set_index ; // set address
block *eviction_block = cache_set; // LRU cacheline
for(i = 0;i<E;i++){
if(cache_set[i].usedtime>0 && cache_set[i].tag ==tag){ //hit
cache_set[i].usedtime = time;
hit++;
if(verbose) cacheStateOut(op,0);
return;
}
else if(!cache_set[i].usedtime){ // empty block
miss++;
cache_set[i].tag = tag;
cache_set[i].usedtime = time;
if(verbose) cacheStateOut(op,1);
return;
}
else if(cache_set[i].usedtime < eviction_block->usedtime) // !=tag , current block is older
eviction_block = cache_set+i;
}
miss ++;
eviction ++;
eviction_block->tag = tag; // replace sacrifice cacheline
eviction_block->usedtime = time;
if(verbose) cacheStateOut(op,2);
return ;
}
```
## Part B
Part B 要我们实作矩阵转置,并将 cache miss 尽可能降低,Part B 的程序限制如下
- 在 stack 中至多 12 个整数型态的局部变量
- 不得使用 long 或位操作,将 2 个整数型态变量存在 1 个变量中
- 不得使用递归
- 不得修改矩阵 A ,但可以修改矩阵 B
- 不得自定义矩阵或使用 对变量动态配置内存空间`malloc`
缓存参数
- 缓存取大小 1KB
- 采用直映射(E=1)
- Block 大小为 32 Byte(b=5)
- Set 共 32 组(s=5)
Eviction 的策略
- 矩阵 A & B 的第一行在 cache 中为同一组
- 对角线元素互相 evict
测试矩阵大小及分数
- 32 x 32: cache miss < 300 满分
- 64 x 64: cache miss < 1300 满分
- 61 x 67: cache miss < 2000 满分
**分析:**
在该实验中,缓存采用的是直接映射高速缓存,s = 5,b = 5,E = 1。对于该缓存,总共存在32个组,每个组共32个字节,可以装入8个int型变量,是非常有限的缓存,矩阵大小>cache大小。
主要需要解决以下两个问题:
* 直接映射缓存所带来的冲突不命中。观察程序中矩阵存储的位置即可以发现,矩阵A和矩阵B的同一行实际上被映射到了同一个缓存组。当进行对角线的引用时,一定会发生缓存的冲突不命中。需要仔细地处理对角线上的元素。
* 所需优化的矩阵的总大小超出了缓存的总大小。必然导致程序的访存效率低下。
为了解决第一个问题,我们需要仔细地考虑对于矩阵访问顺序;第二个问题,采用矩阵的分块(Blocking)方法降低miss
### 32 * 32
缓存一个块的大小为 32 Bytes,可放入 8 个整数类型,又整个缓存有 32 组,代表缓存一次可以存放 32 x 8 = 256 个连续位置的整数。 对于32 x 32的矩阵来说,等于每8列(256/32)就会发生冲突,因此理想的分块大小应该为**8 x 8**
另外,因为假设为直接映射,每组都只有一行,等于说只要发生冲突一定有 eviction,代表我们必需尽可能降低行替换的次数。 作业特别说明对角线元素互相evict,我们画图观察转置对角线元素会发生什么情况,为了简化以4 x 4的状况来呈现
- T1: 第一次置换,都是 cache miss
- T2: 第二次置换,A 是 cache hit,但 B 矩阵第二行不在快取中为 cache miss
- T3: 第二次置换,为了将 B 矩阵第二行读进快取,必需将 A 矩阵第二行替换掉
- T4: 第三次置换,因为 T3 替换了 A 矩阵第二行,在 T4 又必需加载回来
从以上分析可以发现,快取在A &B**对角线**元素的那一行发生**冲突**,所以对角线元素的替换会产生2次的miss及eviction。
简单`8 * 8`分块:
```c
if(M == 32){
for (i = 0; i < N; i+=8) {
for (j = 0; j < M; j+=8) {
for(k = i ;k < i + 8 && k<N;k++){
for(l = j ; l < j + 8 && l < M;l++)
{
a0 = A[k][l];
B[l][k] = a0;
}
}
}
}
}
```
测试结果超过了300miss,原因是**对角线访问冲突问题**
#### 对角线访问冲突问题
矩阵A和矩阵B的同一行实际上被映射到了同一个cache block。当进行对角线的引用时,一定会发生缓存的冲突不命中。并且,由于A和B的元素时一个一个处理的,必定会造成反复多次的冲突不命中。(如下图A第一个元素读miss,B第一个元素存miss,A读第二个元素miss)
**解决方法:通过变量一次性读出A的一整行,再存入B**
```c
for (i = 0; i < N; i+=8) {
for (j = 0; j < M; j+=8) {
if(i == j){
for(k = i ;k < i + 8 && k<N;k++){
a0 = A[k][j];
a1 = A[k][j+1];
a2 = A[k][j+2];
a3 = A[k][j+3];
a4 = A[k][j+4];
a5 = A[k][j+5];
a6 = A[k][j+6];
a7 = A[k][j+7];
B[j][k] = a0;
B[j+1][k] = a1;
B[j+2][k] = a2;
B[j+3][k] = a3;
B[j+4][k] = a4;
B[j+5][k] = a5;
B[j+6][k] = a6;
B[j+7][k] = a7;
}
}
else{
for(k = i ;k < i + 8 && k<N;k++){
for(l = j ; l < j + 8 && l < M;l++)
B[l][k] = A[k][l];
}
}
}
}
```
### 64 * 64
方法:将8 * 8 块再分成4个4 * 4的块进一步处理
* 首先对左上角和右上角进行处理:
1. B左上角 = A左上角转置。B右上角=A右上角转置。
2. 我们最后只需要把这部分平移到B的左下角就好。
* 现在B左上角完成
1. 首先用四个变量存储A的左下角的一列。
2. 再用四个变量存储B的右上角的一行。
3. 把四个变量存储的A的左下角的一列移动到B右上角的一行
4. 把四个变量存储的B的右上角的一行平移到B左下角的一列
5. B的右下角=A的右下角转置
```c
for (i = 0; i < N; i += 8) {
for (j = 0; j < M; j += 8) {
for (k = i; k < i + 4; k++) {
a0 = A[k][j];
a1 = A[k][j + 1];
a2 = A[k][j + 2];
a3 = A[k][j + 3];
a4 = A[k][j + 4];
a5 = A[k][j + 5];
a6 = A[k][j + 6];
a7 = A[k][j + 7];
B[j][k] = a0;
B[j + 1][k] = a1;
B[j + 2][k] = a2;
B[j + 3][k] = a3;
B[j][k + 4] = a4;
B[j + 1][k + 4] = a5;
B[j + 2][k + 4] = a6;
B[j + 3][k + 4] = a7;
}
for (l = j + 4; l < j + 8; l++) {
a4 = A[i + 4][l - 4]; // A left-down col
a5 = A[i + 5][l - 4];
a6 = A[i + 6][l - 4];
a7 = A[i + 7][l - 4];
a0 = B[l - 4][i + 4]; // B right-above line
a1 = B[l - 4][i + 5];
a2 = B[l - 4][i + 6];
a3 = B[l - 4][i + 7];
B[l - 4][i + 4] = a4; // set B right-above line
B[l - 4][i + 5] = a5;
B[l - 4][i + 6] = a6;
B[l - 4][i + 7] = a7;
B[l][i] = a0; // set B left-down col
B[l][i + 1] = a1;
B[l][i + 2] = a2;
B[l][i + 3] = a3;
B[l][i + 4] = A[i + 4][l];
B[l][i + 5] = A[i + 5][l];
B[l][i + 6] = A[i + 6][l];
B[l][i + 7] = A[i + 7][l];
}
}
}
```
### 61 * 67
对于不规则的矩阵,其核心依然是通过分块的方式优化Cache的读写效率。然而,要找到非常明显的规律来判断何时能填满一个Cache却并非易事。鉴于要求较为宽松,我们无需考虑处理对角线的情况,而是直接执行转置操作。只需尝试并更换不同的边长分块就能达到期望效果。实际上,采用16 × 16的分块规模就足以确保获得满分。

Loading…
Cancel
Save