CSE 30: pamt1 (Programming Assignment Multi
Transcription
CSE 30: pamt1 (Programming Assignment Multi
CSE 30: pamt1 (Programming Assignment Multi- Threading 1) and debug1 (Debugging Exercise) Due Tuesday night, November 18th @ 11:59pm The purpose of this mini-assignment is to gently introduce you to parallel programming and multithreading; covering aspects of implementation, benefits and the tradeoffs involved. Provided with skeleton code, you will fill in the functionality where necessary to calculate the squared sum, min and max of a very large array of numbers, both in parallel over many threads simultaneously, and sequentially in one. The program will also record and display the execution time of the calculations using both methods, allowing you to see the relative performance of each. NOTE: Due to the number of classes that use ieng9 and the CPU-intensive nature of this assignment, we are not developing or running the multi-threaded programming assignment on ieng9! Instead we will be using the workstations in the labs in the basement of the CSE building. See the section on Getting the Code for more details on how to set up the repository on the workstation. You will also be given a chance to practice your debugging skills. We've written a program that will read in strings from the command line, reverse the string, and determine whether each string is a palindrome (the same string forward and backward). We think it's close to working, but we didn't have time to debug it. It's your job to help us track down the bugs and fix it up so we can get to work reversing strings. The debugging exercise will be completed on ieng9. In summary: 1) pamt1 will be developed and executed and turned in with your cs30x account on the workstations in the lab (preferred) or ieng6.ucsd.edu remotely. 2) debug1 will be debugged and executed and turned in with your cs30x account on ieng9.ucsd.edu. Grading Breakdown PAMT1 README: 10 points See "PAMT1 README File" section Compiling: 10 points Using our Makefile; no warnings, more details below. Correctness: 40 points Includes both abnormal and normal output, both to the correct destination (stderr vs stdout). debug1 (Debugging Exercise) README: 30 points See "Debug README File" section Correctness: 10 points NOTE: If what you turn in does not compile, you will receive 0 points for this assignment. The files you turn in must compile with the supplied Makefiles , in order for your programming assignment to be graded. The provided Makefile for PAMT1 is included in the git repository which you will clone to your cs30x account. Description of Assignment Click on each of the links below to access different parts of this assignment. 1. PAMT1 Overview 2. PAMT1 Example Output 3. PAMT1 "cpp" Modules 4. PAMT1 README File 5. Debug Overview 6. Debug Example Output 7. Debug C Modules 8. Debug Assembly Modules 9. Debug README File 10. Getting the Code 11. Turnin Instructions 12. Style Requirements START EARLY! CSE 30 Homepage CSE 30 PAMT1 PAMT1 Main 1. PAMT1 Overview 2. PAMT1 Example Output 3. PAMT1 "cpp" Modules 4. PAMT1 README File pamt1: Overview All functions for pamt1 will be written in C++ (really most of it is C, but there are some multi-threading calls that require C++). We will provide a git repository from which you will clone the starter code. Note that all development and running of pamt1 must take place on the workstations in the labs or on ieng6. Do not develop/run this programming assignment on ieng9. 5. Debug Overview One file (initData.cpp) is provided in its entirety for you, while another (main.cpp) has 6. Debug Example Output most of the code, with small additions that you are required to make. The one file you are 7. Debug C Modules expected to create from scratch is sequentialSquaredSumMinMax.cpp. The function 8. Debug Assembly Modules prototypes for the functions are as follows, which should be included in your pamt1.h: 9. Debug README File 10. Getting the Code 11. Turnin Instructions C routines 12. Style Requirements int main( int argc, char* argv[] ); void initData( char a[], int size ); struct result sequentialSquaredSumMinMax( char a[], int lo, int hi ); The pamt1.h header file, which is included in the git repository you will clone, contains the following: the function prototypes (above) the definition of struct result const int numOfThreads, a constant to determine the number of threads the program will spawn The definition for struct result should be as follows: struct result { long long sum; int min; int max; }; CSE 30 PAMT1 PAMT1 Main 1. PAMT1 Overview 2. PAMT1 Example Output 3. PAMT1 "cpp" Modules 4. PAMT1 README File 5. Debug Overview pamt1: Example Output The program takes a single argument from the command line: % squaredSumMinMax array_size This input, array_size, is the size of the array that will be initialized with random values and then have its squared sum, min and max calculated, sequentially in one thread and then in parallel over multiple. 6. Debug Example Output 7. Debug C Modules 8. Debug Assembly Modules 9. Debug README File 10. Getting the Code 11. Turnin Instructions 12. Style Requirements Below are a few examples (bold indicates what you type): % ./squaredSumMinMax 8675309 Initializing array (size = 8675309) with random values . Done Sequential squared sum, min, max (be patient) Squared Sum is: 47210683345 Min value is: -128 Max value is: 127 Completed in 0.023576 sec Async-get parallel squared sum, min, max Number of threads = 4 Squared Sum is: 47210683345 Min value is: -128 Max value is: 127 Completed in 0.006654 sec Speed-up: 3.543132 The output should be fairly self-explanatory. Something important to note is that the first group of results is for sequential mode (running all of the calculations on the array in a single thread all at once), while the second group of results is for parallel mode (dividing up the array into subarrays, launching a bunch of threads and having each one process one subarray, and then combining all of the results back together in the main thread). You should also note the number of threads in the second group. This output was generated on a workstation in B260 which supports 4 concurrent threads. This result was determined by calling the std::thread::hardware_concurrency C++ library function (the numThreads constant from pamt1.h). The program uses that number to decide how many subarrays to divide the array into for parallel computation. The speedup is the factor by which parallel computation of the result is faster than sequential. A speedup of 1 would mean that both methods are about equally fast, while a speedup of less than 1 would indicate that the sequential mode is better, and a speedup of greater than 1 would indicate that the parallel mode is better. As you can see, for an array of this size on this machine, it was approximately 3.5 times faster to calculate the solution in parallel. Here is another example. Nothing too different, just slightly different numbers. % ./squaredSumMinMax 987654321 Initializing array (size = 987654321) with random values ......................... Done Sequential squared sum, min, max (be patient) Squared Sum is: 5378110202388 Min value is: -128 Max value is: 127 Completed in 2.690250 sec Async-get parallel squared sum, min, max Number of threads = 4 Squared Sum is: 5378110202388 Min value is: -128 Max value is: 127 Completed in 0.717829 sec Speed-up: 3.747759 CSE 30 PAMT1 PAMT1 Main 1. PAMT1 Overview 2. PAMT1 Example Output 3. PAMT1 "cpp" Modules 4. PAMT1 README File pamt1: "cpp" Modules (1) main.cpp Function prototype: int main( int argc, char *argv[] ); 5. Debug Overview The driver of the program. Will take the array_size argument from 6. Debug Example Output the command line and convert it to long using strtol. It will then 7. Debug C Modules malloc an array of that size and pass a reference to it and the size to 8. Debug Assembly Modules initData which will populate the array with psuedo-random numbers. 9. Debug README File 10. Getting the Code 11. Turnin Instructions 12. Style Requirements When initData returns, main calls gettimeofday to get the start time, and then calls sequentialSquaredMinMax to run the calculations sequentially. Upon return, gettimeofday is called again to get the end time. The time difference is then calculated and the results of the sequential run are printed to stdout. Everything up to this point is given to you in the starter code. Next, we will partition the array into N separate pieces, where N = # of threads supported by the machine (you can use the numOfThreads constant defined in pamt1.h) and create N - 1 new threads (the Nth thread is just main). An array of result structs is then created to store the results of the subarray calculations and a thread is launched to work on each part of the array, each calling sequentialSquaredSumMinMax with low (inclusive) and high (exclusive) array index arguments that define the boundaries that each thread is operating on, and each returning its results into the array of result structs. You will have to calculate the partition size and fill in the calls to sequentialSquaredSumMinMax() with the appropriate arguments. Now the results need to be combined. The program should iterate through the array of struct results, sum up all of the squared sums and determine the min and max values of the entire array. The results should be saved in a struct result. It is your responsibility to implement the functionality just described in this paragraph. gettimeofday is called before the parallel computations begin and again after they are completed. The time difference and the speedup are then calculated, and the results of the parallel run are printed to stdout. Note: There are several comments marked TODO in main.cpp that show you where you should make additions/changes. You do not need to (and in fact should not) make changes to main.cpp anywhere except at these points. (2) initData.cpp Function prototype: void initData( char a[], int size ); Populates the array passed in from main with random numbers. This entire function is provided for you. (3) sequentialSquaredSumMinMax.cpp Function prototype: struct result sequentialSquaredSumMinMax( char a[], int lo, int hi ); sequentialSquaredSumMinMax takes a reference to the array defined in main, and low and high indexes. It should then iterate through each element, from lo to hi (inclusive of lo, but exclusive of hi) and calculate the squared sum (the sum of the square of each element), and determine the minimum and maximum values in sequence. When calculating the square of each element, do not use pow(), since result of the function call will return a double value instead of an integer, which may later cause unncessary error due to rounding off errors. The results will be saved in a struct result and returned to the caller. It is your responsibility to implement all of the functionality just described. CSE 30 PAMT1 PAMT1 Main pamt1: README File Your README file for this and all assignments should contain: 1. PAMT1 Overview High level description of what your program does. 2. PAMT1 Example Output How to compile it (usually just typing "make"). 3. PAMT1 "cpp" Modules How to run it (give an example). 4. PAMT1 README File An example of normal output and where that normal output 5. Debug Overview goes (stdout or a file or ???). 6. Debug Example Output An example of abnormal/error output and where that error 7. Debug C Modules output goes (stderr usually). 8. Debug Assembly Modules How you tested your program (what test values you used to test 9. Debug README File normal and error states) showing your tests covered all parts of 10. Getting the Code your code (test coverage). 11. Turnin Instructions Anything else that you would want/need to communicate with 12. Style Requirements someone who has not read the assignment write-up but may want to compile and run your program. Refer to the templates provided on Piazza if you are unsure how your README should look. You should also answer the following questions: 1. Try running your program with an array size of 500000000 (that's 500 million). You should notice a fairly substantial speedup of somewhere between 3.5 and 4. Now try running it with an array size of 500 -- the speedup is tiny, less than .01, meaning the sequential computation was much faster than parallel. Why is the sequential computation so much faster for small array sizes? 2. So parallel processing is better for very large arrays, and sequential is better for small arrays. Try out some more values for the array size. At approximately what array size do the parallel and sequential calculations take the same time -- that is, at what size is the speedup approximately 1? (This doesn't have to be exact, just a ballpark number). CSE 30 debug1 Debugging Exercise debug1 Debugging Exercise: Overview The purpose of this program is to read in all strings from the PAMT1 Main 1. PAMT1 Overview 2. PAMT1 Example Output 3. PAMT1 "cpp" Modules 4. PAMT1 README File 5. Debug Overview 6. Debug Example Output 7. Debug C Modules 8. Debug Assembly Modules 9. Debug README File command line and find the reverse of that string. The main() function is written in C, and it will find the reverse of the string with help from several assembly functions. We provide all of the code to you (See the section on Getting the Code for more details), but the code doesn't quite compile or work as it should. It is up to you to track down the bugs and fix them. You'll also need to record all of the bugs you found and the solution for each bug. See the section on Debug README File for more details. C routines 10. Getting the Code 11. Turnin Instructions int main( int argc, char* argv[] ); 12. Style Requirements Assembly routines int reverse( char* str ); int findEnd( char* str, char** endPtr ); int swapChars( char* c1, char* c2 ); CSE 30 debug1 Debugging Exercise debug1 Debugging Exercise: Example Output The program takes one or more string arguments from the command line. % reverseString str1 [str2 str3 ...] Each string will be printed to the screen, then reversed and printed to the screen again. If the string is a palindrome, the program will print a message saying so. At the end, the program prints the total number of palindromes found. PAMT1 Main 1. PAMT1 Overview 2. PAMT1 Example Output 3. PAMT1 "cpp" Modules 4. PAMT1 README File Below are a few examples (bold indicates what you type): 6. Debug Example Output % ./reverseString potatoes Before: potatoes After: seotatop 7. Debug C Modules You found 0 palindrome(s) 5. Debug Overview 8. Debug Assembly Modules 9. Debug README File 10. Getting the Code 11. Turnin Instructions 12. Style Requirements As you can see, the string entered on the command line is printed out, then reversed and printed out again. Let's see what happens if it's a palindrome... % ./reverseString amanaplanacanalpanama Before: amanaplanacanalpanama PALINDROME! After: amanaplanacanalpanama You found 1 palindrome(s) This string is the same forward and backward, so we let the user know (with a triumphant PALINDROME!). We also print the number of palindromes found. (Note: we're not quite fancy enough to deal with spaces and punctuation, so the well-known palindrome "a man, a plan, a canal: Panama" won't work). Now let's try entering several strings: % ./reverseString abba was a band with some serious wow factor Before: abba PALINDROME! After: abba Before: was After: saw Before: a PALINDROME! After: a Before: band After: dnab Before: with After: htiw Before: some After: emos Before: serious After: suoires Before: wow PALINDROME! After: wow Before: factor After: rotcaf You found 3 palindrome(s) Aside from declaring my love for ABBA, this example shows what happens when several strings are entered on the command line, including some palindromes. We can also enclose strings in quotes if we want to include spaces: % ./reverseString "I've always wanted to know how to spell my name in reverse" "George Washington" Before: I've always wanted to know how to spell my name in reverse After: esrever ni eman ym lleps ot woh wonk ot detnaw syawla ev'I Before: George Washington After: notgnihsaW egroeG You found 0 palindrome(s) % ./reverseString "I was a saw I" "semolina is no meal" "---uuu-^U^-uuu---" "four score and seven years ago" Before: I was a saw I PALINDROME! After: I was a saw I Before: semolina is no meal After: laem on si anilomes Before: ---uuu-^U^-uuu--PALINDROME! After: ---uuu-^U^-uuu--Before: four score and seven years ago After: oga sraey neves dna erocs ruof You found 2 palindrome(s) CSE 30 debug1 Debugging Exercise debug1 Debugging Exercise: C Modules (1) main.c PAMT1 Main 1. PAMT1 Overview 2. PAMT1 Example Output 3. PAMT1 "cpp" Modules 4. PAMT1 README File 5. Debug Overview 6. Debug Example Output 7. Debug C Modules 8. Debug Assembly Modules 9. Debug README File 10. Getting the Code 11. Turnin Instructions 12. Style Requirements Function prototype: int main( int argc, char *argv[] ); The only C module of this program. Loops through all command line arguments in argv[]. It first prints the original string, then calls reverse() on it and prints the reversed string. If the string was a palindrome, a counter is incremented. When all strings have been read and reversed, a message is printed showing the total number of palindromes. CSE 30 debug1 Debugging Exercise debug1 Debugging Exercise: Assembly Modules (1) reverse.s PAMT1 Main 1. PAMT1 Overview 2. PAMT1 Example Output 3. PAMT1 "cpp" Modules 4. PAMT1 README File 5. Debug Overview 6. Debug Example Output 7. Debug C Modules 8. Debug Assembly Modules 9. Debug README File 10. Getting the Code 11. Turnin Instructions 12. Style Requirements Function prototype: int reverse( char* str ); The primary purpose of this function is to reverse the character array pointed to by str. It does this by finding the length of the string and a pointer to the last character of the string (using findEnd()) and then looping through all characters in the string, simultaneously incrementing the pointer at the front and decrementing the pointer at the back and swapping the characters. If the characters were the same (as returned by swapChars()), this function will keep track of that. If all characters that were swapped were the same, this function will print a message ("PALINDROME!") and will return 1. Otherwise, it will not print any message and will return 0. (2) findEnd.s Function prototype: int findEnd( char* str , char** endPtr ); This function has two purposes: to find the length of the string str and to set endPtr to point to the last character of the string. It does this simply by iterating through the string and checking whether the character is the null character, keeping a count of how many characters were seen. Once it finds the end of the string, it stores the pointer to the last character in endPtr and returns the length of the str. (3) swapChars.s Function prototype: int swapChars( char* c1 , char* c2 ); Swaps the values of the two characters pointed to by c1 and c2. Determines if the characters were the same and, if so, if they were in fact the same character in the string (i.e. the addresses were the same). If the characters were different, returns 0. If they were the same but the addresses were also the same, returns 1. If they were the same and the addresses were different, returns 2. CSE 30 debug1 Debugging Exercise debug1 Debugging Exercise: README File For the debugging assignment only, you do not have to include the PAMT1 Main 1. PAMT1 Overview 2. PAMT1 Example Output 3. PAMT1 "cpp" Modules 4. PAMT1 README File 5. Debug Overview 6. Debug Example Output 7. Debug C Modules 8. Debug Assembly Modules 9. Debug README File 10. Getting the Code 11. Turnin Instructions 12. Style Requirements usual high level description, how tested, etc. You will, however, have to list each of the compilation errors you encountered and the fix you made to correct the error (include the compilation error, the file name, the line number, and the new code). You will also have to solve several runtime errors. Some of them will be obvious (for example, Bus Error), but some will involve a little more testing and debugging. Again, for each problem, describe the error and describe your solution for fixing it, including the file name, line number, and code for your fix. As a guideline, there should be 2 compilation errors and 6 runtime/functionality problems. (Note: When we say there are 2 compilation errors, we mean that there are two fixes you'll have to make, not that there are two errors that are printed to the screen). CSE 30 PAMT1 PAMT1 Main 1. PAMT1 Overview 2. PAMT1 Example Output 3. PAMT1 "cpp" Modules 4. PAMT1 README File 5. Debug Overview 6. Debug Example Output 7. Debug C Modules 8. Debug Assembly Modules 9. Debug README File 10. Getting the Code 11. Turnin Instructions 12. Style Requirements Getting the Code PAMT1 Unlike previous assignments, there is a git repository already set up -you just have to clone the repository into your class account on a workstation in the basement or on ieng6. You should not do this assignment on ieng9. To clone a local copy, follow these steps: 1. Log in to a workstation in the basement and open a terminal 2. Clone the repository with the following command: git clone ieng9.ucsd.edu:../public/git/pamt1.git At this point you'll be prompted for a password -- just use the password you normally use to log in to ieng9. You should now have a directory named pamt1. This will contain the starter code for the project, including main.cpp, initData.cpp, and pamt1.h. You are responsible for filling in some code in main.cpp and creating the file sequentialSquaredSumMinMax.cpp. debug1 (Debugging Exercise) For debug1 (the debugging exercise), you will develop on ieng9 as you do for most programming assignments. However, we will provide you with the buggy code. Simply go to your home directory and copy the whole folder to your home directory: $ cd $ cp -r ~/../public/debug1 . This will provide you with all of the buggy source code. All you have to do is fix the code and detail in a README file exactly what fixes you had to make to get this code to work properly - line numbers, what the line looked before and after your fix, etc. Be sure to include a short explanation of how you debugged each problem. See the section on Debug README File for more details. CSE 30 PAMT1 PAMT1 Main 1. PAMT1 Overview 2. PAMT1 Example Output 3. PAMT1 "cpp" Modules 4. PAMT1 README File 5. Debug Overview 6. Debug Example Output 7. Debug C Modules 8. Debug Assembly Modules 9. Debug README File 10. Getting the Code 11. Turnin Instructions 12. Style Requirements Turnin Turn In, Due Tuesday Night, November 18th @ 11:59pm For both PAMT1 and debug1 (the debugging exercise), use the CSE 30 local turnin program to turn in all source files, the Makefile, and your README. 1) For pamt1, you will need to run turnin pamt1 in your cs30x account on the lab workstations of ieng6. You will not be able to turnin pamt1 on ieng9. 2) For debug1 (the debugging exercise), you will need to run turnin debug1 in your cs30x acoount on ieng9. You will not be able to turnin debug1 on ieng6. CSE 30 PAMT1 pamt1: Style Requirements PAMT1 Main You will be graded for the style of programming on all the 1. PAMT1 Overview 2. PAMT1 Example Output 3. PAMT1 "cpp" Modules assignments. A few suggestions/requirements for style are given below. Read carefully, and if any of them need clarification do not hesitate to ask. 4. PAMT1 README File Use reasonable comments to make your code clear and 5. Debug Overview readable. 6. Debug Example Output Use file headers and function header blocks to describe the 7. Debug C Modules purpose of your programs and functions. Sample file/function 8. Debug Assembly Modules headers are provided with PA0. 9. Debug README File Explicitly comment all the various registers that you use in your 10. Getting the Code assembly code. 11. Turnin Instructions In the assembly routines, you will have to give high level 12. Style Requirements comments for the synthetic instructions, specifying what the instruction does. You should test your program to take care of invalid inputs like nonintegers, strings, no inputs, etc. This is very important. Points will be taken off if your code doesn't handle exceptional cases of inputs. Use reasonable variable names. Error output goes to stderr. Normal output goes to stdout. Use #defines and assembly constants to make your code as general as possible. Use a local header file to hold common #defines, function prototypes, type definitions, etc., but not variable definitions. Judicious use of blank spaces around logical chunks of code makes your code much easier to read and debug. Keep all lines less than 80 characters, split long lines if necessary. Use 2-4 spaces for each level of indenting in your C source code (do not use tab). Be consistent. Make sure all levels of indenting line up with the other lines at that level of indenting. Do use tabs in your Assembly source code. Always recompile and execute your program right before turning it in just in case you commented out some code by mistake. Before running turnin please do a make clean in your project directory. Do #include only the header files that you need and nothing more. Always macro guard your header files (#ifndef ... #endif). Never have hardcoded magic numbers. This means we shouldn't see magic constants sitting in your code. Use a #define if you must instead.