Performance is a Feature!
Why does performance matter?
What do we need to measure?
How we can fix the issues?
Front-end
Database & Caching
.NET CLR
Mechanical
Sympathy
How?
Measure, measure, measure
1. Identify bottlenecks
2. Know the optimisation works
How?
“The simple act of putting a render time in the upper right hand corner of every
page we serve forced us to fix all our performance regressions and omissions.”
How?
https://github.com/opserver/Opserver
How?
https://github.com/opserver/Opserver
How?
The Art of Benchmarking
Profiling -> Micro-benchmarks
static void Profile(int iterations, Action action)
{
action(); // warm up
GC.Collect(); // clean up
var watch = new Stopwatch();
watch.Start();
for (int i = 0; i < iterations; i++)
{
action();
}
watch.Stop();
Console.WriteLine("Time Elapsed {0} ms",
watch.ElapsedMilliseconds);
}
http://stackoverflow.com/questions/1047218/benchmarking-small-
code-samples-in-c-can-this-implementation-be-improved
private static T Result;
static void Profile<T>(int iterations, Func<T> func)
{
func(); // warm up
GC.Collect(); // clean up
var watch = new Stopwatch();
watch.Start();
for (int i = 0; i < iterations; i++)
{
Result = func();
}
watch.Stop();
Console.WriteLine("Time Elapsed {0} ms",
watch.ElapsedMilliseconds);
}
BenchmarkDotNet
BenchmarkDotNet Demo
How?
Garbage Collection (GC)
Allocations are cheap, but cleaning up isn’t
Difficult to measure the impact of GC
http://www.slideshare.net/benemmett/net-memory-management-ndc-london
https://vimeo.com/113632451
Stack Overflow Performance Lessons
Stack Overflow Performance Lessons
Use static classes
Don’t be afraid to write your own tools
Dapper, Jil, MiniProfiler,
Intimately know your platform - CLR
Roslyn Performance Lessons 1
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);
}
}
Essential Truths Everyone Should Know about Performance in a Large Managed Codebase
Roslyn Performance Lessons 1
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.ToString(), size.ToString());
Logger.WriteLine(s);
}
}
AVOID BOXING
Roslyn Performance Lessons 2
class Symbol {
public string Name { get; private set; }
/*...*/
}
class Compiler {
private List<Symbol> symbols;
public Symbol FindMatchingSymbol(string name)
{
return symbols.FirstOrDefault(s => s.Name == name);
}
}
Roslyn Performance Lessons 2
class Symbol {
public string Name { get; private set; }
/*...*/
}
class Compiler {
private List<Symbol> symbols;
public Symbol FindMatchingSymbol(string name)
{
foreach (Symbol s in symbols)
{
if (s.Name == name)
return s;
}
return null;
}
}
DON’T USE LINQ
Roslyn Performance Lessons 3
public class Example
{
// Constructs a name like "Foo<T1, T2, T3>"
public string GenerateFullTypeName(string name, int arity)
{
StringBuilder sb = new StringBuilder();
sb.Append(name);
if (arity != 0)
{
sb.Append("<");
for (int i = 1; i < arity; i++)
{
sb.Append('T'); sb.Append(i.ToString());
}
sb.Append('T'); sb.Append(arity.ToString());
}
return sb.ToString();
}
}
Roslyn Performance Lessons 3
public class Example
{
// Constructs a name like "Foo<T1, T2, T3>"
public string GenerateFullTypeName(string name, int arity)
{
StringBuilder sb = new AcquireBuilder();
sb.Append(name);
if (arity != 0)
{
sb.Append("<");
for (int i = 1; i < arity; i++)
{
sb.Append('T'); sb.Append(i.ToString());
}
sb.Append('T'); sb.Append(arity.ToString());
}
return GetStringAndReleaseBuilder(sb);
}
}
OBJECT POOLING
Roslyn Performance Lessons 3
[ThreadStatic]
private static StringBuilder cachedStringBuilder;
private static StringBuilder AcquireBuilder()
{
StringBuilder result = cachedStringBuilder;
if (result == null)
{
return new StringBuilder();
}
result.Clear();
cachedStringBuilder = null;
return result;
}
private static string GetStringAndReleaseBuilder(StringBuilder sb)
{
string result = sb.ToString();
cachedStringBuilder = sb;
return result;
}
Roslyn Performance Lessons Demo
Resources
Questions?
@matthewwarren
www.mattwarren.org

Performance is a feature! - Developer South Coast - part 2

  • 1.
  • 2.
    Why does performancematter? What do we need to measure? How we can fix the issues?
  • 3.
    Front-end Database & Caching .NETCLR Mechanical Sympathy
  • 4.
    How? Measure, measure, measure 1.Identify bottlenecks 2. Know the optimisation works
  • 5.
    How? “The simple actof putting a render time in the upper right hand corner of every page we serve forced us to fix all our performance regressions and omissions.”
  • 6.
  • 7.
  • 8.
    How? The Art ofBenchmarking Profiling -> Micro-benchmarks
  • 9.
    static void Profile(intiterations, Action action) { action(); // warm up GC.Collect(); // clean up var watch = new Stopwatch(); watch.Start(); for (int i = 0; i < iterations; i++) { action(); } watch.Stop(); Console.WriteLine("Time Elapsed {0} ms", watch.ElapsedMilliseconds); } http://stackoverflow.com/questions/1047218/benchmarking-small- code-samples-in-c-can-this-implementation-be-improved
  • 10.
    private static TResult; static void Profile<T>(int iterations, Func<T> func) { func(); // warm up GC.Collect(); // clean up var watch = new Stopwatch(); watch.Start(); for (int i = 0; i < iterations; i++) { Result = func(); } watch.Stop(); Console.WriteLine("Time Elapsed {0} ms", watch.ElapsedMilliseconds); }
  • 11.
  • 12.
  • 13.
    How? Garbage Collection (GC) Allocationsare cheap, but cleaning up isn’t Difficult to measure the impact of GC http://www.slideshare.net/benemmett/net-memory-management-ndc-london https://vimeo.com/113632451
  • 16.
  • 18.
    Stack Overflow PerformanceLessons Use static classes Don’t be afraid to write your own tools Dapper, Jil, MiniProfiler, Intimately know your platform - CLR
  • 20.
    Roslyn Performance Lessons1 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); } } Essential Truths Everyone Should Know about Performance in a Large Managed Codebase
  • 21.
    Roslyn Performance Lessons1 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.ToString(), size.ToString()); Logger.WriteLine(s); } } AVOID BOXING
  • 22.
    Roslyn Performance Lessons2 class Symbol { public string Name { get; private set; } /*...*/ } class Compiler { private List<Symbol> symbols; public Symbol FindMatchingSymbol(string name) { return symbols.FirstOrDefault(s => s.Name == name); } }
  • 23.
    Roslyn Performance Lessons2 class Symbol { public string Name { get; private set; } /*...*/ } class Compiler { private List<Symbol> symbols; public Symbol FindMatchingSymbol(string name) { foreach (Symbol s in symbols) { if (s.Name == name) return s; } return null; } } DON’T USE LINQ
  • 24.
    Roslyn Performance Lessons3 public class Example { // Constructs a name like "Foo<T1, T2, T3>" public string GenerateFullTypeName(string name, int arity) { StringBuilder sb = new StringBuilder(); sb.Append(name); if (arity != 0) { sb.Append("<"); for (int i = 1; i < arity; i++) { sb.Append('T'); sb.Append(i.ToString()); } sb.Append('T'); sb.Append(arity.ToString()); } return sb.ToString(); } }
  • 25.
    Roslyn Performance Lessons3 public class Example { // Constructs a name like "Foo<T1, T2, T3>" public string GenerateFullTypeName(string name, int arity) { StringBuilder sb = new AcquireBuilder(); sb.Append(name); if (arity != 0) { sb.Append("<"); for (int i = 1; i < arity; i++) { sb.Append('T'); sb.Append(i.ToString()); } sb.Append('T'); sb.Append(arity.ToString()); } return GetStringAndReleaseBuilder(sb); } } OBJECT POOLING
  • 26.
    Roslyn Performance Lessons3 [ThreadStatic] private static StringBuilder cachedStringBuilder; private static StringBuilder AcquireBuilder() { StringBuilder result = cachedStringBuilder; if (result == null) { return new StringBuilder(); } result.Clear(); cachedStringBuilder = null; return result; } private static string GetStringAndReleaseBuilder(StringBuilder sb) { string result = sb.ToString(); cachedStringBuilder = sb; return result; }
  • 27.
  • 28.
  • 29.

Editor's Notes

  • #2 Who has:      - any perf requirements     - perf requirements with numbers!     - any perf tests     - perf test that are run continuously
  • #4 Front-end - YSlow, Google PageSpeed, CDN & caching    - "High Performance Web Sites" by Steve Sounder Database & caching - Learn to use SQL Profiler  - Redis or similar - MiniProfiler .NET (server-side) <- This is what we are looking at Mechanical Sympathy - Anything by Martin Thompson - Disruptor and Disruptor.NET  - CPU caches (L1, L2, etc) - memory access patterns
  • #5 You’ll probably guess wrong!! Consider adding performance unit tests, Noda-Time does this, can graph performance over time, see if it’s regressed!!
  • #6 MiniProfiler Turn this on in Development and if possible in Production Glimpse is an alternative
  • #7 Runs on .NET, Puts everything in 1 place, Web Server & Database Summary metrics up front Can drill-down into detailed metrics, including executed SQL, page load times, etc
  • #9 Make sure you are really measuring what you think you are measuring!!
  • #10 Warm up – For the JITter Get GC out of the way Lots of iterations Use Stopwatch, NOT DateTime.Now Have to be weary of the JITter
  • #11 JITter will remove functions call if the return value isn’t used (sometimes) Still not perfect, loop overhead can dominate!!! So unr POSSIBLE DEMO (if time)
  • #12 Make sure you are really measuring what you think you are measuring!!
  • #13 Make sure you are really measuring what you think you are measuring!!
  • #14 Both StackOverflow and Roslyn affected by this!!!!! In the .NET Framework 4.5, there is background server garbage collection (before .NET 4.5 was Workstation only) So until .NET 4.5, Server GC was STOP-THE-WORLD In .NET 4.6 there is now TryStartNoGCRegion and EndNoGCRegion
  • #15 Process Explorer From Sysinternals
  • #16 PerfView is a stand-alone utility, to help you debug CPU and memory problems Light-weight and non-intrusive, can be used to on production apps with minimal impact Uses ETW (Event Tracing for Windows), designed to be v. fast!!!!
  • #17 Just and intro Don’t need to say anything else here!
  • #18 They were able to graph these results & equate them to Garbage Collector pauses!!! They had good logging and measurements in place,
  • #20 Ask "Any questions so far?” At this point should be ~45 minutes in Not long left!!!
  • #21 They measured and found that all of these were on the HOT PATH
  • #30 Repeat questions back to the audience!!!!!