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.