diff options
Diffstat (limited to 'labs/datalab/datalab-handout')
| -rw-r--r-- | labs/datalab/datalab-handout/Driverhdrs.pm | 12 | ||||
| -rw-r--r-- | labs/datalab/datalab-handout/Driverlib.pm | 138 | ||||
| -rw-r--r-- | labs/datalab/datalab-handout/Makefile | 24 | ||||
| -rw-r--r-- | labs/datalab/datalab-handout/README | 140 | ||||
| -rw-r--r-- | labs/datalab/datalab-handout/bits.c | 360 | ||||
| -rw-r--r-- | labs/datalab/datalab-handout/bits.h | 31 | ||||
| -rw-r--r-- | labs/datalab/datalab-handout/btest.c | 583 | ||||
| -rw-r--r-- | labs/datalab/datalab-handout/btest.h | 32 | ||||
| -rw-r--r-- | labs/datalab/datalab-handout/decl.c | 57 | ||||
| -rwxr-xr-x | labs/datalab/datalab-handout/driver.pl | 439 | ||||
| -rw-r--r-- | labs/datalab/datalab-handout/fshow.c | 151 | ||||
| -rw-r--r-- | labs/datalab/datalab-handout/ishow.c | 75 | ||||
| -rw-r--r-- | labs/datalab/datalab-handout/tests.c | 118 |
13 files changed, 2160 insertions, 0 deletions
diff --git a/labs/datalab/datalab-handout/Driverhdrs.pm b/labs/datalab/datalab-handout/Driverhdrs.pm new file mode 100644 index 0000000..ecf5e2a --- /dev/null +++ b/labs/datalab/datalab-handout/Driverhdrs.pm @@ -0,0 +1,12 @@ +# +# 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; diff --git a/labs/datalab/datalab-handout/Driverlib.pm b/labs/datalab/datalab-handout/Driverlib.pm new file mode 100644 index 0000000..d7f7da1 --- /dev/null +++ b/labs/datalab/datalab-handout/Driverlib.pm @@ -0,0 +1,138 @@ +############################################################### +# 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; + diff --git a/labs/datalab/datalab-handout/Makefile b/labs/datalab/datalab-handout/Makefile new file mode 100644 index 0000000..ca4bcf0 --- /dev/null +++ b/labs/datalab/datalab-handout/Makefile @@ -0,0 +1,24 @@ +# +# Makefile that builds btest and other helper programs for the CS:APP data lab +# +CC = gcc +CFLAGS = -O -Wall +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 *~ diff --git a/labs/datalab/datalab-handout/README b/labs/datalab/datalab-handout/README new file mode 100644 index 0000000..e73d37f --- /dev/null +++ b/labs/datalab/datalab-handout/README @@ -0,0 +1,140 @@ +*********************** +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) + + + diff --git a/labs/datalab/datalab-handout/bits.c b/labs/datalab/datalab-handout/bits.c new file mode 100644 index 0000000..3cd1d3d --- /dev/null +++ b/labs/datalab/datalab-handout/bits.c @@ -0,0 +1,360 @@ +/* + * 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 +//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) { + /* + (x and not y) or (y and not x) <=> + ~(~(x and not y) & ~(y and not x)) + */ + int x_and_not_y = x & ~y; + int y_and_not_x = y & ~x; + int x_not_y_or_y_not_x = ~x_and_not_y & ~y_and_not_x; + return ~x_not_y_or_y_not_x; +} +/* + * tmin - return minimum two's complement integer + * Legal ops: ! ~ & ^ | + << >> + * Max ops: 4 + * Rating: 1 + */ +int tmin(void) { + return 1<<(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) { + return !!(~0 ^ x) & !(~(x + 1) ^ 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 odd_bits_mask = 0xAA; + odd_bits_mask |= odd_bits_mask << 16; + odd_bits_mask |= odd_bits_mask << 8; + return !((x & odd_bits_mask) ^ odd_bits_mask); +} +/* + * 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 ret = (x + 6) >> 4; + ret &= !(ret ^ 3) & !((x>>4) ^ 3) & !(x>>31); + return ret; +} +/* + * 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) { + /* All ones if x is zero, all zeroes otherwise */ + int mask = (!(x ^ 0) << 31) >> 31; + return (y & ~mask) | (z & mask); +} +/* + * 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 int_min = (1<<31); + int x_is_min = !(x ^ int_min); + int x_is_pos = !(x & int_min); + int y_is_pos = !(y & int_min); + + return (!x_is_pos & y_is_pos) + | x_is_min + | !((y + (~x + 1)) & int_min); +} +//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) { + /* Using arithmetic shift */ + int sign_bit = x >> 31; + int neg_sign_bit = (~x + 1) >> 31; + return (sign_bit | neg_sign_bit) + 1; + + /* Naive approach */ + /* x |= x>>16; */ + /* x |= x>>8; */ + /* x |= x>>4; */ + /* x |= x>>2; */ + /* x |= x>>1; */ + /* return (x & 1) ^ 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) { + /* My original solution was a lot messier */ + int sign_bit = (x>>31); + int b16, b8, b4, b2, b1, b0; + + /* Take the number that is encoded by the positive bits */ + int u = (x & ~sign_bit) | (~x & sign_bit); + + /* unsigned u = x; */ + /* any greater than 16? */ + /* + 0000 000C + 0000 000C + 0000 000C + 0000 0003 + 0000 0001 + + */ + b16 = (!!(u>>16))<<4; + u >>= b16; + + b8 = (!!(u>>8))<<3; + u >>= b8; + + b4 = (!!(u>>4))<<2; + u >>= b4; + + b2 = (!!(u>>2))<<1; + u >>= b2; + + b1 = (!!(u>>1)); + u >>= b1; + + b0 = !!u; + return b16 + b8 + b4 + b2 + b1 + b0 + 1; +} +//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) { + return 2; +} +/* + * 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) { + return 2; +} +/* + * floatPower2 - Return bit-level equivalent of the expression 2.0^x + * (2.0 raised to the power x) for any 32-bit integer x. + * + * The unsigned value that is returned should have the identical bit + * representation as the single-precision floating-point number 2.0^x. + * If the result is too small to be represented as a denorm, return + * 0. If too large, return +INF. + * + * Legal ops: Any integer/unsigned operations incl. ||, &&. Also if, while + * Max ops: 30 + * Rating: 4 + */ +unsigned floatPower2(int x) { + return 2; +} diff --git a/labs/datalab/datalab-handout/bits.h b/labs/datalab/datalab-handout/bits.h new file mode 100644 index 0000000..de2685a --- /dev/null +++ b/labs/datalab/datalab-handout/bits.h @@ -0,0 +1,31 @@ +//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); +unsigned floatPower2(int); +unsigned test_floatPower2(int); diff --git a/labs/datalab/datalab-handout/btest.c b/labs/datalab/datalab-handout/btest.c new file mode 100644 index 0000000..660072e --- /dev/null +++ b/labs/datalab/datalab-handout/btest.c @@ -0,0 +1,583 @@ +/* + * 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; +} diff --git a/labs/datalab/datalab-handout/btest.h b/labs/datalab/datalab-handout/btest.h new file mode 100644 index 0000000..a011bc1 --- /dev/null +++ b/labs/datalab/datalab-handout/btest.h @@ -0,0 +1,32 @@ +/* + * 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[]; + + + + + + + diff --git a/labs/datalab/datalab-handout/decl.c b/labs/datalab/datalab-handout/decl.c new file mode 100644 index 0000000..11370c7 --- /dev/null +++ b/labs/datalab/datalab-handout/decl.c @@ -0,0 +1,57 @@ +#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[] = { +//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}}}, + {"floatPower2", (funct_t) floatPower2, (funct_t) test_floatPower2, 1, + "$", 30, 4, + {{1, 1},{1,1},{1,1}}}, + {"", NULL, NULL, 0, "", 0, 0, + {{0, 0},{0,0},{0,0}}} +}; diff --git a/labs/datalab/datalab-handout/driver.pl b/labs/datalab/datalab-handout/driver.pl new file mode 100755 index 0000000..143c440 --- /dev/null +++ b/labs/datalab/datalab-handout/driver.pl @@ -0,0 +1,439 @@ +#!/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"); +} + diff --git a/labs/datalab/datalab-handout/fshow.c b/labs/datalab/datalab-handout/fshow.c new file mode 100644 index 0000000..fc918f6 --- /dev/null +++ b/labs/datalab/datalab-handout/fshow.c @@ -0,0 +1,151 @@ +/* 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; +} + + diff --git a/labs/datalab/datalab-handout/ishow.c b/labs/datalab/datalab-handout/ishow.c new file mode 100644 index 0000000..ffb1df7 --- /dev/null +++ b/labs/datalab/datalab-handout/ishow.c @@ -0,0 +1,75 @@ +/* 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; +} + + + diff --git a/labs/datalab/datalab-handout/tests.c b/labs/datalab/datalab-handout/tests.c new file mode 100644 index 0000000..38eb9c6 --- /dev/null +++ b/labs/datalab/datalab-handout/tests.c @@ -0,0 +1,118 @@ +/* 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; +} + +//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; +} +unsigned test_floatPower2(int x) { + float result = 1.0; + float p2 = 2.0; + int recip = (x < 0); + /* treat tmin specially */ + if ((unsigned)x == 0x80000000) { + return 0; + } + if (recip) { + x = -x; + p2 = 0.5; + } + while (x > 0) { + if (x & 0x1) + result = result * p2; + p2 = p2 * p2; + x >>= 1; + } + return f2u(result); +} |
