60
1 15-214 School of Computer Science Principles of Software Construction: Performance Christian Kaestner Bogdan Vasilecu

Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

  • Upload
    leduong

  • View
    220

  • Download
    1

Embed Size (px)

Citation preview

Page 1: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

1 15-214

School of Computer Science

Principles of Software Construction: Performance

Christian Kaestner Bogdan Vasilecu

Page 2: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

2 15-214

Your Feedback

• Recitations and homeworks useful

• Art vs performance

• Narrative of the class unclear

• Workload high, assignments too large

• Unclear how to act on feedback

• Suggestions:

– More case studies of good design

– Longer recitations

– More live coding

Page 3: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

3 15-214

Part 1: Design at a Class Level

Design for Change: Information Hiding,

Contracts, Design Patterns, Unit Testing

Design for Reuse:

Inheritance, Delegation, Immutability, LSP, Design Patterns

Part 2: Designing (Sub)systems

Understanding the Problem

Responsibility Assignment,

Design Patterns, GUI vs Core,

Design Case Studies

Testing Subsystems

Design for Reuse at Scale: Frameworks and APIs

Part 3: Designing Concurrent

Systems

Concurrency Primitives, Synchronization

Designing Abstractions for

Concurrency

Distributed Systems in a Nutshell

Intro to Java

Git, CI Static Analysis

GUIs UML More Git

GUIs Performance

Design

Page 4: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

4 15-214

Page 5: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

5 15-214

Learning goals for today

• Avoid premature optimization

• Know pitfalls of common APIs

• Understand garbage collection

• Ability to use a profiler

Page 6: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

6 15-214

More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason—including blind stupidity. —William A. Wulf

Page 7: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

7 15-214

Competing Design Goals

• Extensibility

• Maintainability (design for change & understanding)

• Performance

• Safety, security

• Stability

Page 8: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

8 15-214

Good Programs Rather than Fast Ones

• Information hiding:

– Individual decisions can be changed and improved without affecting other parts of a system

– Abstract interactions with the outside world (I/O, user interactions)

• A good architecture scales

• Hardware is cheap, developers are not

• Optimize only clear, concise, well-structured implementations, if at all

• Who exchanges readability for performance will lose both

Page 9: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

9 15-214

Performance Optimizations

• High-level algorithmic changes

• Low-level hacking

Page 10: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

10 15-214

Performance Optimizations

• High-level algorithmic changes

• Low-level hacking

No amount of low-level optimization can fix an inefficient algorithmic choice

Page 11: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

11 15-214

Before Optimization: Profiling

• Common wisdom: 80% of time spent in 20% of code

• Many optimizations have minimal impact or make performance worse

• Guessing problem often inefficient

• Use profiler to identify bottleneck

– Often points toward algorithmic changes (quadratic -> linear)

Page 12: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

12 15-214

EXAMPLE: COSINE SIMILARITY

Page 13: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

13 15-214

Performance informs design

• Find closest match in n documents

– Computational complexity?

• Find closest matches in n documents

– Computational complexity?

• What’s the actual runtime performance?

Page 14: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

14 15-214

Latency PRIMITIVE LATENCY: ns us ms

L1 cache reference 0.5

Branch mispredict 5

L2 cache reference 7

Mutex lock/unlock 25

Main memory reference 100 Compress 1K bytes with Zippy 3,000 3

Send 1K bytes over 1 Gbps network 10,000 10

Read 4K randomly from SSD* 150,000 150

Read 1 MB sequentially from memory 250,000 250

Round trip within same datacenter 500,000 500

Read 1 MB sequentially from SSD* 1,000,000 1,000 1

Disk seek 10,000,000 10,000 10

Read 1 MB sequentially from disk 20,000,000 20,000 20

Send packet CA->Netherlands->CA 150,000,000 150,000 150

Page 15: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

15 15-214

public class Document { private final ... public Document(String url) throws IOException { } public double cosineSimilarity(Document doc) { } }

Page 16: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

16 15-214

public class Document { private final String url; private final Map<String, Integer> wordFreqs = new HashMap<>(); private final double magnitude; // Smaller win public Document(String url) throws IOException { this.url = url; Scanner sc = new Scanner(new URL(url).openStream()); while (sc.hasNext()) wordFreqs.merge(sc.next(), 1, Integer::sum); double sumOfSquares = 0; for (int freq : wordFrequencies.values()) sumOfSquares += freq * freq; magnitude = Math.sqrt(sumOfSquares); } public double cosineSimilarity(Document doc) { double dotProduct = 0; for (Map.Entry<String, Integer> freq : wordFreqs.entrySet()) { dotProduct += freq.getValue() * doc.wordFreqs.getOrDefault(freq.getKey(), 0); } return dotProduct / (magnitude * doc.magnitude); }

(redacted)

Page 17: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

17 15-214

public static void main(String[] args) throws IOException { // Translate URLs into documents int numDocs = args.length; Document[] docs = new Document[numDocs]; for (int i = 0; i < numDocs; i++) { docs[i] = new Document(args[i]); } // Create matrix of similarity scores double[][] scores = new double[numDocs][numDocs]; for (int i = 0; i < numDocs; i++) { for (int j = i + 1; j < numDocs; j++) { scores[i][j] = scores[j][i] = docs[i].cosineSimilarity(docs[j]); } }

(redacted)

Page 18: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

18 15-214

Profiler Demo

Page 19: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

19 15-214

Performance prediction

• Performance prediction is hard

• Use profiler

• I/O can overshadow other costs

• Performance may not be practically relevant for many problems

Page 20: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

20 15-214

15-313 Question

• Twitter famously had scalability problems and rewrote most of their system (Ruby -> Scala; Monolithic -> Microarchitecture)

• Was the initial monolithic design stupid?

• What tradeoffs to make for a startup?

Page 21: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

21 15-214

Scrabble Design

• When to load the dictionary?

• When to check whether a move is valid?

Page 22: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

22 15-214

PERFORMANCE PITFALLS (NOT ONLY IN JAVA)

Page 23: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

23 15-214

Know the Language and its Libraries

• String concatenation

• List access

• Autoboxing

• Hashcode

Page 24: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

24 15-214

String concatenation in Java

public String toString(String[] elements) {

String result = "";

for (int i = 0; i < elements.length; i++)

result += elements[i];

return result;

}

Page 25: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

25 15-214

String concatenation in Java

public String toString(String[] elements) {

String result = "";

for (int i = 0; i < elements.length; i++)

result = result.concat(elements[i]);

return result;

}

See implementation of String.concat()

Page 26: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

26 15-214

Efficient String Concatenation

public String toString(String[] elements) {

StringBuilder b = new StringBuilder();

for (int i = 0; i < elements.length; i++)

b.append(elements[i]);

return b.toString();

}

See implementation of StringBuilder

Page 27: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

27 15-214

Lists

List<String> l = …

for (int i = 0; i < l.size(); i++)

if (“key”.equals(l.get(i))

System.out.println(“found it”);

Possibly very slow; why?

Page 28: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

28 15-214

Autoboxing: Integer vs int

• Integers are objects, ints are not

• new Integer(42) == new Integer(42) ?

• 4.equals(4) ?

• Integer a = 5 ?

• Math.max(12, new Integer(44)) ?

• new Integer(42) == 42 ?

see implementation of Integer

Page 29: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

29 15-214

Understand Autoboxing

public static void main(String[] args) {

Long sum = 0L;

for (long i = 0; i < Integer.MAX_VALUE; i++) {

sum += i;

}

System.out.println(sum);

}

Very slow; why?

Page 30: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

30 15-214

When to use Boxed Primitives?

• Keys and values in collections (need objects)

• Type parameters in general (Optional<Long>)

• Prefer primitive types over boxed ones where possible

Page 31: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

31 15-214

Understanding Hashcode

class Office {

private String roomNr;

private Set<Person> occupants;

public boolean equals(Object that) { … }

}

Set<Office> …

possible problem?

Page 32: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

32 15-214

Understanding Hashcode

class Office {

private String roomNr;

private Set<Person> occupants;

public int hashCode() { return 0; }

}

Set<Office> …

performance problem?

Page 33: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

33 15-214

Hashcode – good practice

• Start with nonzero constant (e.g. 17)

• For each significant field integrate value (result = result * 31 + c) where c:

– “(f?1:0)” for boolean

– “(int) f” for most primitives

– o.hashCode for objects

Page 34: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

34 15-214

Don’t worry about

• Overhead of method calls (e.g., strategy pattern)

• Overhead of object allocation (unless its millions)

• Multiplication vs shifting (compiler can optimize that)

• Performance of a single statement / microbenchmarks

• Recursion vs iteration

Page 35: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

35 15-214

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. —Donald E. Knuth

Page 36: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

36 15-214

GARBAGE COLLECTION

Page 37: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

37 15-214

Explicit Memory Allocation vs. Garbage Collection

• Stack allocation:

– int x = 4;

• Heap allocation

– Point x = new Point(4, 5);

– Reference on stack, object on heap

• C-style explicit memory allocation

– pointStruct* x; x = malloc(sizeof(pointStruct));

– x -> y = 5; x -> x = 4;

– free(x);

Page 38: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

38 15-214

Garbage Collection

• No explicit “free”

• Elements that are no longer referenced may be freed by the JVM

– int foo() { Point x = new Point(4, 5); return x.x - x.y; }

– set.add(new Point(4, 5)); return set;

Page 39: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

39 15-214 http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

Page 40: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

40 15-214

Memory Leaks

• C: Forgetting to free memory

• Java: Holding on to references to objects no longer needed

– class Memory { static final List<Point> l = new ArrayList(10000); final HashMap<Integer, Connection> … }

• Java: Not closing streams, connections, etc

Page 41: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

41 15-214

Memory Leak Example

class Stack {

Point[] elements;

int size = 0;

void push(Point x) { elements[++size] = x; }

Point peek() { return elements[size]; }

Point pop() { return elements[size--]; }

} Why is this a problem? How to fix it?

Page 42: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

42 15-214

Memory Leak Example

class Stack {

Point pop() {

Point r = elements[size];

elements[size] = null;

size--;

return r;

}

}

Page 43: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

43 15-214

Weak References

• References that may be garbage collected

– java.lang.ref.WeakReference<T>

– java.util.WeakHashMap<K,V> (weak keys)

• x = new WeakReference(new Point(4 ,5)); x.get() // returns the point, or null if garbage collected in between

• WeakHashMap useful for caching, when cache should not prevent garbage collection

Page 44: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

44 15-214

References and Observers

class Game {

List<WeakReference<Listener>> listeners = …

void addListener(Listener l) {

listeners.add(new WeakReference(l));

}

void fireEvent() {

for (wl : listeners) {

Listener l = wl.get();

if (l != null) l.update();

}

}

}

Should lists of observers be stored as weak

references to avoid memory leaks?

Page 45: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

45 15-214

Caching expensive computations (on immutable objects) class Cache {

Map<Cryptarithm, Solution> cache = new WeakHashMap<>();

Solution solve(Cryptarithm c) {

Solution result = cache.get(c);

if (result != null) return result;

result = c.solve();

cache.put(c, result);

return result;

}

} similar caching in factories when creating objects

Page 46: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

46 15-214

PERFORMANCE AND DESIGN

Page 47: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

47 15-214

Performance in API Design

• Immutable classes are easy and fast

– Easy to share

– No defensive copying

• class type instead of interface type ties to that class; inheritance ties subclass to superclass decisions, delegation does not

Page 48: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

48 15-214

Example: Poor Performance through API Design

• java.awt.Component.getSize returns mutable Dimension

– lots of defensive copying

– separate getWidth/getHight methods added later for performance reasons

• “Returns the current height of this component. This method is preferable to writing component. getBounds().height or component.getSize().height because it doesn't cause any heap allocations.”

• Old design problems stick around

Page 49: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

49 15-214

Design Pattern for Performance

• Flyweight

• Proxy (caching)

• Factories (caching)

Page 50: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

50 15-214

Proxy Design Pattern

Applicability • Whenever you need a more sophisticated

obj reference than a simple pointer

• Local representative for remote obj.

• Create/load expensive obj on demand

• Control access to an object

• Extra error handling, failover

• Caching

• Reference count an object

Consequences • Introduces a level of indirection • Hides distribution from client • Hides optimizations from client • Adds housekeeping tasks

Page 51: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

51 15-214

Proxy Example

CryptarythmProxy implements Cryptarythm {

private Cryptarythm c;

private final String[] input;

CryptarythmProxy(String[] words) { input = words; }

public solve() {

if (c != null)

c = new Cryptarythm(input);

return c.solve();

}

}

Page 52: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

52 15-214

Proxy Example

CryptarythmProxy implements Cryptarythm {

private Solution solution;

private final String[] input;

CryptarythmProxy(String[] words) { input = words; }

public solve() {

if (solution != null)

solution = new Cryptarythm(input).solve();

return solution;

}

}

Page 53: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

53 15-214

The Flyweight Pattern

• Share data structures for values efficiently; create one instance per value

• Examples:

– Characters in a document

– Enums

– Coffee Flavors

• Flyweights are immutable value objects, their creation is cached in a factory

• Aka “Hash consing”

Page 54: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

54 15-214

Page 55: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

55 15-214

Flyweight Example

class TileImage { // immutable value class, the flyweight

TileImage(char c) { … } // package-visible constructor can prevent

image, draw() … // clients from instantiating directly

}

class TileImageFactory {

private Map<Char, TileImage> cache = new WeakHashMap<>();

public TileImage create(char c) {

TileImage result = cache.get(c);

if (result != null) return result;

result = new TileImage(c);

cache.put(c, result);

return result;

}

}

Page 56: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

56 15-214

Page 57: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

57 15-214

5

3 3

1 2 2 3

1 2

How can we represent the same tree with fewer objects?

Page 58: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

58 15-214

5

3 3

1 2 2 3

1 2 5

3

3

1 2

Reusing Tree Nodes with Flyweight Pattern:

Page 59: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

59 15-214

Conclusion

• Performance does not matter, until it does

• Focus on good designs, avoid premature optimization

• Use a profiler before optimizing

• Know pitfalls in Java, understand weak references

• Flyweight, Proxies, *Factory Patterns all enable caching of sorts

Page 60: Principles of Software Construction: Performanceckaestne/15214/s2017/slides/20170307...Principles of Software Construction: Performance ... Unit Testing Design for Reuse: ... (Document

60 15-214

Further Reading

• Effective Java, Item 55 and many more

• Design patterns Proxy, Flyweight, *Factory

• Java API documentation of WeakReference, WeakHashmap