A package of C# life savers

Florian Rappl, MVP Visual C#

A package of C# life savers

performance optimizations and design considerations

A package of life savers

About me (technologies)

C#

JavaScript

C/C++

App

WinForms, WPF, Azure

Web

HTML5, ASP.NET MVC

HPC

Intel MIC, OMP, MPI

About me (publicity)

  • CodeProject MVP
  • Most articles about C# and JavaScript
  • Advertising open-source projects
  • Microsoft MVP for Visual C#
  • Lectures about C# at the University
  • Tutorials in various (online) magazines
  • Attended several competitions
  • Won App Innovation Contest, Perceptual Computing
  • Writing technical articles for IDZ

Motivation

  • The bad news
    • High performance doesn't just happen!
    • We have to design them that way!
    • Thus most performance is lost very early
    • Most designs consider performance too late in dev
  • The good news
    • Most (~95%) of our application is not performance critical
    • Generally it is easy to identify the critical sections

Agenda

  1. Cherry: Lambda expressions
  2. Raspberry: Asynchronous patterns
  3. Orange: Potential optimizations
  4. Pineapple: Best practices
  5. Watermelon: Some tricks
Cherry flavor

Lambda expressions

  • With LINQ they are everywhere (very comfortable)
  • They improve code maintenance and reliability
  • More possibilities than anonymous methods (Expression)
  • Also shorter to write than anonymous methods:
    Func<double, double> g = delegate (double x) { return x * x; };
    Func<double, double> f = x => x * x;
    
  • Another good usage: closure (compiler generates a class for us)

Improving code maintenance

  • Scenario: map user input to a function
  • Usually this is done by using a switch statement
  • Sometimes a Dictionary gives us more flexibility:
    var functions = new Dictionary<string, Func<double, double>>();
    void Init() {
    	functions.Add("sin", Math.Sin); 
    	functions.Add("cos", Math.Cos); /* and others */
    }
    public double Evaluate(string f, double x) {
    	//Let's just assume that the specified function exists
    	return functions[f](x);
    }
    

Thread communication

  • Communication with the SynchronizationContext
  • The closure handles everything for us:
    var ctx = SynchronizationContext.Current ?? new SynchronizationContext();
    public event EventHandler<MyEventArgs> Event;
    public void RaiseEvent() {
    	if(Event != null)
    		ctx.Post(o => Event(this, new MyEventArgs(a1, ..., an)), null);
    }
    
  • No casts and no parameter (passed null) required

Useful JavaScript patterns

  • Callback pattern (e.g. events, ...)
  • Returning functions (e.g. closures, ...)
  • Init-time branching (e.g. handlers, ...)
  • Self-defining functions (e.g. state-machine, ...)

Example: Self-defining functions

  • Pattern requires a global or local delegate
  • Idea is that any function can change the delegate
  • Hence the delegate could change itself
  • Very useful if a function should change itself
  • Could increase performance in special cases

Example code

class Greeter {
	public Greeter() {
		SayHello = () => {
			SayHello = () => {
				SayHello = () => {
					return "Stop it for God's sake!"
				};
				return "I already said hello!";
			};
			return "Hello";
		};
	}
	public Func<string> SayHello { get; private set; }
}
Raspberry flavor

Asynchronous patterns

  • Using async. APIs is the key for responsive apps
  • Key question: CPU or IO bound?
  • IO bound tasks are attacked by callbacks
  • CPU bound tasks are attacked by multi-threading
  • The TPL covers both scenarios with Task
  • C# 5 introduces async / await

Decorating methods as async

// A usual (non-async) method
int ComputeNumber() {
	return 42;
}
// Decorate method as being async - will be wrapped automatically
async Task<int> ComputeNumberAsync() {
	return 42;
}
// Can be used as always
var answer = ComputeNumberAsync().Result;
// Or with await
var answer = await ComputeNumberAsync();
// Important: No new thread or similar has been created previously
var answer = await Task.Run(ComputeNumber);

Using await

// Auto-wrapping by using async is required for await
async Task ComputeNumberAsync() {
	/* Do some UI changes (in UI / current thread) */
	var result = await LongRunningTask();
	/* Do some UI changes (back in UI / current thread) */
}

Dos and don'ts

  • Always prefer using async Methods if available
  • Always return Task or Task<T>
  • Only return void in case of event handlers
  • Do not use Task.Run in case of memory bound methods
  • Use ConfigureAwait(false) for creating APIs
  • Build async. methods using the TaskCompletionSource

Building a statemachine

Asynchronous events

// Creating extension methods like this
public static async Task WhenClicked(this Button button) {
	var tcs = new TaskCompletionSource<bool>();
	RoutedEventHandler ev = (sender, evt) => tcs.TrySetResult(true);
	//This is a perfect async. code, no other thread required
	try {
		button.Click += ev;
		await tcs.Task;
	} finally {
		button.Click -= ev;
	}
}
// Using them
await button.WhenClicked();
Orange flavor

How can we optimize code?

Potential optimizations

  • Detect the code's hot path
  • Don't optimize unimportant aspects
  • Maintain readability where possible
  • Use a good profiler for analysis
  • Look at MSIL for details
  • Use micro-benchmarks for comparisons
  • Build caches only with discard policy

Using PerfView

  • CPU, managed memory and blocked time investigation
  • Investigate performance hotspots
  • Can be used to make an analysis of any process
  • Logs data and presents the data
  • Is able to show potential bottlenecks
  • Uses ETW (Event-Tracing for Windows) kernel routine
  • Additionally we could also use tools like VMMap

PerfView 101

  • Use (and read!) integrated help
  • Select right process(es) with at least 2000 stack dumps
  • Always look at right data (e.g. Metric/msec ≥ 0.5)
  • Look at significant time range
  • The call-tree gives us a nice top-down approach
  • For bottom-up we would use the by-name tab

The biggest bottlenecks

  • LINQ queries (~15% and more)
  • Abstract or virtual methods
  • Using unnecessary large objects
  • GC pollution / pressure
  • Frequent boxing / unboxing
  • Any kind of allocation smell

Allocation "smells"

  • Boxing
  • Strings and string manipulation
  • Iterators
  • Delegates and lambdas
  • Collections (Dictionary, ConcurrentDictionary, etc.)
  • IDisposable guard objects
  • EventHandler

Example: Boxing

public class Logger {
	public static void WriteLine(string s) { /*...*/ }
}
public class BoxingExample {
	public void Log(int id, int size) {
		var s = string.Format("{0}:{1}", id, size);
		Logger.WriteLine(s);
	}
}

Example: Boxing (fix)

Compiler selects string.Format(string, object, object).

public class BoxingExample {
	public void Log(int id, int size) {
		var s = string.Format("{0}:{1}", id.ToString(), size.ToString());
		Logger.WriteLine(s);
	}
}

Example: Boxing (alternative)

public class Logger {
	public static void WriteLine(string s) { /*...*/ }
}
public class BoxingExample {
	public void Log(int id, int size) {
		var s = id.ToString() + ':' + size.ToString();
		Logger.WriteLine(s);
	}
}

Example: Boxing (alternative)

Compiled to string.Concat(object, object, object).

public class BoxingExample {
	public void Log(int id, int size) {
		var s = id.ToString() + ":" + size.ToString();
		Logger.WriteLine(s);
	}
}

Another Example: Boxing

public enum Color {
	Red, Green, Blue
}
public class BoxingExample {
	string name;
	Color color;
	public override int GetHashCode() {
		return name.GetHashCode() ^ color.GetHashCode();
	}
}

The enum value is boxed - use (int)color before calling GetHashCode.

Example: LINQ

class Symbol {
	public string Name { get; private set; }
	/*...*/
}
class Compiler {
	List<Symbol> symbols;
	public Symbol FindMatchingSymbol(string name) {
		return symbols.FirstOrDefault(s => s.Name == name);
	}
}

Example: LINQ (unrolled)

class Compiler {
	List<Symbol> symbols;
	public Symbol FindMatchingSymbol(string name) {
		Func<Symbol, bool> predicate = s => s.Name == name;
		IEnumerable<Symbol> enumerable = symbols;
		IEnumerator<Symbol> enumerator = enumerable.GetEnumerator();
		while(enumerator.MoveNext()) {
			if (predicate(enumerator.Current))
				return enumerator.Current;
		}
		return default(Symbol);
	}
}

Example: LINQ (fix)

class Compiler {
	List<Symbol> symbols;
	public Symbol FindMatchingSymbol(string name) {
		foreach (Symbol s in symbols) {
			if (s.Name == name)
				return s;
		}
		return null;
	}
}

Reduction of GC pressure

  • Try to minimize creation of new instances
  • Use structures for small temp. objects
  • Prefer static methods where possible
  • The same applies to fields
  • Create permanent objects before temporary ones
Pineapple flavor

StringBuilder pooling

  • Many StringBuilder instances are unnecessary
  • Concatenations are (sometimes) acceptable
  • Otherwise use pooling
  • 1-2 are usually enough
  • Avoid format helpers if possible

Reduce allocations

  • Class allocations put pressure on the GC
  • They also require memory and computing time
  • Use same principle as with StringBuilder
  • Try to minimize (re-) allocations
  • For really small objects prefer struct

Example: String allocations

string[] lines = text.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
int numLines = lines.Length; bool skipSpace = true;
if (lines[0].TrimStart().StartsWith("///")) {
	for (int i = 0; i < numLines; i++) {
		string trimmed = lines[i].TrimStart();
		if (trimmed.Length < 4 || !char.IsWhiteSpace(trimmed[3])) {
			skipSpace = false;
			break;
		}
	}
	int substringStart = skipSpace ? 4 : 3;
	for (int i = 0; i < numLines; i++)
		WriteLine(lines[i].TrimStart().Substring(substringStart));
} else { /* ... */ }

Example: String allocations (fix)

int IndexOfFirstNonWhiteSpaceChar(string text, int start) {
	while (start < text.Length && char.IsWhiteSpace(text[start]))
		start++;
	return start;
}
bool TrimmedStringStartsWith(string text, int start, string prefix) {
	start = IndexOfFirstNonWhiteSpaceChar(text, start);
	int len = text.Length - start;
	if (len < prefix.Length) return false;
	for (int i = 0; i < len; i++) {
		if (prefix[i] != text[start + i]) return false;
	}
	return true;
}
// etc...

Using structures

  • Any class needs at least 12 bytes (x86)
  • Classes smaller than 16 bytes are more efficiently handled as struct
  • Structures should not contain more than 64 bytes in data
  • Watch out for repeated calls to property getters that return a struct
  • Try to avoid boxing (will be put on the heap then)

Benefits and disadvantages of generics

  • Generics reduce casts
  • They also improve type safety
  • Less casts is less boxing / unboxing
  • The hidden cost is the type transportation
  • But: e.g. List<string> is faster than StringCollection
  • In most cases using the generic version is better

Async void failure

BitmapImage m_bmp;
protected override async void OnNavigatedTo(NavigationEventArgs e) {
	base.OnNavigatedTo(e);
	await PlayIntroSoundAsync();
	image1.Source = m_bmp;
	Canvas.SetLeft(image1, Window.Current.Bounds.Width - m_bmp.PixelWidth);
}
protected override async void LoadState(Object nav, Dictionary<String, Object> pageState) {
	m_bmp = new BitmapImage();
	var file = await StorageFile.GetFileFromApplicationUriAsync("...");
	using (var stream = await file.OpenReadAsync())
		await m_bmp.SetSourceAsync(stream);
}

Async void failure

  • What is happening here?
  • Why is no image shown on the screen?
  • But sometimes we can see an image ...
  • The problem is a race condition
  • Two tasks are competing against each other

Simple solution

Task<BitmapImage> m_bmpTask;
protected override async void OnNavigatedTo(NavigationEventArgs e) {
	base.OnNavigatedTo(e);
	await PlayIntroSoundAsync();
	var bmp = await m_bmpTask;
	image1.Source = bmp;
	Canvas.SetLeft(image1, Window.Current.Bounds.Width - bmp.PixelWidth);
}
protected override void LoadState(/* ... */) {
	m_bmpTask = LoadBitmapAsync();
}
async Task<BitmapImage> LoadBitmapAsync() {
	var bmp = new BitmapImage(); /* ... */ return bmp;
}

Watch out with async lambdas

try {
	await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
	{
		await LoadAsync();
		m_Result = "done";
		throw new Exception();
	});
} catch (Exception) {
	/* will not be entered */
} finally {
	DebugPrint(m_Result);
}

What did go wrong?

  • Everything seems alright
  • LoadAsync is invoked
  • But we skip the catch block
  • Reason: No async overload
  • Therefore the rest is fire-and-forget
  • Fire-and-forget does not throw exceptions
Watermelon flavor

Unions with C#

[StructLayout(LayoutKind.Explicit, Pack = 1)]
struct Number {
	[FieldOffset(0)]
	public int Value;
	[FieldOffset(0)]
	public byte First;
	[FieldOffset(1)]
	public byte Second;
	[FieldOffset(2)]
	public byte Third;
	[FieldOffset(3)]
	public byte Fourth;
}

Sealing methods

  • Sealing classes stops inheritance chain
  • Sealing only (single) methods or properties also possible
  • abstract class Mother {
    	public abstract void DoSomething();
    }
    class Daughter {
    	public sealed override void DoSomething() { }
    }
    
  • Still callvirt instead of call
  • However, possibility to stop overriding

Weak event handlers

  • Handlers are often source of memory leaks
  • Problem: Delegate makes listener a strong reference
  • The solution is to wrap listener in a weakly referenced object (WeakReference)
  • The target method has to be stored separately

Example: Add and remove event handlers

WeakEvent<EventHandler> _event = new WeakEvent<EventHandler>();
//Let public event appear normally
public event EventHandler Event {
	add { _event.Add(value); }
	remove { _event.Remove(value); }
}
//Fire over a special method (good practice anyway)
public void RaiseEvent() {
	_event.Raise(this, EventArgs.Empty);
}
//Using it is straight forward:
someClassInstance.Event += MyEventHandler;

Readonly and constants

  • Usually readonly should be preferred
  • const has the advantage of allowing switch
  • Advantage of readonly: Changes affect external code
  • Marking PI as a constant is valid
  • Marking some connection string / url as a constant is bad
  • Changing the value requires re-compilation of ref. assemblies

Most useful attributes

[Flags]
enum MyBitFlag { /* ... */ }
[DebuggerStepThrough]
void MyShortHelper() { /* ... */ }
[Conditional("DEBUG")]
void MyDebuggingHelper() { /* ... */ }
[DebuggerDisplay("FirstName={FirstName}, LastName={LastName}")]
class MyClass { /* ... */ }
[ThreadStatic]
static StringBuilder cachedStringBuilder;

Improve MVVM binding

  • Never pass in strings as property names
  • Use the CallerMemberName attribute
  • Alternatively use an Expression
  • First one is shorter to write
  • Second one is more flexible
static string GetName([CallerMemberName] string name = null) {
	return name ?? string.Empty;
}

Any questions?

Contact me any time ...