diff --git a/README.md b/README.md new file mode 100644 index 0000000..8c3052c --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# lab-1 +Here are three different version... + +1. [recursion](lab-1/): Use `make` command to check the answer +2. [iteration](lab-1i/): Use `make` command to check the answer +3. [c-code](lab-1-c/): Translate arm code to c, and use `gprof` to analyze. You can use `make` to run the `gprof` script, the results will show in `analysis.txt`. After arranging the data, you can see the example in [result.txt](lab-1-c/result.txt). Finally, I use the [script](lab-1-c/gplot_cmd.txt) and the [result](lab-1-c/efficiency.png) shows as following... +```sh +gnuplot +> plot "analysis-result.txt" +> set style data lines # connect each dots +> set grid # set background as grid +> set title "fib efficiency" # add title +> replot +> plot "analysis-result.txt" using 1:2 title 'Recursion', \ + "analysis-result.txt" using 1:3 title 'Tail-Recursion', \ + "analysis-result.txt" using 1:4 title 'Iteration' # plot three data at the same time +> set logscale y; replot # data in y-axis is large, use logscale +> set output "efficiency.png" ; set term png ; replot +``` +![picture alt](lab-1-c/efficiency.png) diff --git a/lab-1-c/Makefile b/lab-1-c/Makefile new file mode 100644 index 0000000..b04846a --- /dev/null +++ b/lab-1-c/Makefile @@ -0,0 +1,19 @@ + +default: fib + +fib: fib.o + gcc -Wall -pg fib.c -o fib + +fib.o: fib.c + +qemu: fib + @num=1 ; while [ $$num -le 10 ] ; do \ + echo "go to $$num" ; \ + echo "\ngo to $$num \n" >> analysis.txt ; \ + ./fib $$num ; \ + gprof fib gmon.out -p -b >> analysis.txt ; \ + num=`expr $$num + 1` ; \ + done + +clean: + rm fib fib.o gmon.out analysis.txt diff --git a/lab-1-c/efficiency.png b/lab-1-c/efficiency.png new file mode 100644 index 0000000..0ff1451 Binary files /dev/null and b/lab-1-c/efficiency.png differ diff --git a/lab-1-c/fib.c b/lab-1-c/fib.c new file mode 100644 index 0000000..c5613b0 --- /dev/null +++ b/lab-1-c/fib.c @@ -0,0 +1,22 @@ +#include +#define TIMES 1000000 + +int recursive(int n){ return n<3 ? 1 : recursive(n-1)+recursive(n-2); } + +int tail_rec(int n,int a,int b){ return n==0 ? b : tail_rec(n-1,a+b,a); } + +int iterative(int n){ + int i1=0, i2=1, res; + for(;n;--n){ res=i2; i2+=i1; i1=res; } + return res; +} + +int main(int argc, char* argv[]){ + int n=atoi(argv[1]),i; + for(i=0;i + +int main(void){ + int i1=0, i2=1, n, res; + scanf("%d",&n); + for(;n;--n){ res=i2; i2+=i1; i1=res; } + printf("%d\n",res); +} diff --git a/lab-1-c/fib_recursive.c b/lab-1-c/fib_recursive.c new file mode 100644 index 0000000..ca261e8 --- /dev/null +++ b/lab-1-c/fib_recursive.c @@ -0,0 +1,9 @@ +#include + +int fib(int n){ return n<3 ? 1 : fib(n-1)+fib(n-2); } + +int main(void){ + int n; + scanf("%d",&n); + printf("%d\n",fib(n)); +} diff --git a/lab-1-c/fib_tail_recursive.c b/lab-1-c/fib_tail_recursive.c new file mode 100644 index 0000000..12eb77f --- /dev/null +++ b/lab-1-c/fib_tail_recursive.c @@ -0,0 +1,12 @@ +#include +#define times 10000000 + +int fib(int n,int a,int b){ return n==0 ? b : fib(n-1,a+b,a); } + +int main(void){ + int n,i; + scanf("%d",&n); + for(i=0;i plot "analysis-result.txt" +> set style data lines # 設定成連線模式 +> set grid # 模擬方格紙效果 +> set title "fib efficiency" # 加上標題。 +> replot # 重畫一遍 +> plot "analysis-result.txt" using 1:2 title 'Recursion', \ + "analysis-result.txt" using 1:3 title 'Tail-Recursion', \ + "analysis-result.txt" using 1:4 title 'Iteration' # 同時畫三圖 +> set logscale y; replot # y軸差異太大, 用 logscale +> set output "efficiency.png" ; set term png ; replot diff --git a/lab-1-c/result.txt b/lab-1-c/result.txt new file mode 100644 index 0000000..607006f --- /dev/null +++ b/lab-1-c/result.txt @@ -0,0 +1,46 @@ +1 1.52 3.03 2.02 +2 3.03 1.01 6.06 +3 7.58 13.13 5.05 +4 9.09 9.09 5.05 +5 29.80 20.20 7.07 +6 50.52 16.16 6.06 +7 30.31 21.21 10.10 +8 95.98 22.22 28.28 +9 121.24 25.25 15.15 +10 298.04 29.29 44.44 +11 272.78 40.40 35.35 +12 722.37 30.30 26.26 +13 914.33 43.43 31.31 +14 1400 43.43 40.40 +15 2550 52.53 46.46 +16 3030 49.49 35.35 +17 10100 56.57 58.59 +18 9090 63.64 65.66 +19 15150 68.69 49.49 +20 23740 64.65 67.68 +21 48490 98.99 62.63 +22 60110 72.73 78.79 +23 111640 78.79 66.67 +24 183880 87.88 77.78 +25 293490 85.86 84.85 +26 606190 90.91 79.80 +27 1210000 97.98 81.82 +28 1520000 96.97 90.91 +29 2170000 124.24 84.85 +30 3740000 130.30 74.75 +31 5250000 121.21 78.79 +32 9500000 104.04 90.91 +33 13490000 146.46 94.95 +34 22530000 111.11 118.18 +35 46520000 119.19 109.09 +36 65670000 120.20 98.99 +37 70720000 151.52 101.01 +38 141440000 129.29 123.23 +39 227320000 153.54 117.17 +40 434430000 132.32 135.35 +41 676910000 161.62 122.22 +42 1120000000 137.37 143.43 +43 1720000000 200.00 130.30 +44 3120000000 155.56 115.15 +45 4600000000 157.58 128.28 +45 8660000000 159.60 145.45 diff --git a/lab-1/Makefile b/lab-1/Makefile index 84806d7..45ded60 100644 --- a/lab-1/Makefile +++ b/lab-1/Makefile @@ -1,34 +1 @@ -CC = arm-linux-gnueabihf-gcc -CFLAGS = -O1 -Wall -LDFLAGS = -fno-stack-protector - -objects = fibseq.o fib.o - -default: fibseq - -.PHONY: default clean qemu - -fibseq: $(objects) - $(CC) $(LDFLAGS) -o $@ $^ - -fib.o: fib.s -fibseq.o: fibseq.c - -%.o: %.c - $(CC) -c $(CFLAGS) -o $@ $< - -%.o: %.s - $(CC) -c $(CFLAGS) -o $@ $< - -clean: - rm -f $(objects) fibseq - -QEMU_CMD = qemu-arm -L /usr/arm-linux-gnueabihf ./fibseq & -CMD = yes 9 | $(call QEMU_CMD) && sleep 1 -qemu: fibseq - @yes 5 | $(call QEMU_CMD) - @sleep 1 - @yes 6 | $(call QEMU_CMD) - @sleep 1 - @yes 7 | $(call QEMU_CMD) - @sleep 1 +include ../make_fib.mk diff --git a/lab-1/fib.s b/lab-1/fib.s index 14c6734..e1b6b45 100644 --- a/lab-1/fib.s +++ b/lab-1/fib.s @@ -11,33 +11,25 @@ fibonacci: @ ADD/MODIFY CODE BELOW @ PROLOG - push {r3, r4, r5, lr} + push {r4, r5, lr} - @ R4 = R0 - 0 (update flags) - @ if(R0 <= 0) goto .L3 (which returns 0) + subs r4, r0, #0 @ R4 = R0 - 0 (update flags) + beq .L4 @ If R4 == 0 goto .L4 (which returns second) - @ Compare R4 wtih 1 - @ If R4 == 1 goto .L4 (which returns 1) + sub r5, r1, #0 @ R5 = first - @ R0 = R4 - 1 - @ Recursive call to fibonacci with R4 - 1 as parameter + sub r0, r4, #1 @ R0 = R4 - 1 + add r1, r5, r2 @ R1 = first+second + mov r2, r5 @ R2 = first + bl fibonacci @ Recursive call to fibonacci - @ R5 = R0 - @ R0 = R4 - 2 - @ Recursive call to fibonacci with R4 - 2 as parameter - - @ R0 = R5 + R0 (update flags) - - pop {r3, r4, r5, pc} @EPILOG + pop {r4, r5, pc} @EPILOG @ END CODE MODIFICATION -.L3: - mov r0, #0 @ R0 = 0 - pop {r3, r4, r5, pc} @ EPILOG .L4: - mov r0, #1 @ R0 = 1 - pop {r3, r4, r5, pc} @ EPILOG + sub r0, r2, #0 @ R0 = second + pop {r4, r5, pc} @ EPILOG .size fibonacci, .-fibonacci .end diff --git a/lab-1/fibseq.c b/lab-1/fibseq.c index 90913c2..a649e66 100644 --- a/lab-1/fibseq.c +++ b/lab-1/fibseq.c @@ -1,6 +1,13 @@ +/* * The fibonacci function call here, + * there are three arguments: fibonacci(int x, int y, int z) + * x: request for the xth Fibonacci number + * y: the last Fibonacci number we've known (fib 1 = 1) + * z: the second last Fibonacci number (fib0 = 0) + */ + #include -extern int fibonacci(int x); +extern int fibonacci(int x, int y, int z); int main(int argc, char **argv) { @@ -8,7 +15,7 @@ int main(int argc, char **argv) int result=0; scanf("%d",&number); - result = fibonacci(number); + result = fibonacci(number,1,0); printf("The fibonacci sequence at %d is: %d\n", number, result); } diff --git a/lab-1i/Makefile b/lab-1i/Makefile index 84806d7..45ded60 100644 --- a/lab-1i/Makefile +++ b/lab-1i/Makefile @@ -1,34 +1 @@ -CC = arm-linux-gnueabihf-gcc -CFLAGS = -O1 -Wall -LDFLAGS = -fno-stack-protector - -objects = fibseq.o fib.o - -default: fibseq - -.PHONY: default clean qemu - -fibseq: $(objects) - $(CC) $(LDFLAGS) -o $@ $^ - -fib.o: fib.s -fibseq.o: fibseq.c - -%.o: %.c - $(CC) -c $(CFLAGS) -o $@ $< - -%.o: %.s - $(CC) -c $(CFLAGS) -o $@ $< - -clean: - rm -f $(objects) fibseq - -QEMU_CMD = qemu-arm -L /usr/arm-linux-gnueabihf ./fibseq & -CMD = yes 9 | $(call QEMU_CMD) && sleep 1 -qemu: fibseq - @yes 5 | $(call QEMU_CMD) - @sleep 1 - @yes 6 | $(call QEMU_CMD) - @sleep 1 - @yes 7 | $(call QEMU_CMD) - @sleep 1 +include ../make_fib.mk diff --git a/lab-1i/fib.s b/lab-1i/fib.s index 14c6734..d4f18ec 100644 --- a/lab-1i/fib.s +++ b/lab-1i/fib.s @@ -11,33 +11,22 @@ fibonacci: @ ADD/MODIFY CODE BELOW @ PROLOG - push {r3, r4, r5, lr} + push {r4, r5, r6, lr} - @ R4 = R0 - 0 (update flags) - @ if(R0 <= 0) goto .L3 (which returns 0) + sub r4, r0, #0 @ R4 = R0 - 0 (update flags) - @ Compare R4 wtih 1 - @ If R4 == 1 goto .L4 (which returns 1) + mov r5, #0 @ init fib(0) = 0 + mov r6, #1 @ init fib(1) = 1 +.Loop: + mov r0, r6 @ R0 = R6 and also the result + add r6, r5, r6 @ R6 += R5 + mov r5, r0 @ R5 = R0 (exchange R5, R6) + subs r4, r4, #1 @ R4 = R4 - 1 + bne .Loop - @ R0 = R4 - 1 - @ Recursive call to fibonacci with R4 - 1 as parameter - - @ R5 = R0 - @ R0 = R4 - 2 - @ Recursive call to fibonacci with R4 - 2 as parameter - - @ R0 = R5 + R0 (update flags) - - pop {r3, r4, r5, pc} @EPILOG + pop {r4, r5, r6, pc} @EPILOG @ END CODE MODIFICATION -.L3: - mov r0, #0 @ R0 = 0 - pop {r3, r4, r5, pc} @ EPILOG - -.L4: - mov r0, #1 @ R0 = 1 - pop {r3, r4, r5, pc} @ EPILOG .size fibonacci, .-fibonacci .end diff --git a/make_fib.mk b/make_fib.mk new file mode 100644 index 0000000..a9e957e --- /dev/null +++ b/make_fib.mk @@ -0,0 +1,48 @@ +CC = arm-linux-gnueabihf-gcc +CFLAGS = -O1 -Wall +LDFLAGS = -fno-stack-protector + +objects = fibseq.o fib.o + +default: fibseq + +.PHONY: default clean qemu + +fibseq: $(objects) + $(CC) $(LDFLAGS) -o $@ $^ + +fib.o: fib.s +fibseq.o: fibseq.c + +%.o: %.c + $(CC) -c $(CFLAGS) -o $@ $< + +%.o: %.s + $(CC) -c $(CFLAGS) -o $@ $< + +clean: + rm -f $(objects) fibseq + +QEMU_CMD = qemu-arm -L /usr/arm-linux-gnueabihf ./fibseq & +CMD = yes 9 | $(call QEMU_CMD) && sleep 1 +qemu: fibseq + @num=1 ; i1=0 ; i2=1 ; \ + while [ $$num -le 50 ] ; do \ + # save output answer \ + ans=`yes $$num | $(call QEMU_CMD)` ; \ + sleep 0.5 ; \ + # echo output \ + echo $$ans ; \ + # split output string && save answer \ + ans=`echo $$ans | cut -d ' ' -f 7` ; \ + # calculate the correct answer \ + i3=$$i2 ; i2=`expr $$i1 + $$i2` ; i1=$$i3 ; \ + # check if it is right \ + if [ "$$i1" -eq "$$ans" ] ; then \ + echo " -> correct" ; \ + else \ + echo " -> wrong, the ans is $$i1" ; \ + fi ; \ + num=`expr $$num + 1` ; \ + done +