TL;DR: This book is unique in providing an overview of the four major approaches to program analysis: data flow analysis, constraint-based analysis, abstract interpretation, and type and effect systems.
Abstract: Program analysis utilizes static techniques for computing reliable information about the dynamic behavior of programs. Applications include compilers (for code improvement), software validation (for detecting errors) and transformations between data representation (for solving problems such as Y2K). This book is unique in providing an overview of the four major approaches to program analysis: data flow analysis, constraint-based analysis, abstract interpretation, and type and effect systems. The presentation illustrates the extensive similarities between the approaches, helping readers to choose the best one to utilize.
TL;DR: A Logic Model process is described, a tool used by program evaluators, in enough detail that managers can use it to develop and tell the performance story for their program.
TL;DR: Frequency Spectrum Analysis as discussed by the authors analyzes the frequencies of program entities in a single execution to decompose a program, identify related computations and find computations related to specific input and output characteristics of a program.
Abstract: Dynamic analysis is the analysis of the properties of a running program. In this paper, we explore two new dynamic analyses based on program profiling:Frequency Spectrum Analysis. We show how analyzing the frequencies of program entities in a single execution can help programmers to decompose a program, identify related computations, and find computations related to specific input and output characteristics of a program.Coverage Concept Analysis. Concept analysis of test coverage data computes dynamic analogs to static control flow relationships such as domination, postdomination, and regions. Comparison of these dynamically computed relationships to their static counterparts can point to areas of code requiring more testing and can aid programmers in understanding how a program and its test sets relate to one another.
TL;DR: For interprocedural analysis, existing methods are examined and a new approach that is especially tailored for the cache analysis is presented, which allows for a static classification of the cache behavior of memory references of programs.
Abstract: interpretation is a technique for the static detection of dynamic properties of programs. It is semantics based, that is, it computes approximative properties of the semantics of programs. On this basis, it supports correctness proofs of analyses. It replaces commonly used ad hoc techniques by systematic, provable ones, and it allows for the automatic generation of analyzers from specifications by existing tools. In this work, abstract interpretation is applied to the problem of predicting the cache behavior of programs. semantics of machine programs are defined which determine the contents of caches. For interprocedural analysis, existing methods are examined and a new approach that is especially tailored for the cache analysis is presented. This allows for a static classification of the cache behavior of memory references of programs. The calculated information can be used to improve worst case execution time estimations. It is possible to analyze instruction, data, and combined instruction/data caches for common (re)placement and write strategies. Experimental results are presented that demonstrate the applicability of the analyses.
TL;DR: This paper describes an approach for bounding the worst and best case performance of large code segments on machines that exploit both pipelining and instruction caching and indicates that the timing analyzer efficiently produces tight predictions of best and best-case performance for pipelined and instruction cache.
Abstract: Predicting the execution time of code segments in real-time systems is challenging. Most recently designed machines contain pipelines and caches. Pipeline hazards may result in multicycle delays. Instruction or data memory references may not be found in cache and these misses typically require several cycles to resolve. Whether an instruction will stall due to a pipeline hazard or a cache miss depends on the dynamic sequence of previous instructions executed and memory references performed. Furthermore, these penalties are not independent since delays due to pipeline stalls and cache miss penalties may overlap. This paper describes an approach for bounding the worst and best case performance of large code segments on machines that exploit both pipelining and instruction caching. First, a method is used to analyze a program's control flow to statically categorize the caching behavior of each instruction. Next, these categorizations are used in the pipeline analysis of sequences of instructions representing paths within the program. A timing analyzer uses the pipeline path analysis to estimate the worst and best-case execution performance of each loop and function in the program. Finally, a graphical user interface is invoked that allows a user to request timing predictions on portions of the program. The results indicate that the timing analyzer efficiently produces tight predictions of worst and best-case performance for pipelining and instruction caching.
TL;DR: An efficient algorithm for lazily decomposing aggregates such as records and arrays into simpler components based on the access patterns specific to a given program to identify implicit aggregate structure not evident from declarative information in the program.
Abstract: In this paper, we describe an efficient algorithm for lazily decomposing aggregates such as records and arrays into simpler components based on the access patterns specific to a given program. This process allows us both to identify implicit aggregate structure not evident from declarative information in the program, and to simplify the representation of declared aggregates when references are made only to a subset of their components. We show that the structure identification process can be exploited to yield the following principal results: - A fast type analysis algorithm applicable to program maintenance applications such as date usage inference for the "Year 2000" problem. - An efficient algorithm for atomization of aggregates. Given a program, an aggregate atomization decomposes all of the data that can be manipulated by the program into a set of disjoint atoms such that each data reference can be modeled as one or more references to atoms without loss of semantic information. Aggregate atomization can be used to adapt program analyses and representations designed for scalar data to aggregate data. In particular, atomization can be used to build more precise versions of program representations such as SSA form or PDGs. Such representations can in turn yield more accurate results for problems such as program slicing.Our techniques are especially useful in weakly-typed languages such as Cobol (where a variable need not be declared as an aggregate to store an aggregate value) and in languages where references to statically-defined subranges of data such as arrays or strings are allowed.
TL;DR: A data flow algorithm for computing a conservative estimate of the MHP information for Java programs that has a worst-case time bound that is cubic in the size of the program.
Abstract: Information about which statements in a concurrent program may happen in parallel (MHP) has a number of important applications. It can be used in program optimization, debugging, program understanding tools, improving the accuracy of data flow approaches, and detecting synchronization anomalies, such as data races. In this paper we propose a data flow algorithm for computing a conservative estimate of the MHP information for Java programs that has a worst-case time bound that is cubic in the size of the program. We present a preliminary experimental comparison between our algorithm and a reachability analysis algorithm that determines the “ideal” static MHP information for concurrent Java programs. This initial experiment indicates that our data flow algorithm precisely computed the ideal MHP information in the vast majority of cases we examined. In the two out of 29 cases where the MHP algorithm turned out to be less than ideally precise, the number of spurious pairs was small compared to the total number of ideal MHP pairs.
TL;DR: This analysis relies on unification-based type inference in a non-standard type system, using rows to approximate both the flow of escaping exceptions and theflow of result values, and the resulting analysis is efficient and precise.
Abstract: This paper presents a program analysis to estimate uncaught exceptions in ML programs. This analysis relies on unification-based type inference in a non-standard type system, using rows to approximate both the flow of escaping exceptions (a la effect systems) and the flow of result values (a la control-flow analyses). The resulting analysis is efficient and precise; in particular, arguments carried by exceptions are accurately handled.
TL;DR: A tutorial overview of Ciaopp, the Ciao system preprocessor, which is a public-domain, next-generation logic programming system specifically designed to be highly extensible via librarles and support modular program analysis, debugging, and optimization.
Abstract: We present a tutorial overview of Ciaopp, the Ciao system preprocessor. Ciao is a public-domain, next-generation logic programming system, which subsumes ISO-Prolog and is specifically designed to a) be highly extensible via librarles and b) support modular program analysis, debugging, and optimization. The latter tasks are performed in an integrated fashion by Ciaopp. Ciaopp uses modular, incremental abstract interpretation to infer properties of program predicates and literals, including types, variable instantiation properties (including modes), non-failure, determinacy, bounds on computational cost, bounds on sizes of terms in the program, etc. Using such analysis information, Ciaopp can find errors at compile-time in programs and/or perform partial verification. Ciaopp checks how programs cali system librarles and also any assertions present in the program or in other modules used by the program. These assertions are also used to generate documentation automatically. Ciaopp also uses analysis information to perform program transformations and optimizations such as multiple abstract specialization, parallelization (including granularity control), and optimization of run-time tests for properties which cannot be checked completely at compile-time. We illustrate "hands-on" the use of Ciaopp in all these tasks. By design, Ciaopp is a generic tool, which can be easily tailored to perform these and other tasks for different LP and CLP dialects.
TL;DR: In this article, the authors propose fragment data-flow analysis as an alternative approach which computes dataflow information for a specific program fragment, parameterized by the additional information available about the rest of the program.
Abstract: Traditional interprocedural data-flow analysis is performed on whole programs; however, such whole-program analysis is not feasible for large or incomplete programs. We propose fragment data-flow analysis as an alternative approach which computes data-flow information for a specific program fragment. The analysis is parameterized by the additional information available about the rest of the program. We describe two frameworks for interprocedural flow-sensitive fragment analysis, the relationship between fragment analysis and whole-program analysis, and the requirements ensuring fragment analysis safety and feasibility. We propose an application of fragment analysis as a second analysis phase after an inexpensive flow-insensitive whole-program analysis, in order to obtain better information for important program fragments. We also describe the design of two fragment analyses derived from an already existing whole-program flow- and context-sensitive pointer alias analysis for C programs and present empirical evaluation of their cost and precision. Our experiments show evidence of dramatically better precision obtainable at a practical cost.
TL;DR: An idealized functional language with futures is considered and a series of operational semantics with increasing degrees of intensionality is presented, which defines future to be a semantically transparent annotation and interprets a future expression as a potentially parallel task.
Abstract: The future annotation of MultiLisp provides a simple method for taming the implicit parallelism of functional programs. Prior research on future has concentrated on implementation and design issues, and has largely ignored the development of a semantic characterization of future. This paper considers an idealized functional language with futures and presents a series of operational semantics with increasing degrees of intensionality. The first semantics defines future to be a semantically transparent annotation. The second semantics interprets a future expression as a potentially parallel task. The third semantics explicates the coordination of parallel tasks by introducing placeholder objects and touch operations.We use the last semantics to derive a program analysis algorithm and an optimization algorithm that removes provably redundant touch operations. Experiments with the Gambit compiler indicate that this optimization significantly reduces the overhead imposed by touch operations.
TL;DR: It is demonstrated that abstract interpretation is useful for analysing calculi of computation such as the ambient calculus and that the entire development can be expressed in a constraint-based formalism that is becoming exceedingly popular for the analysis of functional and object-oriented languages.
Abstract: We demonstrate that abstract interpretation is useful for analysing calculi of computation such as the ambient calculus (which is based on the π-calculus); more importantly, we show that the entire development can be expressed in a constraint-based formalism that is becoming exceedingly popular for the analysis of functional and object-oriented languages.
The first step of the development is an analysis for counting occurrences of processes inside other processes (for which we show semantic correctness and that solutions constitute a Moore family); the second step is a previously developed control flow analysis that we show how to induce from the counting analysis (and its properties are derived from those of the counting analysis using general results).
TL;DR: The results show that data flow analysis plays an important role in achieving efficient parallelizations, and that the cost of such analysis con be reasonable even for quite sophisticated abstract domains.
Abstract: We report on a detailed study of the application and effectiveness of program analysis based on abstract interpretation of automatic program parallelization. We study the case of parallelizing logic programs using the notion of strict independence. We first propose and prove correct a methodology for the application in the parallelization task of the information inferred by abstract interpretation, using a parametric domain. The methodology is generic in the sense of allowing the use of different analysis domains. A number of well-known approximation domains are then studied and the transformation into the parametric domain defined. The transformation directly illustrates the revelance and applicability of each abstract domain for the application. Both local and global analyzers are then built using these domains and embedded in a complete parallelizing compiler. Then, the performance of the domains in this context is assessed through a number of experiments. A comparatively wide range of aspects is studied, from the resources needed by the analyzers in terms of time and memory to the actual benefits obtained from the information inferred. Such benefits are evaluated both in terms of the characteristics of the parallelized code and of the actual speedups obtained from it. The results show that data flow analysis plays an important role in achieving efficient parallelizations, and that the cost of such analysis con be reasonable even for quite sophisticated abstract domains. Furthermore, the results also offer significant insight into the characteristics of the domains, the demands of the application, and the trade-offs involved.
TL;DR: An analysis is designed which allows to verify properties pertaining to the relation between values of the numeric and boolean variables of a reactive system and is expressed and proved correct with respect to the source program rather than on an intermediate representation of the program.
Abstract: We define an operational semantics for the Signal language and design an analysis which allows to verify properties pertaining to the relation between values of the numeric and boolean variables of a reactive system. A distinguished feature of the analysis is that it is expressed and proved correct with respect to the source program rather than on an intermediate representation of the program. The analysis calculates a safe approximation to the set of reachable states by a symbolic fixed point computation in the domain of convex polyhedra using a novel widening operator based on the convex hull representation of polyhedra.
TL;DR: This paper provides an overview of compilation techniques for distributed memory machines that must perform partitioning of both code and data for parallel execution and discusses the relationship between the nature of compiler support and type of processor architecture.
Abstract: Over the past two decades tremendous progress has been made in both the design of parallel architectures and the compilers needed for exploiting parallelism on such architectures. In this paper we summarize the advances in compilation techniques for uncovering and effectively exploiting parallelism at various levels of granularity. We begin by describing the program analysis techniques through which parallelism is detected and expressed in form of a program representation. Next compilation techniques for scheduling instruction level parallelism (ILP) are discussed along with the relationship between the nature of compiler support and type of processor architecture. Compilation techniques for exploiting loop and task level parallelism on shared-memory multiprocessors (SMPs) are summarized. Locality optimizations that must be used in conjunction with parallelization techniques for achieving high performance on machines with complex memory hierarchies are also discussed. Finally we provide an overview of compilation techniques for distributed memory machines that must perform partitioning of both code and data for parallel execution. Communication optimization and code generation issues that are unique to such compilers are also briefly discussed.
TL;DR: In this article, a method and several variants are provided for analyzing and transforming a computer program such that instructions may be reordered even across instructions that may throw an exception, while strictly preserving the precise exception semantics of the original program.
Abstract: A method and several variants are provided for analyzing and transforming a computer program such that instructions may be reordered even across instructions that may throw an exception, while strictly preserving the precise exception semantics of the original program. The method uses program analysis to identify the subset of program state that needs to be preserved if an exception is thrown. Furthermore, the method performs a program transformation that allows dependence constraints among potentially excepting instructions to be completely ignored while applying program optimizations. This transformation does not require any special hardware support, and requires a compensation code to be executed only if an exception is thrown, i.e., no additional instructions need to be executed if an exception is not thrown. Variants of the method show how one or several of the features of the method may be performed.
TL;DR: A debugging system has a central processing unit, a register group, a tracer and a trace buffer integrated on a single semiconductor chip, a main memory for storing a target program and other data and an emulator as mentioned in this paper.
Abstract: A debugging system has a central processing unit, a register group, a tracer and a trace buffer integrated on a single semiconductor chip, a main memory for storing a target program and other data and an emulator, and the tracer is connected to a cache memory of the central processing unit and the register group through built-in signal lines patterned over the semiconductor chip so that the tracer is responsive to a high-speed data processing of the central processing unit by virtue of the built-in signal lines merely coupled with small parasitic capacitors.
TL;DR: This chapter treats all of the main approaches to program analysis at the level of examples, stressing the many similarities between what may at a first glance appear to be very unrelated approaches.
Abstract: : In this book we shall introduce four of the main approaches to program analysis: Data Flow Analysis, Control Flow Analysis, Interpretation, and Type and Effect Systems. Each of Chapters 2 to 5 deals with one of these approaches to some length and generally treats the more advanced material in later sections. Throughout the book we aim at stressing the many similarities between what may at a first glance appear to be very unrelated approaches. To help getting this idea across, and to serve as a gentle introduction, this chapter treats all of-the approaches at the level of examples. The technical details are worked-out but it may be difficult to apply the techniques to related examples until some of the material of later chapters have been studied.
TL;DR: This paper describes a systematic method for transforming programs written as straightforward recursions into programs that use dynamic programming, based on incrementalization, which has been implemented and applied to numerous problems and succeeded on all of them.
Abstract: Dynamic programming is an important algorithm design technique. It is used for solving problems whose solutions involve recursively solving subproblems that share subsubproblems. While a straightforward recursive program solves common subsubproblems repeatedly and often takes exponential time, a dynamic programming algorithm solves every subsubproblem just once, saves the result, reuses it when the subsubproblem is encountered again, and takes polynomial time. This paper describes a systematic method for transforming programs written as straightforward recursions into programs that use dynamic programming. The method extends the original program to cache all possibly computed values, incrementalizes the extended program with respect to an input increment to use and maintain all cached results, prunes out cached results that are not used in the incremental computation, and uses the resulting incremental program to form an optimized new program. Incrementalization statically exploits semantics of both control structures and data structures and maintains as invariants equalities characterizing cached results. The principle underlying incrementalization is general for achieving drastic program speedups. Compared with previous methods that perform memoization or tabulation, the method based on incrementalization is more powerful and systematic. It has been implemented and applied to numerous problems and succeeded on all of them.
TL;DR: In this article, the user selects a program from the program scheduling information, and the system determines if a function can be enabled for the selected program by determining the differences between the recurring periods of the selected programs and the function.
Abstract: A user interface and software for enabling or performing functions on programs contained within program scheduling information. The user selects a program from the program scheduling information, and the system determines if a function can be enabled for the selected program by determining the differences between the recurring periods of the selected program and the function.
TL;DR: In this article, a system, method, and program enables a platform independent way for specifying a property, or function, of a program, which enables the program to be developed and run on different operating systems.
Abstract: A system, method, and program enables a platform independent way for specifying a property, or function, of a program. Values of properties that are specific to a given operating system are treated as a variable in a program which enables it to run on multiple operating systems. This enables the program to be developed and run on different operating systems. The program reads in the properties and the values, or variables, from a script file into property objects. As such, variables that have meaning to a system can be put into the property object as the value for that property. To use the property by the program, the program sends a get call to the property object to get the value or to provide substitution of a platform specific value for the variable. Accessible to the program is a plurality of operating system specific code segments which define an actual value for the variable for the specific operating systems. Once the substitution is made, the program uses the actual substituted value for the process the program is carrying out. At the end of the program's process, the program saves the properties by parsing out the operating system specific value and inserting the variable back in. The program is then capable of being run on a different operating system. This provides a platform independent way for an install program to specify and use directories or other install properties; or for other programs to specify and use properties in general; i.e., by creating platform independent variables for properties.
TL;DR: In this article, the authors present a unifying framework for using game semantics as a basis for program analysis, and present a case study of the techniques, which concerns an application to security.
Abstract: We present a unifying framework for using game semantics as a basis for program analysis. Also, we present a case study of the techniques. The unifying framework presents games-based program analysis as an abstract interpretation of an appropriate games category in the category of non-deterministic games. The case study concerns an application to security.
TL;DR: In this article, a dynamic action linker is used to modify the existing program by inserting new actions in the memory image, which are then run under the control of a dynamic linker.
Abstract: A method and apparatus for debugging software for the purpose of modification of the target program's behavior and/or collection of data pertinent to a target program's execution. New user actions are compiled and converted into a dynamically linkable module. The existing program is run under the control of a dynamic action linker. The dynamic action linker modifies the existing program by inserting the new actions in the memory image. The insertion is accomplished by automatically recognizing and modifying object code sequences in the existing program to call the new actions. Once the modification phase has finished modifying the existing program's memory image the new program is run without additional interruption, the new actions acting as if they were present in the original source code for the program.
TL;DR: This paper describes a general and powerful method for dead code analysis and elimination in the presence of recursive data constructions that yields a most precise liveness pattern for the data at each program point, which is significantly more precise than results from previous methods.
Abstract: This paper describes a general and powerful method for dead code analysis and elimination in the presence of recursive data constructions. We represent partially dead recursive data using liveness patterns based on general regular tree grammars extended with the notion of live and dead, and we formulate the analysis as computing liveness patterns at all program points based on program semantics. This analysis yields a most precise liveness pattern for the data at each program point, which is significantly more precise than results from previous methods. The analysis algorithm takes cubic time in terms of the size of the program in the worst case but is very efficient in practice, as shown by our prototype implementation. The analysis results are used to identify and eliminate dead code. The general framework for representing and analyzing properties of recursive data structures using general regular tree grammars applies to other analyses as well.
TL;DR: In this article, a meta-interpreter for goal-directed bottom-up evaluation of logic programs is presented, which avoids re-computation by maintaining and reusing partial solutions to clause bodies.
Abstract: This paper introduces a new strategy for the efficient goal directed bottom-up evaluation of logic programs. Instead of combining a standard bottom-up evaluation strategy with a Magicset transformation, the evaluation strategy is specialized for the application to Magic-set programs which are characterized by clause bodies with a high degree of overlapping. The approach is similar to other techniques which avoid re-computation by maintaining and reusing partial solutions to clause bodies. However, the overhead is considerably reduced as these are maintained implicitly by the underlying Prolog implementation. The technique is presented as a simple meta-interpreter for goal directed bottom-up evaluation. No Magic-set transformation is involved as the dependencies between calls and answers are expressed directly within the interpreter. The proposed technique has been implemented and shown to provide substantial speed-ups in applications of semantic based program analysis based on bottom-up evaluation.
TL;DR: The system, McMicMac, offers a simple yet powerful means for describing specifications, prevents unintentional name clashes, provides feedback in terms of the programmer's source, and has modular mechanisms for managing specifications.
Abstract: A program should document its organization and decisions about the programming process. Since the programmer's thinking about programming and program organization continually evolves, languages inevitably prove unable to state these decisions in a precise and adequate fashion. Macro systems could provide a convenient way to extend a language with such statements, if they had more structure than traditional C- and Lisp-style macros provide.
With our system, McMicMac, designers can express a variety of specifications as language constructs, including program representations of design patterns, high-level recursive programming operators, and collaboration-based design mechanisms. Unlike traditional macro systems, McMicMac offers a simple yet powerful means for describing specifications, prevents unintentional name clashes, provides feedback in terms of the programmer's source, and has modular mechanisms for managing specifications. We have implemented and used McMicMac to define several groups of extensions.
TL;DR: In this article, an apparatus and method allow analyzing the performance of a computer program is presented, which allows a user to detect via queries complex performance bottlenecks that are caused by interactions between multiple code segments.
Abstract: An apparatus and method allow analyzing the performance of a computer program. The computer program is initially executed according to a predefined set of program execution conditions. As the computer program executes, information for each code segment is logged. Using the logged performance data, a graphical representation of the executed computer program is constructed. A user can then formulate ad hoc queries to analyze any desired performance parameters for the computer program by replaying how the computer program ran using the graphical representation of the executed computer program. The present invention thus allows a user to detect via queries complex performance bottlenecks that are caused by interactions between multiple code segments.
TL;DR: By design, Ciaopp is a generic tool, which can be easily tailored to perform program transformations and optimizations such as multiple abstract specialization, parallelization, and optimization of run-time tests for properties which cannot be checked completely at compile-time.
Abstract: We present a tutorial overview of Ciaopp, the Ciao system preprocessor. Ciao is a public-domain, next-generation logic programming system, which subsumes ISO-Prolog and is specifically designed to a) be highly extensible via libraries and b) support modular program analysis, debugging, and optimization. The latter tasks are performed in an integrated fashion by Ciaopp. Ciaopp uses modular, incremental abstract interpretation to infer properties of program predicates and literais, including types, variabie instantiation properties (including modes), non-failure, determinacy, bounds on computational cost, bounds on sizes of terms in the program, etc. Using such analysis information, Ciaopp can find errors at compile-time in programs and/or perform partial verification. Ciaopp checks how programs call system libraries and also any assertions present in the program or in other modules used by the program. These assertions are also used to generate documentation automatically. Ciaopp also uses analysis information to perform program transformations and optimizations such as multiple abstract specialization, parallelization (including granularity control), and optimization of run-time tests for properties which cannot be checked completely at compile-time. We illustrate “hands-on” the use of Ciaopp in all these tasks. By design, Ciaopp is a generic tool, which can be easily tailored to perform these and other tasks for different LP and CLP dialects
TL;DR: In this article, the authors consider abstract domains for polymorphically typed logic programs and show how specialised domains may be constructed for each type in the program, which capture the degree of instantiation to a high level of precision.
Abstract: Precise mode information is important for compiler optimisations and in program development tools. Within the framework of abstract compilation, the precision of a mode analysis depends, in part, on the expressiveness of the abstract domain and its associated abstraction function. This paper considers abstract domains for polymorphically typed logic programs and shows how specialised domains may be constructed for each type in the program. These domains capture the degree of instantiation to a high level of precision. By providing a generic definition of abstract unification, the abstraction of a program using these domains is formalised. The domain construction procedure is fully implemented using the Godel language and tested on a number of example programs to demonstrate the viability of the approach.