• No results found

Optimizations of Big Data Jobs

a graph and warns developers about variable, properties, and functions that have multiple inconsistent types. The work by Mutlu et al. [MTL15] proposes a novel lightweight runtime symbolic exploration algorithm for finding races in JavaScript applications. The key advantages of the approach is that it requires only a single execution and reports only harmful races. Dynamic determinacy analysis by Schaefer et al. [SSDT13] analyzes more or one concrete executions to identify variables and expressions that have the same value at a given program point in any execution. This information can be exploited by other analyses and tools to, e.g., identify dead code or specialize uses of dynamic language constructs.

Other dynamic analyses support developers in program comprehension tasks. Clematis [ASMP14] is a technique for capturing low-level event-based interactions in a web application and mapping those to a higher-level behavioral model. This model is then visualized to illustrate episodes of triggered events, related JavaScript code executions and their impact on DOM state. Tochal [AMP15] is a DOM-sensitive event-aware change impact analysis technique for JavaScript. The approach creates a novel hybrid model to identify the impact set of a change in a given application.

6.6

Optimizations of Big Data Jobs

The analysis in Chapter 4 leverages cross-language optimization to reduce cross- runtime interactions in big data queries. Unfortunately, many powerful query optimizations [CS94, YL95, MP94, SHP+96, Kim82, Mur92, CKPS95, PL08, Sel88, BK89, FFN+08, HS93, CGK89] are not applicable in modern big-data processing systems because the traditional query optimizer treats non-relational code as a black-box.

To improve the performance of modern large-scale data processing systems, several optimization strategies have been proposed. Quincy [IPC+09] is a frame- work for scheduling concurrent distributed jobs with fine-grain resource sharing. LATE [ZKJ+08] addresses scheduling problems in heterogeneous environments by es- timating the time needed to speculatively execute the task that hurt the response time the most. Hadoop++ [DQRJ+10] improves the query runtime of a Hadoop system by changing the internal layout of a split, a large horizontal partition of the data, and feeding Hadoop with appropriate user-written functions. Floratou et al. [FPST11] propose an approach to speed up MapReduce jobs by using column-oriented binary storage formats in Hadoop compatible with its replication and scheduling constraints. MRShare [NPM+10] is a sharing framework tailored to MapReduce programs. It merges jobs into groups and evaluates each group as a single query which enables more efficient execution of different jobs that perform similar work. Although some of the standard database optimizations, such as filter pushdown are implemented in Pig [ORSS08], the recent work by Jahani et al. [JCR11] suggests that many traditional query optimizations are not applicable to MapReduce [DG08] because of user-written operators. It further proposes several optimizations of map() functions by targeting data-centric programming idioms [JCR11]. These optimizations include data compression and eliminating unnecessary fields from files and indexing. In Chapter 4, we show that the time spent in non-relational code takes a large fraction

of data center time. Furthermore, we propose a novel cross-language optimization based on method inlining to improve the performance of MapReduce jobs.

Many MapReduce systems, such as Hadoop [DQRJ+10], provide facilities for monitoring cluster performance. The collected metrics usually represent cluster-level information from which the regular user does not benefit. Herodotou et al. [HB11] introduce a new dynamic binary instrumentation of the MapReduce framework to capture dataflows and costs during job execution at the task level or the phase level. Obtained profiles help developers apply a new class of optimization opportunities based on tuning of the configuration parameters. In contrast to the dynamic analysis, our approach to profiling big data jobs is purely static and based on the analysis of job artifacts. Doing this allows us to analyze a large number of jobs without introducing any additional overhead.

Conclusion

In this dissertation, we present actionable program analyses to improve software performance. More concretely, we focus on an empirical study of the most common performance issues in JavaScript programs (Chapter 2), analyses to find reordering opportunities (Chapter 3) and method inlining opportunities(Chapter 4) and a novel test generation technique for higher-order functions in dynamic languages (Chapter 5). These approaches aim to reduce manual effort by suggesting only beneficial optimization opportunities that are easy to understand and applicable across multiple projects.

7.1

Summary of Contributions

Chapter 2 presents an empirical study of 98 performance issues and optimizations in JavaScript projects. The results of the study show that many of the studied optimizations have the following key properties: they are effective, exploitable, recurring, and out-of-reach for compilers. To help developers find and exploit such

optimization opportunities, Chapters 3 and 4 propose two actionable program analyses. The first analysis finds reordering opportunities in switch statements and logical expressions by dynamically analyzing and computing the optimal orders of evaluations. The second analysis statically analyzes programs for big data processing to find opportunities for method inlining, i.e., replacing a call to a user-written function with the logic of that function. Finally, Chapter 5 discusses how to improve state-of-the-art test generation approaches to generate effective tests for higher-order functions in dynamic languages such as JavaScript. Generated tests then can be used to drive the program execution during dynamic analysis and to reliably measure the performance impact of applied optimizations.

In this dissertation, we show that it is possible to automatically suggest effective, exploitable, recurring and out-of-reach for compilers optimization opportunities. In particular:

• By empirically studying performance issues and optimizations in real-world software, we show that most issues are addressed by optimizations that modify only a few lines of code, without significantly affecting the complexity of the source code. By studying the performance impact of optimizations on several JIT engines, we find that less than half of all optimizations improve performance consistently across all engines. Furthermore, we observe that many

optimizations are instances of patterns applicable across projects. These results motivate the development of performance-related techniques that address relevant performance problems.

• Applying these optimizations in a fully automatic way is a challenging task: they are subject to preconditions that are hard to check or can be checked only at runtime. We propose two program analyses that prove to be powerful in finding optimization opportunities in complex programs. Even though our approaches do not guarantee that code transformations are semantics- preserving, the experimental results illustrate that suggested optimizations do not change program behavior.

• Reliably finding optimization opportunities and measuring their performance benefits require a program to be exercised with sufficient inputs. One possible solution to this problem is to use automated test generation techniques. We complement existing testing approaches by addressing the problem of test generation for higher-order functions. Finally, we show that generating effective tests for higher-order functions triggers behaviors that are usually not triggered by state-of-the-art testing approaches.