Overall Objectives
Scientific Foundations
Application Domains
New Results
Other Grants and Activities

Section: New Results

Dynamic dependency analysis

Dynamic dependence analysis consists in observing all memory (or object) accesses performed by a program to detect all the data dependences that occur. It is essentially incomplete in that it relies on a specific execution, but can provide insight on the memory behavior and help designing correct program transformations, e.g., for parallelization. Dynamic dependence analysis has been used mainly for detecting parallel, or almost parallel, program sections, and are often coupled with thread-level speculation. We believe dynamic dependence analysis can also be extremely useful as an aid to the programmer, provided the tools are able to extract usable information on which parts of the program can be parallelized. We plan to make it a central component to our parallelization assistant project.

In its simplest form, dynamic dependence analysis takes a trace of memory accesses, and finds in the trace the addresses that have appeared previously. Every such occurrence is a dependence if any of the accesses involved is a write. This is barely useful if it is not related in some way to the structure of the program under scrutiny. Most previous studies have used “local” structures, keeping, for instance, a table of memory accesses for each iteration of a loop, and then testing independence to find out that the loop is parallel (in the sense that all its iterations could have been run in parallel). Even when the loop iterations are dependent, a low frequency of dependence may still make the loop be considered a good candidate for speculative parallelization.

Our approach is much more focused on the program structure. It associates to each memory access an execution point that contains an interleaving of function calls and loop iterations (we call this an extended stack trace). Given two conflicting accesses, the longest common prefix of their extended stack trace indicates the “nearest” program structure that exhibits the dependence (either a function call or a loop iteration). This has been used in other works, to detect parallel loops. What is less often noticed is that the remaining portions of the execution points (i.e., the upper parts of the stacks) provide detailed information on the respective iterations that carry the dependence. It is therefore possible to extract complete dependence schema for loop nests (with dependence distances), and not only for single loops as is usual. This means that, if dynamic dependence analysis is used in an interactive tool, more elaborate parallelization strategies can be suggested.

Another major topic related to dynamic dependence analysis is the scalability of the approach, which requires heavy instrumentation and sophisticated and efficient data structures to be usable. Part of the solution is covered by our other studies on “program skeletonization” (see above), but much remains to be done to make the analysis usable in a developer tool. We have started work on using static analysis of the binary program (and/or debugging information where available) to reduce the cost of instrumentation and analysis. Once again, this relies on detecting loops whose memory footprints can be known by analyzing the code. Fortunately, a large body of theory, especially on parametric integer programming, can help reduce the amount of data to process. The idea is to use the static description of complete parts of the program to update the dependence data structures. This is again an illustration of a principle that is used throughout our work, namely the cooperation between static and dynamic data.


Logo Inria