Faster Haskell. Neil Mitchell

Similar documents
Fastest Lambda First. Neil Mitchell.

Optimising Functional Programming Languages. Max Bolingbroke, Cambridge University CPRG Lectures 2010

A Supercompiler for Core Haskell

Transformation and Analysis of Haskell Source Code

CSCE 314 Programming Languages

Shell CSCE 314 TAMU. Higher Order Functions

References. Monadic I/O in Haskell. Digression, continued. Digression: Creating stand-alone Haskell Programs

CS457/557 Functional Languages

Parser Design. Neil Mitchell. June 25, 2004

Simon Peyton Jones Microsoft Research August 2013

Functional Programming - 2. Higher Order Functions

Uniform Boilerplate and List Processing

Simon Peyton Jones Microsoft Research August 2012

Dynamically-typed Languages. David Miller

Urmas Tamm Tartu 2013

Once Upon a Polymorphic Type

Haskell & functional programming, some slightly more advanced stuff. Matteo Pradella

Parallel Functional Programming Lecture 1. John Hughes

A Brief Haskell and GHC Refresher

CSc 372. Comparative Programming Languages. 11 : Haskell Higher-Order Functions. Department of Computer Science University of Arizona

Lecture 5: Lazy Evaluation and Infinite Data Structures

CSc 520 Principles of Programming Languages. Currying Revisited... Currying Revisited. 16: Haskell Higher-Order Functions

Programming Languages and Compilers (CS 421)

Haskell Refresher Informatics 2D

Functional Programming in Haskell for A level teachers

Haskell: From Basic to Advanced. Part 3 A Deeper Look into Laziness

n What is its running time? 9/18/17 2 n poor_rev [1,2,3] = n (poor_rev [1] = n ((poor_rev [1] =

Iteration. Side effects

Push/enter vs eval/apply. Simon Marlow Simon Peyton Jones

CITS3211 FUNCTIONAL PROGRAMMING. 6. Folding operators

Tail Recursion. ;; a recursive program for factorial (define fact (lambda (m) ;; m is non-negative (if (= m 0) 1 (* m (fact (- m 1))))))

Short Notes of CS201

Static Contract Checking for Haskell

Weaving Source Code into ThreadScope

CS113: Lecture 4. Topics: Functions. Function Activation Records

Fibonacci in Lisp. Computer Programming: Skills & Concepts (CP1) Programming Languages. Varieties of Programing Language

Functional Programming and Haskell

CS Lecture 6: Map and Fold. Prof. Clarkson Fall Today s music: Selections from the soundtrack to 2001: A Space Odyssey

CS 11 Haskell track: lecture 1

CS Lecture 6: Map and Fold. Prof. Clarkson Spring Today s music: Selections from the soundtrack to 2001: A Space Odyssey

Compiler Construction

CS201 - Introduction to Programming Glossary By

CSE341: Programming Languages Lecture 6 Nested Patterns Exceptions Tail Recursion. Zach Tatlock Winter 2018

Solution sheet 1. Introduction. Exercise 1 - Types of values. Exercise 2 - Constructors

Extended Static Checking for Haskell (ESC/Haskell)

FP Implementation. Simon Marlow PLMW 15

Dynamic analysis in the Reduceron. Matthew Naylor and Colin Runciman University of York

Compiler Construction

Compiler Construction Lent Term 2015 Lectures 10, 11 (of 16)

Functional Programming in C++

Stream Fusion. From Lists to Streams to Nothing at All. 2 Computer Science & Engineering

Hoogλe Fast Type Searching

Types and Type Inference

Lightweight Concurrency Primitives for GHC. Peng Li Simon Peyton Jones Andrew Tolmach Simon Marlow

Unboxing Sum Types. Johan Tibell - FP-Syd

Stream Fusion. Wouter Swierstra 30/11/2010

NOTE: Answer ANY FOUR of the following 6 sections:

Datatype declarations

Introduction to Haskell

Lazy Functional Programming in Haskell

The Haskell HOP: Higher-order Programming

Lecture 05: Methods. AITI Nigeria Summer 2012 University of Lagos.

Compiler Construction

Implementing Type-Based Deforestation. by Marie-Christine (Kirsten) Chevalier. Research Project

CSE 130 [Winter 2014] Programming Languages

COMP 202 Recursion. CONTENTS: Recursion. COMP Recursion 1

Lecture 4: Higher Order Functions

Informatics 1 Functional Programming Lecture 4. Lists and Recursion. Don Sannella University of Edinburgh

Semantic Analysis. Outline. The role of semantic analysis in a compiler. Scope. Types. Where we are. The Compiler Front-End

Simon Peyton Jones Microsoft Research. August 2012

Introduction to Functional Programming

COMPILER DESIGN - RUN-TIME ENVIRONMENT

CS201 Some Important Definitions

CS 457/557: Functional Languages

CS/ENGRD 2110 Object-Oriented Programming and Data Structures Spring 2012 Thorsten Joachims. Lecture 10: Asymptotic Complexity and

Continuations and Continuation-Passing Style

Haske k ll An introduction to Functional functional programming using Haskell Purely Lazy Example: QuickSort in Java Example: QuickSort in Haskell

Administration CS 412/413. Why build a compiler? Compilers. Architectural independence. Source-to-source translator

Functional Programming for Logicians - Lecture 1

Functional Programming in Haskell Part I : Basics

Programming Paradigms and Languages Introduction to Haskell. dr Robert Kowalczyk WMiI UŁ

FORM 2 (Please put your name and form # on the scantron!!!!)

Standard prelude. Appendix A. A.1 Classes

New Mapping Interface

The role of semantic analysis in a compiler

Instances for Free* Neil Mitchell (* Postage and packaging charges may apply)

An introduction introduction to functional functional programming programming using usin Haskell

Running Valgrind on multiple processors: a prototype. Philippe Waroquiers FOSDEM 2015 valgrind devroom

Scope, Functions, and Storage Management

C Functions. CS 2060 Week 4. Prof. Jonathan Ventura

Generative and accumulative recursion. What is generative recursion? Example revisited: GCD. Readings: Sections 25, 26, 27, 30, 31

f() ! " Run a higher-priority task? ! " Yield the processor to another task because our ! " Use the processor for some other activity while

CS 410/510: Advanced Programming

RACKET BASICS, ORDER OF EVALUATION, RECURSION 1

A general introduction to Functional Programming using Haskell

CSE P 501 Compilers. Java Implementation JVMs, JITs &c Hal Perkins Winter /11/ Hal Perkins & UW CSE V-1

Principles of Programming Languages Topic: Scope and Memory Professor Louis Steinberg Fall 2004

CS 160: Interactive Programming

Side Effects (3A) Young Won Lim 1/13/18

3. Functional Programming. Oscar Nierstrasz

Transcription:

Faster Haskell Neil Mitchell www.cs.york.ac.uk/~ndm

The Goal Make Haskell faster Reduce the runtime But keep high-level declarative style Full automatic - no special functions Different from foldr/build, steam/unstream Whole program optimisation But fast (developed in Hugs!)

Word Counting In Haskell main = print. length. words =<< getcontents Very high level A nice specification of the problem Note: getcontents reimplemented in terms of getchar

And in C int main() { int i = 0, c, last_space = 1; while ((c = getchar())!= EOF) { int this_space = isspace(c); if (last_space &&!this_space) i++; last_space = this_space; } printf("%i\n", i); return 0; } About 3 times faster than Haskell

Why is Haskell slower? Intermediate lists! (and other things) GHC goes through 4Gb of memory O(n) C requires ~13Kb O(1) length. words =<< getcontents getcontents produces a list words consumes a list, produces a list of lists length consumes the outer list

Removing the lists GHC already has foldr/build fusion map f (map g x) == map (f. g) x But getcontents is trapped under IO Much harder to fuse automatically Don t want to rewrite everything as foldr Easy to go wrong (take function in GHC 6.6)

Supero: My Optimiser Fully automatic No annotations, special functions Evaluate the program at compile time Start at main, and execute Stop when you reach a primitive The primitive is in the optimised program

With wordcount main r (print. length. words =<< getcontents) r (getcontents >>= print. length. Words) r case getcontents r of (# s, r #) -> getchar >>= if c == 0 then return [] else case getchar r of Have reached a case on a primitive

The new program main r = case getchar r of (# c, r #) -> main2 c r Create main2, for the alternative Continue optimisation on the branches of the case, main2 The evaluation mainly does inlining Also case/case, case/ctor, let movement

Tying in the knot Each name in the new program corresponds to an expression in the old main = print. length. words =<< getcontents main2 = the case alternative If you reach the same expression, use the same name makes recursive call

Summing a list sum x = case x of [] -> 0 (x:xs) -> x + sum xs range i n = case i > n of True -> [] False -> i : range (i+1) n main n = sum (range 0 n)

Evaluate main n sum (range 0 n) main n = main2 0 n where main2 i n = sum (range i n) case range i n of {[] -> 0; x:xs -> x + sum xs} case (case i > n of {True -> []; False -> }) of case i > n of {True -> 0 ;False -> i + sum (range (i+1) n)} tie back: main2 (i+1) n

The Result main n = main2 i n main2 i n = if i > n then 0 else i + main2 (i+1) n Lists have gone entirely Everything is now strict Using sum as foldl or foldl would have given accumulator version

Ensuring Termination To make the optimisation terminate Need to hide some information Anything which is an accumulator i.e. foldl s 2 nd argument Lots of possible termination criteria Want to give good optimisation But not blow up the size of the code

Termination Problems One theme bound recursion depth Problem 1: Some optimisations require ~5 recursive inlinings 5 recursive inlinings blows up code a lot Problem 2: Repeated application can square any bound Bound of 5 can become a bound of 25!

Back to word counting What if we use Supero on the Haskell? Compile using yhc, to Yhc.Core Optimise, using Supero Write out Haskell, compile with GHC GHC provides: Strictness/unboxing Native code generator

Problem 1: isspace On GHC, isspace is too slow (bug 1473) C's isspace: 0.375 C's iswspace: 0.400 Char.isSpace: 0.672 For this test, I use the FFI SOLVED!

Problem 2: words words :: String -> [String] words s = case dropwhile isspace s of "" -> [] s' -> w : words s'' where (w, s'') = break isspace s' Does two extra isspace tests per word Better version in Yhc SOLVED!

Other Problems Wrong strictness information (bug 1592) IO functions do not always play nice Badly positioned heap checks (bug 1498) Tight recursive loop, where all time is spent Allocates only on base case (once) Checks for heap space every time Unnecessary stack checks Probably ~15% slowdown Pending

Performance Now Supero+GHC is 10% faster than C! Somewhat unexpected Can anyone guess why? while ((c = getchar())!= EOF) int this_space = isspace(c); if (last_space &&!this_space) i++; last_space = this_space;

The Inner Loop space/not C Haskell not/space Haskell encodes space/not in the program counter! Hard to express in C

The wc benchmark 25 20 15 10 C Supero GHC 5 0 charcount linecount wordcount

Haskell Benchmarks Working towards the nofib/nobench suite Termination vs optimisation problem Massively more complex Much larger volumes of code Particular issues The read function Invoking a Haskell lexer to read an Int! List comprehensions (as desugared by Yhc)

Conclusions Still lots of work to do before concluding! Nobench is a priority Haskell can be both beautiful and fast Thanks to: Simon Peyton Jones, Simon Marlow, Tim Chevalier for low-level GHC help