2018q3 Homework2 (lab0)

contributed by < happyincent >

Environment

VM

$ cat <(echo) <(echo "CPU:    " `lscpu | grep "Model name" | cut -d' ' -f12-17`) <(echo "OS:     " `lsb_release -d | cut -f2`) <(echo "Kernel: " `uname -a | cut -d' ' -f1-3,14`) <(echo "gcc:    " `gcc --version | head -n1`) <(echo "ldd:    " `ldd --version | head -n1`) <(echo "Make:   " `make --version | head -n1`)

CPU:     Intel(R) Core(TM) i5-2400 CPU @ 3.10GHz
OS:      Ubuntu 18.04.1 LTS
Kernel:  Linux xubuntu 4.15.0-36-generic x86_64
gcc:     gcc (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0
ldd:     ldd (Ubuntu GLIBC 2.27-3ubuntu1) 2.27
Make:    GNU Make 4.1

RPi

$ cat <(echo) <(echo "CPU:    " `lscpu | grep "Model name" | cut -d' ' -f14-18`) <(echo "OS:     " `lsb_release -d | cut -f2`) <(echo "Kernel: " `uname -a | cut -d' ' -f1-3,12`) <(echo "gcc:    " `gcc --version | head -n1`) <(echo "ldd:    " `ldd --version | head -n1`) <(echo "Make:   " `make --version | head -n1`)

CPU:     ARMv7 Processor rev 4 (v7l)
OS:      Raspbian GNU/Linux 9.4 (stretch)
Kernel:  Linux raspberrypi 4.14.52-v7+ armv7l
gcc:     gcc (Raspbian 6.3.0-18+rpi1+deb9u1) 6.3.0 20170516
ldd:     ldd (Debian GLIBC 2.24-11+deb9u3) 2.24
Make:    GNU Make 4.1

Makefile

  • ๅŠ ไธŠ -std=gnu11ใ€ๅ˜—่ฉฆ Implicit Rulesใ€ๅŠ ไธŠ dependency
.PHONY: dep test clean

CC = gcc
CFLAGS = -O0 -g -Wall -Werror -std=gnu11
GIT_HOOKS := .git/hooks/applied
all: $(GIT_HOOKS) qtest

$(GIT_HOOKS):
	@scripts/install-git-hooks
	@echo

# queue.o: queue.c queue.h harness.h
# 	$(CC) $(CFLAGS) -c queue.c 

# qtest: qtest.c report.c console.c harness.c queue.o
# 	$(CC) $(CFLAGS) -o qtest qtest.c report.c console.c harness.c queue.o

queue.o: queue.c queue.h harness.h

qtest: qtest.c report.c console.c harness.c queue.o

dep:
	@$(CC) -MM *.c
	@$(CC) -M *.c > depend

test: qtest scripts/driver.py
	scripts/driver.py

clean:
	rm -f *.o *~ qtest depend
	rm -rf *.dSYM
	(cd traces; rm -f *~)
  • .PHONY

    • A phony target is one that is not really the name of a file. [source]
  • CFLAGS [source]

    • -O0: ้—œ้–‰ๅ„ชๅŒ–๏ผŒdefault optimization level
    • -g: Options for Debugging
    • -Wall: ๅ•Ÿ็”จๅฎนๆ˜“่ขซ้ฟๅ…็š„ warnings
    • -Werror: Make all warnings into errors.
    • -std=gnu11
      • gcc version 6.3.1 - 7.3.1: default is '-std=gnu11' [source]
        • GNU C Library ๆœ‰ ISO C ไนŸๆœ‰ POSIX [source]
      • ่‹ฅ็”จ -std=c11 ๆœƒ็„กๆณ•็ทจ่ญฏ
        • console.h: unknown type name โ€˜fd_setโ€™
          • fd_set ๅฎš็พฉๅœจ <sys/select.h> ๅฑฌๆ–ผ C POSIX library ่€Œ้ž ISO C
        • harness.c: implicit declaration of function โ€˜randomโ€™ (โ€˜sigsetjmpโ€™)
          • ๅŒไธŠ่ฟฐๅŽŸๅ› , random: <stdlib.h> (BSD Random), sigsetjmp: <setjmp.h>
  • $(GIT_HOOKS)

    • target ่จญ็‚บ .git/hooks/applied
      • ๅŸท่กŒ scripts/install-git-hooks ๆ™‚ๆœƒ touch ๆช”ๆกˆ: .git/hooks/applied
      • ็ฌฌไบŒๆฌกๅพŒ Make ๆ™‚ๅ› ็‚บ $(GIT_HOOKS) ๆช”ๆกˆๅทฒๅญ˜ๅœจไธ”้€™ๅ€‹ target ๆฒ’ๆœ‰ prerequisites ้œ€่ฆ็ขบ่ช๏ผŒๅ› ๆญค Make ๆœƒ่ช็‚บๅทฒ็ถ“ up to date ไพฟไธๆœƒๅ†ๅŸท่กŒ
        โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹$ rm .git/hooks/applied
        โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹$ make clean all > /dev/null && ls -l .git/hooks/applied
        โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹-rw-rw-r-- 1 ddl ddl 0 Oct  3 02:40 .git/hooks/applied
        โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹$ make clean all > /dev/null && ls -l .git/hooks/applied
        โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹-rw-rw-r-- 1 ddl ddl 0 Oct  3 02:40 .git/hooks/applied
        โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹$ make .git/hooks/applied
        โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹make: '.git/hooks/applied' is up to date.
        
      • install-git-hooks ๅœจ .git/hooks ๅปบ็ซ‹ๅ…ฉๅ€‹ๅœจ commit ๅ‰ๆœƒๅŸท่กŒ็š„ scripts
        • pre-commit: clang-format (ๆชขๆŸฅๆ ผๅผ)ใ€cppcheck (ๆชขๆŸฅ bugs)
        • commit-msg: ๆชขๆŸฅ commit message (git-good-commit)
    • a line starts with@: ไธ echo ่ฉฒ่กŒๆŒ‡ไปค (Recipe Echoing)
    • := : Simply expanded variables, = : recursively expanded variables,
      ?= : conditional variable assignment [source]
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹A = $(B)
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹B = $(C)
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹C ?= World!
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹C ?= World!!!
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹X := Hello $(A)
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹Y = Hello $(A)
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹C = DDL!
      
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹all:
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹    @echo $(X)  ## Hello World!
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹    @echo $(Y)  ## Hello DDL!
      
  • all

  • queue.o, qtest

    • -c: compile or assemble the source files, but do not link
    • -o file: output in file file
    • ๅฆ‚ๆžœ rule ไธญๆฒ’ๆœ‰ recipe๏ผŒMake ๆœƒไพๆ“š targetใ€prerequisites (the source files) ไพ†ๆฑบๅฎš Implicit Rules (recursively)
      • Built-In Rules: Compiling C programsใ€Linking a single object file
  • dep [source]

    • -M: output a rule suitable for make describing the dependencies of the main source file
    • -MM: ๆ‰พๅ‡บ้ž include ็ณป็ตฑไธ”้ž้–“ๆŽฅ include ็š„ source file dependencies
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹$ make dep
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹console.o: console.c console.h report.h
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹harness.o: harness.c report.h harness.h
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹qtest.o: qtest.c harness.h queue.h console.h report.h
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹queue.o: queue.c harness.h queue.h
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹report.o: report.c report.h
      
  • test

    • prerequisites: qtestใ€scripts/driver.py
    • ไธๅธถๅƒๆ•ธๅŸท่กŒ scripts/driver.py๏ผŒไพๆ“š ./traces/*.cmd ๅŸท่กŒ qtest ไธฆ็ฎ—ๅ‡บๅˆ†ๆ•ธ
  • clean

    • ๅˆชๆމ make ๅ‡บไพ†็š„ .oใ€ๅŸท่กŒๆช”็ญ‰
    • .dSYM: debug symbols
    • *~: ็ทจ่ผฏๅ™จๅ‚™ไปฝๆช”

queue

  • Queue Structure

    โ€‹โ€‹โ€‹โ€‹typedef struct {
    โ€‹โ€‹โ€‹โ€‹    list_ele_t *head; /* Linked list of elements */
    โ€‹โ€‹โ€‹โ€‹    list_ele_t *tail;
    โ€‹โ€‹โ€‹โ€‹    size_t q_size; /* Linked list's size */
    โ€‹โ€‹โ€‹โ€‹} queue_t;
    
    • ๅŠ ๅ…ฅ size_t q_size ไพ†้”ๆˆๅœจ O(1) ๆ™‚้–“ๅ…งๅพ—ๅˆฐ queue elements ็š„ๆ•ธ็›ฎ
      • size_t: unsigned integer type
        • sizeof(long) = sizeof(size_t) [stackoverflow: size_t ]
        • Limit of size_t type [stdint.h]
          • SIZE_MAX: 18446744073709551615 (64 bit), 4294967295 (32 bit)
          โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹#include <stdio.h>
          โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹#include <stdint.h>
          โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹int main() {
          โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹    printf("SIZE_MAX: %lu\n", SIZE_MAX);
          โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹    size_t a = 18446744073709551615U;
          โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹    printf("(%lu + 1) > 1: %s\n", a, (a + 1 > 1) ? "true" : "false");
          โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹}
          
          โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹$ gcc -Wall a.c && ./a.out
          โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹SIZE_MAX: 18446744073709551615
          โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹(18446744073709551615 + 1) > 1: false
          
    • ๅŠ ๅ…ฅ list_ele_t *tail ็ด€้Œ„ queue ไธญ tail element ็š„ไฝๅ€
  • q_insert_head

    • ๆœฌไพ†ๅฐ‡ insert ็š„ๅญ˜ๆ”พๅญ—ไธฒๅฆๅค–ๅฏซๆˆ static inline list_ele_t *ele_new(char *s)๏ผŒไฝ†็™ผ็พๆœƒ้€ ๆˆๆ›ดๅคš็š„ jmp (BL, BNE, โ€ฆ) ๆฌกๆ•ธ
      • gcc -O0 (optimization level 0) ๆ™‚ๅฏ่ƒฝไธๆœƒๅฑ•้–‹ inline [source] [gcc-inline]
        • ้™ค้žๅœจ function ๅŠ ไธŠ __attribute__((always_inline)) ๅผทๅˆถๅš inline
  • q_reverse

    โ€‹โ€‹โ€‹โ€‹/* iterate the queue to reverse each next pointer */
    โ€‹โ€‹โ€‹โ€‹list_ele_t *left = q->head;
    โ€‹โ€‹โ€‹โ€‹list_ele_t *right = NULL;
    โ€‹โ€‹โ€‹โ€‹list_ele_t *tmp = NULL;
    
    โ€‹โ€‹โ€‹โ€‹q->tail = left;
    
    โ€‹โ€‹โ€‹โ€‹while (left != NULL) {
    โ€‹โ€‹โ€‹โ€‹    tmp = left->next;
    โ€‹โ€‹โ€‹โ€‹    left->next = right;
    โ€‹โ€‹โ€‹โ€‹    right = left;
    โ€‹โ€‹โ€‹โ€‹    left = tmp;
    โ€‹โ€‹โ€‹โ€‹}
    
    โ€‹โ€‹โ€‹โ€‹q->head = right;
    

ๆฏ”่ผƒไธๅŒ็’ฐๅขƒ็š„ Grade ๅˆ†ๆ•ธ

็ต่ซ–: ๆˆ‘ๆฒ’ๆœ‰่ƒฝๅŠ›ๆŠŠ C ๅฏซๅˆฐ -O0 ๅ’Œ -O1 ไธ€ๆจฃๅฅฝ

  • ๅˆ†ๅˆฅไปฅ optimization level: -O0 (ไธ‹ๅœ–ๅทฆ)ใ€-O1 (ไธ‹ๅœ–ๅณ) compile queue.c๏ผŒไธฆๆฏ”่ผƒ IDA Pro disassemble ๅพŒ q_insert_head ็š„ graph ๅœ–
  • ๅœจ VM ็’ฐๅขƒไธ‹ (gcc Ubuntu 7.3.0)
    • O0 ๆœ€ๅคš้œ€ 8 ๆฌก jmp
    • O1 ๆœ€ๅคš้œ€ 6 ๆฌก jmp
  • ๅœจ RPi ็’ฐๅขƒไธ‹ (gcc Raspbian 6.3.0)
    • O0 ๆœ€ๅคš้œ€ 6 ๆฌก jmp
    • O1 ๆœ€ๅคš้œ€ 3 ๆฌก jmp

ๅŸท่กŒ็ตๆžœ

  • ๅœจ RPi ็’ฐๅขƒ -O0
    • ๅพž trace 13 ้–‹ๅง‹ๅฐฑๆœƒๅ› ็‚บ ih ๆˆ– it ็š„ๆฌกๆ•ธ่ผƒๅคง็™ผ็”Ÿ ERROR: Time limit exceeded
    โ€‹โ€‹โ€‹โ€‹ddl@raspberrypi:~/lab0-c $ make clean all test
    โ€‹โ€‹โ€‹โ€‹...
    โ€‹โ€‹โ€‹โ€‹+++ TESTING trace trace-13-perf:
    โ€‹โ€‹โ€‹โ€‹# Test performance of insert_tail
    โ€‹โ€‹โ€‹โ€‹ERROR: Time limit exceeded.  Either you are in an infinite loop, or your code is too inefficient
    โ€‹โ€‹โ€‹โ€‹ERROR: Insertion of dolphin failed (1 failures total)
    โ€‹โ€‹โ€‹โ€‹---     trace-13-perf   0/7
    โ€‹โ€‹โ€‹โ€‹...
    
  • ไฝฟ็”จ grade.sh ๅˆ†ๅˆฅไปฅ -O0, -O1, -O2, -O3 ๆธฌ่ฉฆ 10 ๆฌกไธฆ่จˆ็ฎ—ๅนณๅ‡ๅˆ†ๆ•ธ (timeout 10 ็ง’ total = 0)
    • VM ็’ฐๅขƒ
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹ddl@xubuntu:~/Desktop/sysprog/lab0-c$ ./grade.sh
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹-O0 grade: 100
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹-O1 grade: 100
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹-O2 grade: 100
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹-O3 grade: 100
      
    • RPi ็’ฐๅขƒ
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹ddl@raspberrypi:~/lab0-c $ ./grade.sh
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹-O0 grade: 23
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹-O1 grade: 98
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹-O2 grade: 98
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹-O3 grade: 99