© Stefania Loredana Nita and Marius Mihailescu 2019
Stefania Loredana Nita and Marius MihailescuHaskell Quick Syntax Referencehttps://doi.org/10.1007/978-1-4842-4507-1_22

22. Performance

Stefania Loredana Nita1  and Marius Mihailescu1
(1)
Bucharest, Romania
 

Sometimes your program will need to meet some requirements for space and time execution. It is really important to know how the data is represented, what lazy evaluation or strict evaluation involves, and how to control the space and time behavior. In this chapter, you will learn basic techniques to improve the performance of your programs.

Type Signatures

If you don’t specify the type signatures, GHC will provide you with a warning about defaults and missing types. It is important to explicitly name the types. For example, the default type for the integer values is Integer, which is ten times slower than Int.

Optimization Flags

When you are thinking about time complexity, you can use –O flags . There are several options, listed here1:
  • No –O flag: This is the default type of compiling.

  • -O0 is equivalent to the first option (no optimization at all).

  • -O or -O1 means, “Generate good-quality code without taking too long about it.” In a terminal, you use the following command:

    ghc -c -O Program.hs
  • -O2 means “Apply every nondangerous optimization, even if it means significantly longer compile times.” A dangerous optimization means that you actually obtain a worse time or space complexity.

Profiling

One of the most important technique that allows you to learn about space and time allocation in Haskell is profiling.

Profiling is a technique through which you can monitor the expressions in the programs. You can observe how many times an expression runs and how much it allocates. There are three methods in which you can enable profiling: using GHC, using Stack, or using Cabal. In this section, you will use GHC’s profiling.

The main steps are as follows:
  1. 1.

    Compile the program with the –prof option. If you want automatic annotations, use the –fprof-auto option.

     
  2. 2.

    Run the program with an option that generates the profile. For example, the option +RTS –p shows time profiling, generated in a file with the .prof extension.

     
  3. 3.

    Check the profile.

     
To see how it works, write the following line into a file called Main.hs:
main = print (fib 30)
fib n = if n < 2 then 1 else fib (n-1) + fib (n-2)
Save the file and then open a terminal and compile it (don’t forget to change the current directory to the directory that contains the Main.hs file).
$ ghc -prof -fprof-auto -rtsopts Main.hs

The –rtsopts option enables RTS.

Next, run the program.
$ Main.exe +RTS –p
If you use Unix, type ./Main instead of Main.exe. This will print the result of fib 30 and will generate a file called Main.prof, which contains statistics about the time of execution. It looks similar to Figure 22-1.
../images/475690_1_En_22_Chapter/475690_1_En_22_Fig1_HTML.jpg
Figure 22-1.

Profiling a simple program

In the first section of the file, you can see the program names and options, the total time, and the total memory used. The second section shows the costliest function (time and allocation), and the third section shows details about costs. The statistics are displayed for individual items and inherited, which includes the cost of the children of the node.

For a complete guide to profiling, consult [1]. If you want to use profiling with Cabal, consult [2]. For profiling with Stack, consult [3].

The weigh Library

The weigh library measures how much memory a value or a function uses. To install it, open a terminal and type the following:
cabal install weigh
The following is a simple example, from the GitHub page of the library2:
import Weigh
main :: IO ()
main =
  mainWith
    (do func "integers count 0" count 0
        func "integers count 1" count 1
        func "integers count 10" count 10
        func "integers count 100" count 100)
  where
    count :: Integer -> ()
    count 0 = ()
    count a = count (a - 1)
The result will look like this:

Case

Allocated

GCs

integers count 0

16

0

integers count 1

88

0

integers count 10

736

0

integers count 100

7,216

0

Other Techniques

Here are some other techniques for obtaining good performance:
  • Checking for space leaks [4]

  • Setting up an isolated benchmark, using Criterion [5]

  • Checking for the strictness of functions’ arguments [6]

  • Using a correct data structure [7]

  • Checking for strictness and unpacking the types [8]

  • Checking to see whether the code is polymorphic [9]

  • Using the core language to generate real code before assembly (many optimizations can be done here) [10]

  • Using Text or ByteString instead of String [11]

References

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.213.235