• No results found

Guaranteeing That Optimizations are

3.5 Evaluation

3.5.5 Guaranteeing That Optimizations are

Semantics-Preserving

A conservative variant of our approach could report an optimization only if it can statically show the optimization to be semantics-preserving. To assess how effective this approach would be, we manually analyze whether the detected opportunities are amenable to a sound static analysis. We identify three critical challenges for such an analysis, which are at best partly solved in state of the art analyses for JavaScript. First, several opportunities involve function calls, which are not easy to resolve in JavaScript due to its dynamic features, such as dynamically overriding the methods of objects. Second, several opportunities involve calls of native functions, which a static analysis would have to model, including any variants of their implementation that may exist across the various JavaScript engines. Third, several opportunities involve property reads and writes, which might trigger arbitrary code via getter and

setter functions. A sound static analysis would have to show that properties are not implemented with getters and setters, or analyze the effects of them. Out of the 52 beneficial reordering opportunities, 28 involve at least one of these challenges, i.e., a conservative variant of our approach would likely miss these opportunities. These results confirm our design decision in favor of unsoundness, which turns out to be a non-issue in practice [LSS+15, SPL18, AMN17].

3.6

Summary

In this chapter, we present DecisionProf , a profiler that identifies optimization opportunities related to the order of evaluating subexpressions involved in a complex decision. The core idea is to profile the computational cost and the value of each check and to compute the optimal order of evaluating checks. We apply the approach to 9 real-world JavaScript projects and 34 benchmarks where it finds 23 previously unreported reordering opportunities that reduce the execution time in statistically significant ways.

The opportunities reported by DecisionProf are effective and actionable. They are effective because the approach assesses the performance impact of every optimization before reporting it, instead of requiring a developer to manually experiment with code changes. They are actionable because a developer must only decide whether to use a suggested optimization, instead of manually identifying a bottleneck and finding an optimization for it. As a result, our approach further increases the level of automation in optimizing the performance of a program compared to state of the art profilers.

Cross Language Optimizations in

Big Data Systems

Chapters 2 and 3 illustrate how relatively small code changes can significantly improve the execution time of JavaScript applications. While this is true for JavaScript-based web applications, frameworks and libraries, the question is whether similar findings hold for complex, distributed applications that run simultaneously on multiple machines.

In this chapter, we demonstrate the potential of the method inlining code optimization in a large-scale data processing system. Method inlining is a simple program transformation that replaces a function call with the body of the function. We search for method inlining opportunities in programs written in SCOPE [CJL+08], a language for big-data processing queries that combines SQL-like declarative language with C# expressions.

To demonstrate the effectiveness of method inlining, Figure 4.1 illustrates two semantically equivalent SCOPE programs that interleave relational logic with C#

expressions. Figure 4.1a shows the situation where the user implements the predicate in the WHERE clause as a separate C# method. Unfortunately, the presence of non-

relational code blocks the powerful relational optimizations in the SCOPE compiler. As a result, the predicate is executed in a C# virtual machine. On the other hand,

Figure 4.1b shows a slight variation where the user inlines the method body in the WHERE clause. Now, the predicate is amenable to two potential optimizations:

1. The optimizer may choose to promote one (or both) of the conjuncts to an earlier part of the script, especially if either A or B are columns used for partitioning the data. This can dramatically reduce the amount of data needed to be transferred across the network.

2. The SCOPE compiler has a set of methods that it considers to be intrinsics. An intrinsic is a .NET method for which the SCOPE runtime has a semantically equivalent native function, i.e., implemented in C++. For instance, the method

String.isNullOrEmpty checks whether its argument is either null or else the empty string. The corresponding native method is able to execute on the native data encoding, which does not involve creating any .NET objects or instantiating the CLR, i.e., the .NET virtual machine.

The resulting optimizations improve the throughput of the SCOPE program by as much as 90% percent.

SYSTEMS data = SELECT *

FROM inputStream WHERE M(A, B); #CS

bool M(string x, string y) {

return !String.IsNullOrEmpty(x) && y == "Key1"; }

#ENDCS

(a) Predicate invisible to optimizer.

data = SELECT * FROM inputStream

WHERE !String.IsNullOrEmpty(A) AND B == "Key1";

(b) Predicate visible to optimizer.

Figure 4.1: Examples of SCOPE programs.

The cross-language interaction in SCOPE, i.e., between the native and C#

runtimes, poses a significant cost in the overall system. The goal of this chapter is to study and better understand the key performance bottlenecks in this modern data- processing system and demonstrate the potential for cross-language optimization based on method inlining. While this work is primarily about SCOPE, we believe our results and optimizations generalize to other data-processing systems.

To motivate a need for reducing cross-runtime interactions, we first present a new profiling infrastructure based on a combination of offline static analysis of the executed code in addition to low-overhead online measurements captured by SCOPE’s runtime. Then, we describe the results of our profiling of over 3 million SCOPE programs across five data centers within Microsoft. We find that programs with non-relational code take between 45-70% of data center CPU time. Furthermore, we propose a novel static analysis to find inlining opportunities. By inlining a method call, the compiler/optimizer becomes aware of the logic contained in the body of the method and can trigger additional optimizations. Finally, we discuss the effectiveness of such optimizations in six case studies by optimizing jobs from 5 different teams at Microsoft.

4.1

Background

SCOPE [CJL+08] is a big data query language and it combines a familiar SQL-like declarative language with the extensibility and programmability provided by C#

types and the C# expression language. In addition to C# expressions, SCOPE

4.2. PROFILING INFRASTRUCTURE FOR DATA CENTERS