- 92 Views
- Uploaded on
- Presentation posted in: General

Visualizing Memory Graphs by Thomas Zimmermann and Andreas Zeller

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

University of Konstanz

Department of Computer and Information Science

Prof. Dr Stefan Leue, Wei Wei

Software Visualization

SS 2006

Visualizing Memory GraphsbyThomas Zimmermann and Andreas Zeller

Presented by

Giannakaras Giorgos

- Motivation
- Structure of Memory Graphs
- Obtaining Memory Graphs
- Conclusion

GNU debugger GDB

Values are shown as texts.

Problem

A user will never notice if 2 pointers point to the same address – except by thoroughly checking and comparing pointer values.

GNU DDD debugger

- Models memory as a graph.
- Each value in memory becomes a vertex and references between values become edges between these vertices (i.e. pointers).
Drawback

- Each and every pointer of a data structure must be dereferenced manually.

Memory graphs

- A memory graph captures the program state as a graph.
- The graph is extracted automatically from a program.
Usefulness

- Checking if there are pointers pointing to a specific address.
- Checking the number of elements a data structure has.
- Checking if an allocated memory block is reachable from within a module.
- Checking if the tree changed during the last function call.

Graph Notation

- G = (V, E, root)
- V : set of vertices
- E : set of edges
- root : dedicated vertex root
Vertices

- v = (val, tp, addr)
- val : value
- tp : type
- addr : memory address
Edges

- e = (v1, v2, op)
- v1, v2 : related vertices
- op : operation which takes the expression of v1 to construct the expression of v2.

Edge Operations

- Construct the name of the descendants from their parent’s name.
- Operations on edges leading from root to base variables initially set the name.
- We denote functions by λx.B – a function that has a formal parameter x and a body B.
- In our graph visualizations the operation body is shown as edge label with the formal parameter replaced by “()“.
Root

- References all base variables of the program.
- Each vertex in the graph is accessible from the root.

Example

- C declaration of a struct f :
struct foo { int val; } f = {47};

- Results in 2 vertices and an edge :
- Vf = ({…}, struct foo, 0x5678)
- Vf.val = (47, int, 0x9abc)
- ef.val = (vf, vf.val, opf.val)

To obtain a memory graph G = (V, E, root) :

- Let unfold(parent, op, G) be a procedure that takes the name of a parent expression parent and an operation op and unfolds the element op(parent), adding new edges and vertices to the memory graph.
- Initialize V = {root} and E =
- Invoke unfold(root, λx.“name“) for each base variable name in the program.
- The expression expr = op(parent) that will be unfolded depends on the structure of the expr :

- Aliases : if V already has a vertex v΄at the same address and with the same type, do not unfold expr again. However insert an edge (parent, v΄, op) to the existing vertex.
- Records : if expr is a record containing n members m1, m2,...mn, add a vertex v = ({...}, tp, addr) to V, and an edge (parent, v, op) to E. For each mi {m1, m2, mn} invoke unfold(expr, λx.“x.mi“, G), unfolding the record members.
- Arrays : if expr is an array containing n members m[0] , m[1], ..., m[n-1], add a vertex v = ([...], tp, addr) to V and an edge (parent, v, op) to E. For each i {0, 1,..., n} invoke unfold(expr, λx.“x[i]“, G), unfolding the array elements.
- Pointers : if expr is a pointer with address value val, add a vertex v= (val, tp, addr) to V and an edge (parent, v, op) to E. Invoke unfold(expr, λx.“*(x)“, G),unfolding the element that expr points to.
- Atomic values : if expr contains an atomic value val, add a vertex v= (val, tp, addr) to V and an edge (parent, v, op) to E.

Example

- #include <stdio.h>
- #include <stdlib.h>
- #define M 3
- #define N 2
- // _break is used to set the breakpoint
- void _break() {}
- main() {
- int dim2[M][N];
- int i, j;
- for (i=0; i<M; i++)
- for (j=0; j<N; j++)
- dim2[i][j]=i*N+j;
- _break(); }

Comparing program states

- In an alternate program run, all pointers can have different values, but still the same semantics.
- Comparing program states using a graph is a simple operation, since we try to detect the greatest common sub graph.
Usefulness

- Comparing memory graphs gives us the ability to detect exactly where a failure has occurred.

Maximum common subgraph

- Create the set of all pairs of vertices (v1, v2) with the same value and the same type, one from each graph.
- Form the correspondence graph C whose nodes are the pairs from (1) .
- The maximal common sub graph then corresponds to the complete sub graph of C that is not contained to any other complete sub graph.
- Any vertex that is not on the clique indicates a difference between G1 and G2.

DOT graph layouter

- Layouts are nice and descriptive.
- They do not scale to large memory graphs (1000 vertices and more).

h3viewer

- Interactive graph rendering tool that allows the user to navigate along the graph.
- Clicking on any vertex brings it on the front, showing detailed information.
- By dragging and rotating the view, the user can quickly follow and examine data structures.

Applications

- Visualization of all data structures in memory and capturing the entire program state.
- Detection of common sub graphs to isolate differences between program states – especially differences that cause failure.
Limitations – Drawbacks

- Limitation in visualization : lack of capability to depict graphs which contain more than 40.000 vertices.
- Not easily task to detect cycles in very large graphs which might cause endless recursions and eventually eating up all available heap space.

Enhancements - Improvements

- Summarizing parts of the graph – Instead of showing all n elements of a list it might suffice to present only the basic shape of the list.
- Reducing the graph size : pruning the graph at a certain depth in order to restrict the view to a particular module or variable.
- Development of graph algorithms for the detection of specific trouble spots or invariant violations.