1. Goals for this week
-
Practice with an example visualization program that uses the ParaVisi visualization library.
-
Some reminders about using
gdbandvalgrindfor debugging C programs, and setting conditional breakpoints ingdb.
2. Starting Point Code
Start by creating the week09 directory in
your WeeklyLabs subdirectory and copying over some files:
$ cd ~/cs31/WeeklyLabs
$ mkdir week09
$ cd week09
$ pwd
/home/you/cs31/WeeklyLabs/week09
$ cp ~newhall/public/cs31/week09/* ./
$ ls
Makefile colors.h conditional_brk.c visi_example.c
3. Direct Mapped Caching Practice
Before we get started on today’s in-lab exercises, we are going to start with an Exercise we would like you to try out.
Please DO NOT start this (DO NOT CLICK LINK) until I give you a brief introduction to what this is.
Please DO NOT start this before your lab time
4. Reminder about gdb and valgrind for C program debugging
Using gdb and valgrind will save you hours of debugging time. We are going to step through an example of how to set a conditional breakpoint, which may be useful in your debugging.
Try running condition_brk two different ways:
./condition_brk ./condition_brk 10 8
The second way isn’t correctly initializing the 2D array of values.
Let’s run in gdb and put a breakpoint in the init function:
gdb ./condition_brk
(gdb) break init
(gdb) run 10 8
(gdb) list
71 void init(int *array, int rows, int cols) {
72 int i, j;
73
74 for (i = 0; i < rows; i++) {
75 for (j = 0; j < cols; j++) {
76 array[i*cols + j] = i+j;
77 }
78 }
We could add a breakpoint at line 76 to examine the state inside the loop to try to figure out what is going wrong.
(gdb) break 76
The problem with this is that the error doesn’t happen until many
iterations of the loop. If we
set a breakpoint inside the loop, we would have to enter cont many
many times before we get to the point in the execution that we want
to debug.
Instead, we can add a condition to a breakpoint in gdb
to tell it do only trigger the breakpoint when the condition we specify
is true.
You may want want to look at Commands for Setting and Manipulating Breakpoints in section 3.2 of the textbook about conditional breakpoints as we do this.
Let’s try setting a condition on the breakpoint inside the loop that stops just a little before things start to go wrong:
(gdb) info break # get the breakpoint number (2 in my example) ... 2 breakpoint keep y 0x0000555555555320 in init at condition_brk.c:76 (gdb) condition 2 (i > 2 && j > 4) (gdb) info break # see the condition added to breakpoint 2 (gdb) cont (gdb) print i (gdb) print j
Try continuing from here and figure out what is going on with this code.
You may want to use display to display some value every time this
breakpoint is hit.
To remove a condition associated with a breakpoint, just use the command condition followed by the breakpoint number. For example:
(gdb) condition 2 # removes the condition with breakpoint 2 (gdb) info break # see that the condition has been removed
We also could have used valgrind to help us track down this bug.
For more information on gdb and valgrind, see last week’s in-lab page for more information about using gdb and valgrind: Week 8 In-lab
5. ParaVisi Visualization Library
In the GOL lab, you will implement implement two different animations/visualizations of the solution. You have already worked on the ascii animation. The other implements a GUI (Graphical User Interface) visualization that uses the ParaVisi library. It is particularly useful for visualizing very large worlds.
With the files you copied over is an example program that uses the ParaVisi library. Let’s first try running it to see what it does:
$ ./visi_example 200 200 50
Then, let’s open up the source file and examine the code together:
$ code visi_example.c
At the top of the file is a long comment about the steps a program
needs to take to initialize and use the ParaVisi library to visualize
their program. Let’s first read through these, and then look at
this code together, starting with main.
As we look at it, note how the struct appl_data is being used as an argument
to the ParaVisi library functions. It defines the key information that the
library needs to know.
Let’s also look at the simulation function that performs the updates
to the image buffer based on updates to application program state.
Note that after each call to the ParaVisi draw_ready function, the
program calls usleep to slow down the animation:
usleep(SLEEP_USECS); // otherwise animation moves too fast
Looking in the update_colors function, you can see how the program
updates the color of each pixel based on some the program data. A line
such as the one below says that the buffer buff, indexed at buff_i,
should be set to the color red:
buff[buff_i] = c3_red;
The colors are defined in the colors.h file: c3_black, c3_red,
c3_orange, c3_yellow, c3_green, c3_blue, c3_purple,
c3_white, c3_pink, c3_teal, c3_brown. If you want to define
your own colors, you can specify the red, green and blue values as
follows:
// This is "garnet" according the College's style guide
buff[buff_i] = (color3){99, 25, 25};
There are a lot of websites that will give you the RGB values for different colors. Here is one example.
Documentation about using the ParaVisi interface is available as
a comment at the top of the visi_example.c program. Also, more
detailed documentation is available in the pthreadGridVisi.h
header file:
$ code /usr/local/include/qtvis/pthreadGridVisi.h