Will not get into specifics as it's a general course Will talk about lanaguage and environment differences - compiled vs interpreted - garbage collected vs manual memory management
Significant changes will generally come from general ideas and principles.
Improving efficiency will be like copywriting a poorly written novel where you have to go through the code line by line and examine and change everything.
This is rarely, if ever, necessary. Usually, only a few places in your code can make a significant improvement.
Working on efficiency requires guru-level knowledge of language and environment.
Huge improvements are achievable with code you could have written first few days of using the language
Being an expert is not necessary and may be detrimental for lack of humility
If working on existing code, the precondition is that the code works
What about if you're writing new code?
First, do nothing (as far as efficiency)
"Premature optimization is the root of all evil in programming" - Knuth
Begin by valuing clarity and focus of code Prove there's an issue before fixing it
Trusting your gut feeling of what the issue is is a bad habit to get into
UI that freezes could be a network issue, memory issue, threading issue, etc.
Memory
Algorithmic
File/Disk I/O
Network
All independently verifiable. Efficiency is a sliding scale.
Client side -> low control, low predictability Web server -> high control, high predictability
If there's a memory issue on the browser side, the only option is optimizing the Javascript code and how it works on low-specification machines
If there's a memory issue on the server side, you can just add another stick of memory or another server.
For a programmer, laziness is a virtue.
Helps avoid pitfall of getting caught up in an area without realizing whether or not it's worth it.
You're looking for something to leap out at you. If you don't find an obvious bottleneck, look for things that you can remove or move.
Efficiency improvements are not identical in impact. Don't get caught up in the technical advances, etc.
Profiling
Stay focused: Utilities not just used for efficiency - used to monitor health of system -> aimed more at sys admin - need to filter and ignore most things
General builtin task monitoring applications Specialized monitoring and profiling tools
Activity Monitor / Task Manager
Good for quick scan
top
-> all processes
ps {PID}
-> process status
lsof -p {PID}
-> list open files
sudo fs_usage {PID}
-> file system usage
heap {PID or name of application}
leaks {PID}
sudo sysdiagnose {PID}
-> could be run without PID for system diagnosticdtrace
-> dynamic tracingProfiling more related to language than editor Python -> cProfile Ruby -> rProfile, ruby-prof
Use Developer Tools to check web application
Physical memory: RAM/primary memory
If you run out of physical memory iand application requests more:
Operating system is out of physical memory
If Application C then needs mmemory back:
When you need to take physical memory and write to disk -> paging out When bringing back in from disk -> paging in
Working with RAM is significantly faster Swapping adds up and can contribute to latency
If running low on physical memory, iOS will ask application to free up memory
Memory elements:
Reasons for memory growth:
Fake growth (temporary objects stay alive)
If using garbage-collected language, could get false positive because it takes a while for garbage-collection to take place
Instantiation inside loops
Objects with large object graphs
Recommended: Lazy instantiation Any time you can put it off, do so. Example:
// Normal instantiation:
class Employee {
String name;
Image photo;
public Employee (String n) {
name = n;
photo = new Image("~/path/to/employee/names" + "name"
}
public Image getPhoto() {
return photo;
}
// Lazy Instantiation:
class Employee {
String name;
Image photo;
public Employee (String n) {
name = n;
}
public Image getPhoto() {
if (photo == null) {
photo = new Image("~/path/to/employee" + "name");
}
return photo;
}
Manual Automatic (GC)
--------------------------------------------
Con: Harder to write Pro: Easier to write
Con: Risk of memory bugs Pro: Less memory bugs
Pro: Usually faster Con: Slower
Pro: Deterministic Con: Non-deterministic
Garbage collector needs to be part of the process Misconception: "It takes care of everything!"
Reference counter -> incremented based on number of objects needed ARC (automatic reference counting) "As if the compiler writes the manual memory management code you would write if you were really good at writing it"
Performance profiling? Use a release build Memory profiling? Use debug build Some have default build settings
Test large data sets Test with constrained devices If you have a "first-run" or install process, test it
Exceptions: Not always using the least amount of memory
"Could these statements have been written to accomplish the same result, but do it faster?"
Instruments -> Time Profiler
Be aware of multi-core differences
A lot of times, you'll do print debugging for debugging -> can add getTime() in prints to see time between statements
Basic logging: console.log console.warn console.debug console.error console.info
Simple time measurement:
window.onload = function () {
console.time("myTimer");
complexFunction();
console.timeEnd("myTimer");
}
JS Profiling:
window.onload = function () {
console.profile();
complexFunction();
console.profileEnd();
}
Writing console messages
Console.writeLine("..."); // can keep in code and will get taken out of production
Using debug class:
Debug.WriteLine("..."); // can keep in code and will get taken out of production
Using Trace class:
Trace.WriteLine("..."); // stays in production code -> can be saved to log files
Performance Monitor Performance Counter
Testing a function - Two Approaches
bool isLastNumberEven (array unsortedArray) {
int length = unsortedArray.length;
if (unsortedArray[length] % 2 == 0) {
return true;
}
return false;
}
int CountAllEvenNumbers(array unsorted Array) {
int evenNumberCount = 0;
for (int i = 0; i < unsortedArray.length; i++) {
if (unsortedArray[i] % 2 == 0) evenNumberCount++;
}
return evenNumberCount;
}
bool findDuplicates (array unsortedArray) {
for each integer A in unsortedArray {
for each integer B in unsortedArray {
if (A.index == B.index) continue;
if (A == B) return true;
}
}
return false;
}
Usually want to avoid quadratic time
Used by better sorting algorithms
Traveling Salesman (brute force)
Iterations -> potential for improvement is high
Collections ->
Always profile Research collection types Think about what the statements need to do Concentrate effort on iterated code Beware large strings Realize some things just take time
(HD, SSD, External Storage)
Main memory reference: 100ns Read: 1 MB 20,000ns - 100,000ns Drive seek: 4,000,000ns - 10,000,000ns Drive read: 1 MB 2,000,000ns - 20,000,000ns There are warm up costs for using the disk
fs_usage
-> Instruments - try to find bottlenecks
Only read in a file if you need it
Group small reads/writes
Minimize network latency 1 - Client request to server 2 - Server processing 3 - Server response to client
1 + 2 + 3 = latency (delay)
In Network tab of Developer Tools: Time to first byte (latency) Time to get whole resource (timeline)
Distance affects latency
It's not always a network issue
Chunky, not chatty
Move assets closer
Compress your information
Specialized area
Begins with normalization
Consider each statement
Web application => server side
Client-side
Mobile Applications
Desktop Applications:
Work on improving startup time
Better use of multithreading for UI
First, do nothing You don't know what the problem is until you measure it Understand what's under your control Always look for the easy win