PAMT2/Debug2

Programming Assignment Multi-Threading and Debugging 2
Due Date: Friday night, May 29 @ 11:59pm
Overview:
The purpose of this mini-assignment is to continue your introduction to parallel programming and multithreading, covering aspects of implementation, benefits and the tradeoffs involved. You will again be provided
with skeleton code, and this time you will fill in the functionality where necessary to determine whether a large
number is prime or not, 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: Once again, due to the number of classes that use ieng9 and the CPU-intensive nature of this
assignment, we are developing and running the multi-threaded programming assignment on the
workstations or ieng6! See the section on Getting the Code for more details on how to set up the repository
on the workstation.
You also get to practice your debugging skills again. We've written a program that will read in a string from the
command line and count the characters in the string. 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. You should reference
your notes on static vs. global to help you finish this assignment. The debugging exercise will be
completed on ieng9.
In summary:
1) pamt2 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) debug2 will be debugged and executed and turned in with your cs30x account on ieng9.ucsd.edu.
Grading:
PAMT 2
README: 10 points
See "PAMT 2 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).
Debug 2
README: 30 points
See "Debug README File" section
Correctness: 10 points
NOTE: If what you turn in does not compile with given Makefile, you will receive 0 points for this assignment.
PAMT 2 Overview
Once again, all functions for pamt2 are written in C++. We provide a git repository from which you will clone the
starter code. Your job is to fill in the missing functionality. Note that all development and running of pamt2 must
take place on the workstations in the labs or on ieng6. Do not develop/run this programming assignment on
ieng9.
The pamt2.h header file, which is included in the git repository you will clone, contains the following:
- the function prototypes
- const int numOfThreads, a constant to determine the number of threads the program will spawn
C++ routines
int main( int argc, char* argv[] );
bool isPrime( long long n, long long lo, long long hi );
Getting the Code for PAMT 2
Like pamt1, there is a git repository already set up containing starter code -- you just have to clone the
repository into your class account on a workstation in the basement or on ieng6.
Follow the following steps to clone the repository:
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/pamt2.git
You should now have a directory named pamt2. This will contain the starter code for the project, including
main.cpp, isPrime.cpp and pamt2.h. You are responsible for filling in some code in main.cpp,as well as the
bulk of isPrime.cpp.
PAMT 2 Example Output
This program takes a list of long long integers (64 bit numbers, up to about 9 quintillion in decimal) and
displays information on whether each number is prime and how long it took to determine that.
Below are a few examples (bold indicates user input):
[cs30xyz]:pamt2$ ./isPrime 8081 246813607
Number of threads = 8
Sequential isPrime for 8081
8081 is prime
Completed in 2e-06 sec
Async-get parallel isPrime for 8081
8081 is prime
Completed in 0.000898 sec
Speed-up: 0.00222717
--------------
Sequential isPrime for 246813607
246813607 is prime
Completed in 5e-05 sec
Async-get parallel isPrime for 246813607
246813607 is prime
Completed in 0.00018 sec
Speed-up: 0.277778
-------------[cs30xyz]:pamt2$ ./isPrime 790738119649411319
Number of threads = 8
Sequential isPrime for 790738119649411319
790738119649411319 is prime
Completed in 3.52902 sec
Async-get parallel isPrime for 790738119649411319
790738119649411319 is prime
Completed in 0.892324 sec
Speed-up: 3.95487
-------------[cs30xyz]:pamt2$ ./isPrime 6312646216567629137
Number of threads = 8
Sequential isPrime for 6312646216567629137
6312646216567629137 is prime
Completed in 11.037 sec
Async-get parallel isPrime for 6312646216567629137
6312646216567629137 is prime
Completed in 2.68558 sec
Speed-up: 4.10972
-------------[cs30xyz]:pamt2$ ./isPrime 9223372036854775783
Number of threads = 8
Sequential isPrime for 9223372036854775783
9223372036854775783 is prime
Completed in 11.5436 sec
Async-get parallel isPrime for 9223372036854775783
9223372036854775783 is prime
Completed in 2.7456 sec
Speed-up: 4.2044
--------------
Note that the first group of results for each number is for sequential mode (checking each possible factor of the
number in sequence in a single thread), while the second group of results is for parallel mode (dividing up the
possible factors into ranges, launching a number of threads that each check a range of factors, and then
checking the return value from each thread).
Like last time, 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 (the overhead of forking and joining threads can dominate small
problems), and a speedup of greater than 1 would indicate that the parallel mode is better. Your output might
not be exactly the same as the sample output, but it should look reasonable and justifiable.
Here are some large numbers for you to test your program’s correctness and speed-up:
489133282872437277
// not prime; sequential performs better
87178291199
70368760954879
688846502588399
32361122672259149
489133282872437279
790738119649411319
6312646216567629137
9223372036854775783
PAMT 2 Modules
1. main.cpp
int main( int argc, char* argv[] );
The driver of the program. For each number entered on the command line, main() calls gettimeofday() to
get the start time, and then calls isPrime() 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 factor range into N separate pieces, where N = # of threads supported by the
machine (you can use the numOfThreads constant defined in pamt2.h) and create N - 1 new threads (the Nth
thread is just main). An array of bools is then created to store the results of the calculations for each partition
and a thread is launched to work on each part of the factor range, each calling isPrime() with low (inclusive)
and high (exclusive) factor arguments that define the boundaries that each thread is operating on, and each
returning its result into the array of bools. You will have to calculate the partition size and fill in the call to
isPrime() with the appropriate arguments.
Now the results need to be combined. The program should iterate through the array of bools, checking the
values returned by each thread's call to isPrime(). If any returned false, set a variable to indicate that the
number is not prime and then break out of the loop. If all parallel calls to isPrime() returned true, then the
number is prime and you should set the relevant variable accordingly. It is your responsibility to implement the
functionality 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. isPrime.cpp
bool isPrime( long long n, long long lo, long long hi );
isPrime() takes the number n which we are checking to the primality of, lo which is the low (inclusive) range
of possible factors to check, and hi which is the high (exclusive) range of possible factors to check. The
general algorithm is that it will iterate through each factor from lo to hi (inclusive of lo, but exclusive of hi),
iterating by two each time, and returning false if any factors evenly divide into n. If you make it through the
range of factors without returning false, then return true. For the full details regarding the algorithm you must
implement, refer to the comments in the provided isPrime.cpp file. It is your responsibility to implement all of
the functionality as described there.
PAMT 2 README File
Along with your source code, you will be turning in a README (use all caps and no file extension for example,
the file is README and not README.txt) file with every assignment. Use vi/vim to edit this file!
Your README file for this and all assignments should contain:
- Header with your name, cs30x login
- High level description of what your program does
- How to compile it (usually just typing "make")
- How to run it (give an example)
- An example of normal output and where that normal output goes (stdout or a file or ???)
- An example of abnormal/error output and where that error output goes (stderr usually)
- How you tested your program
- Anything else that you would want/need to communicate with someone who has not read the writeup
- Answers to questions (if there are any)
Questions to Answer for the README
1. Try running isPrime on the very large prime number 426110284379068259. You should see that the
sequential version takes much longer than the parallel version. What results do you see when you run isPrime
on the nearby composite number 426110284379068249?
2. How do you explain the results from the previous question? (It may be useful to know that
426110284379068249 = 653,947,933 * 651,596,653 and that the square root of 426110284379068249 =
652,771,234).
3. Now try running isPrime on another nearby composite 426110284379068257. What results do you see this
time?
4. How do you explain those results? (It may be useful to know that 426110284379068257 = 3 * 47 *
3022058754461477).
Debugging Exercise 2 Overview
The purpose of this program is to read in a single string from the command line and count the characters in this
string. The main() function is written in C, and it will find the counts with help from a C helper function.
We provide all of the code to you, 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. There are a total of 5 bugs in the source code. You are required to record
ALL of the bugs we placed and the solution for each bug. See the section on Debug README File for more
details.
C routines
int main( int argc, char* argv[] );
int* count( char* str );
Getting the Code for Debugging Exercise
For debug2 (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/debug2 .
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.
Debugging Exercise 2 Example Output
The program takes one string argument from the command line:
$ ./countChars STRING
Below are a few examples (bold indicates user input):
[cs30xyz@ieng9]:debug2$ ./countChars
Usage: ./countChars STRING
If the user didn't pass in the expected number of arguments, the program will print usage.
[cs30xyz@ieng9]:debug2$ ./countChars doge
Counting number of characters for "doge"...
Character
Character
Character
Character
d
e
g
o
appeared
appeared
appeared
appeared
1
1
1
1
times
times
times
times
"doge" has a total of 4 character(s)
wow 4 different ascii character(s) much unique so skill
As you can see, the program prints out the characters and the number of times they appear in the input string.
The program also prints out the total number of characters and the total number of unique characters in the
string.
[cs30xyz@ieng9]:debug2$ ./countChars supercalifragilisticexpialidocious
Counting number of characters for "supercalifragilisticexpialidocious"...
Character a appeared 3 times
Character c appeared 3 times
Character d appeared 1 times
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
e
f
g
i
l
o
p
r
s
t
u
x
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
2
1
1
7
3
2
2
2
3
1
2
1
times
times
times
times
times
times
times
times
times
times
times
times
"supercalifragilisticexpialidocious" has a total of 34 character(s)
wow 15 different ascii character(s) much unique so skill
The program simply counts the number of times each ascii characters appear in the string. The program is
expected to work on long words and phrases that have length less than 80 characters.
[cs30xyz@ieng9]:debug2$ ./countChars "J.A.R.V.I.S. is just a rather very
intelligent system."
Counting number of characters for "J.A.R.V.I.S. is just a rather very intelligent
system."...
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
Character
.
A
I
J
R
S
V
a
e
g
h
i
j
l
m
n
r
s
t
u
v
y
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
appeared
7
7
1
1
1
1
1
1
2
5
1
1
3
1
2
1
2
3
4
5
1
1
2
times
times
times
times
times
times
times
times
times
times
times
times
times
times
times
times
times
times
times
times
times
times
times
"J.A.R.V.I.S. is just a rather very intelligent system." has a total of 54
character(s)
wow 23 different ascii character(s) much unique so skill
Debugging C Modules
1. main.c
int main( int argc, char *argv[] );
The main driver of this program. It first checks the user has entered the right number of arguments. Then it
copies the string argument into a local string and calls count(). It loops through the counts array and prints
out the characters and their counts if their counts are greater than 0. Finally it prints the total number of
characters and the total number of unique characters in the string.
2. count.c
int* count( char* str );
This helper method counts the appearances of ascii characters in a given string. It creates an int array of size
256 and increments the element if the ascii character has the same ascii value as the index of the element. It
also counts the number of characters in the string by calling a C routine strlen().
Debugging 2 README File
For the debugging assignment only, you do not have to include the 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 logic errors. 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 3 compilation errors and 2 functionality problems. Make sure you locate all of
them!! (Note: When we say there are 3 compilation errors, we mean that there are three fixes you'll have to
make, not that there are three errors that are printed to the screen). Reference your lecture notes on static vs.
global to help you with this assignment.
Turnin Instructions
Complete Turnin - due Friday night, May 29 @ 11:59 pm
Once you have checked your output, compiled, executed your code, and finished your README file (see
below), you are ready to turn it in. Before you turn in your assignment, you should do make clean in order to
remove all the object files, lint files, core dumps, and executables.
How to Turn in an Assignment
First, you need to have all the relevant files in a subdirectory of your home directory.
PAMT 2
cse30turnin pamt2
In your cs30x account on the lab workstations of ieng6. You will not be able to turn in pamt2 on ieng9.
DEBUG 2
cse30turnin debug2
In your cs30x acoount on ieng9. You will not be able to turn-in debug2 on ieng6.
Style Requirements
You will be graded for the style of programming on all the assignments. A few suggestions/requirements for
style are given below. Read carefully, and if any of them need clarification do not hesitate to ask.
- Use reasonable comments to make your code clear and readable.
- Use file headers and function header blocks to describe the purpose of your programs and functions. Sample
file/function headers are provided with PA0.
- Explicitly comment all the various registers that you use in your assembly code.
- In the assembly routines, you will have to give high level 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 O #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.