1. Goals for this week

  1. Practice with an example visualization program that uses the ParaVisi visualization library.

  2. Some reminders about using gdb and valgrind for debugging C programs, and setting conditional breakpoints in gdb.

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

6. Handy References