Lab 11—Dynamic analysis
Objectives
- Practice using a set of free dynamic analysis tools:
gdb
,valgrind
, andkcachegrind
- Please pair-program today!
Exercise
First, clone the source code from asayler/CU-CSCI3308-DynamicPractice. The code consists of a small program that calculates PI using statistics and geometry.
The usage of the program is ./pi <iterations>
where
iterations is the number of calculations to run. Higher iterations will
result in more accurate calculations of PI but will take longer to run.
If no argument is supplied, the program defaults to 1,000,000 iterations.
Then, make sure you have the following software installed on your system (the CU CS Virtual Machine has this installed by default):
- gcc
- GNU Make
- gdb
- valgrind
- kcachegrind
Ubuntu setup
sudo apt-get install build-essential valgrind kcachegrind
macOS setup
Note: Valgrind does not yet work on macOS 10.12 Sierra. Use an Ubuntu virtual machine instead.
Use Homebrew to install the following tools:
brew install gdb valgrind graphviz qcachegrind
macOS does not allow a process to take control over another process, the sole
purpose of gdb
, without code signing the binary. Follow these steps to
create a self-signed certificate and sign the gdb
binary to give it permission
to debug other processes.
Alternatively, install Xcode and use the lldb
command line tool.
Now we’ll walk through some analysis and modification of the source code
using the tools above. Where questions appear below, please type your answer
into a plain text file called answers.txt
. You will submit these answers,
as well as the modified code, at the end of this assignment.
Part 1 - GDB
- Use
make
to compile the code. - Run
./pi
. What happens? - Run the code again via GDB.
- Using GDB, determine where the issue is occurring. On which line of code does the program crash?
- Exit GDB.
- Open the code in an editor. Find the problem line. What is the problem and
how do we fix it? Hint: look at the similar working code in
zeroDist()
. - Fix the code, save, and the re-make the code.
- Run the code again via GDB. Confirm the crash is fixed. If not, iterate until the code does not crash.
- Set a breakpoint at the
zeroDist()
function. What GDB command did you use? - Run the code again.
- When you reach the breakpoint, print the current
x
andy
values of theother_pt
argument. What GDB commands did you use? - Delete the breakpoint and continue. What GDB commands did you use?
- When the program exists successfully, close GDB.
Part 2 - Valgrind
- Now run the code via valgrind
- Is the code leaking memory? How much?
- Use valgrind to identify where in the code memory is being allocated but not freed. What are the problematic line numbers?
- Open the code in an editor. Find the problem lines. What is the problem and how do we fix it?
- Fix the code, save, and the re-make the code.
- Run the code again via valgrind. Confirm the memory leak is fixed. If not, iterate until the code does not leak memory.
Part 3 - Profiling
- Use
/usr/bin/time
to calculate how long it takes./pi
to run. Play with the number of iteration until you have it taking ~1s of real time. Record the number of iterations you are using and how long the program takes to run. - Now generate a callgrind profile by running
valgrind --tool=callgrind ./pi <your iterations>
- Open the resulting profile output using kcachegrind: e.g.
kcachegrind callgrind.out.?????
- Explore the information kcachegrind provides. Starting with
main()
, what are the top 5 places the program spends the largest percentage if its time? What percentage of time does it spend in each place? - Close kcachegrind.
- Using the information from 4, can you make the code faster? How?
- Modify and rebuild the code with some of your enhancements.
- Run the code again via
/usr/bin/time
. How does the new runtime compare to the runtime from 1?
Credit
To get credit for this lab exercise, show the TA and sign the lab’s completion log.
Lab material by Liz Boese.