Huge performance difference running f# same code on fsi 4.0.30319.1 and 2.0.0.0

StackOverflow https://stackoverflow.com/questions/7645804

  •  06-02-2021
  •  | 
  •  

Question

I am running the same F# code with the two versions of fsi.exe which I can find under my FSharp-2.0.0.0 install:

C:\Program Files\FSharp-2.0.0.0\bin\fsi.exe - Microsoft (R) F# 2.0 Interactive build 2.0.0

C:\Program Files\FSharp-2.0.0.0\v4.0\bin\fsi.exe - Microsoft (R) F# 2.0 Interactive build 4.0.30319.1

What I find is that the same code runs about three times faster on the 2.0.0.0 build. Does this make any sense? Is there something messed up with my environment or possibly code??

Incidentally, the reason I am trying to use the v4.0 build is to be able to use the TPL and compare sequential and parallel implementations of my code. When my parallel implementation was much slower than the sequential one, after much head-scratching I realized that the parallel version was running under a different fsi.exe, and that's when I realized that the same (sequential) version of the code is much slower under version 4.0.

Thanks in advance for any help

IS

The code:

module Options

//Gaussian module is from http://fssnip.net/3g, by Tony Lee
open Gaussian

//The European Option type
type EuropeanOption = 
        {StockCode: string
         StockPrice: float
         ExercisePrice: float
         NoRiskReturn: float
         Volatility: float
         Time: float
        }

//Read one row from the file and return a European Option
//File format is:
//StockCode<TAB>StockPrice,ExercisePrice,NoRiskReturn,Volatility,Time
let convertDataRow(line:string) =
    let option = List.ofSeq(line.Split('\t'))
    match option with
    | code::data::_ -> 
        let dataValues = (data.Split(','))
        let euopt = {StockCode = code; 
                     StockPrice = float (dataValues.[0]); 
                     ExercisePrice = float (dataValues.[1]); 
                     NoRiskReturn = float (dataValues.[2]); 
                     Volatility = float (dataValues.[3]); 
                     Time = float (dataValues.[4])
                     }
        euopt
    | _ -> failwith "Incorrect Data Format" 

//Returns the future value of an option. 
//0 if excercise price is greater than the sum of the stock price and the calculated asset price at expiration. 
let futureValue sp ep nrr vol t =
    //TODO: Is there no better way to get the value from a one-element sequence?
    let assetPriceAtExpiration = sp+sp*nrr*t+sp*sqrt(t)*vol*(Gaussian.whiteNoise |> Seq.take 1  |> List.ofSeq |> List.max)
    [0.0;assetPriceAtExpiration - ep] |> List.max

//Sequence to hold the values generated by the MonteCarlo iterations
//50,000 iterations is the minimum for a good aprox to the Black-Scholes equation
let priceValues count sp ep nrr vol t = 
    seq { for i in 1..count
          -> futureValue sp ep nrr vol t
    }

//Discount a future to a present value given the risk free rate and the time in years
let discount value noriskreturn time =
    value * exp(-1.0*noriskreturn*time) 

//Get the price for a European Option and a given number of Monte Carlo iterations (use numIters >= 50000)
let priceOption europeanOption numIters =
    let futureValuesSeq = priceValues numIters europeanOption.StockPrice europeanOption.ExercisePrice europeanOption.NoRiskReturn europeanOption.Volatility europeanOption.Time
    //The simulated future value is just the average of all the MonteCarlo runs
    let presentValue = discount (futureValuesSeq |> List.ofSeq |> List.average) europeanOption.NoRiskReturn europeanOption.Time
    //Return a list of tuples with the stock code and the calculated present value
    europeanOption.StockCode + "_to_" + string europeanOption.Time + "_years \t" + string presentValue 


module Program =

    open Options
    open System
    open System.Diagnostics
    open System.IO

    //Write to a file
    let writeFile path contentsArray = 
        File.WriteAllLines(path, contentsArray |> Array.ofList)

    //TODO: This whole "method" is sooooo procedural.... is there a more functional way?

    //Unique code for each run
    //TODO: Something shorter, please
    let runcode = string DateTime.Now.Month + "_" + string DateTime.Now.Day + "_" + string DateTime.Now.Hour + "_" + string DateTime.Now.Minute + "_" + string DateTime.Now.Second

    let outputFile = @"C:\TMP\optionpricer_results_" + runcode + ".txt"

    let statsfile = @"C:\TMP\optionpricer_stats_" + runcode + ".txt"

    printf "Starting"
    let mutable stats = ["Starting at: [" + string DateTime.Now + "]" ]

    let stopWatch = Stopwatch.StartNew()

    //Read the file
    let lines = List.ofSeq(File.ReadAllLines(@"C:\tmp\9000.txt"))

    ignore(stats <- "Read input file done at: [" + string stopWatch.Elapsed.TotalMilliseconds + "]"::stats)
    printfn "%f" stopWatch.Elapsed.TotalMilliseconds

    //Build the list of European Options
    let options = lines |> List.map convertDataRow

    ignore(stats <- ("Created Options done at: [" + string stopWatch.Elapsed.TotalMilliseconds + "]")::stats)
    printfn "%f" stopWatch.Elapsed.TotalMilliseconds

    //Calculate the option prices
    let results = List.map (fun o -> priceOption o 50000) options

    ignore(stats <- "Option prices calculated at: [" + string stopWatch.Elapsed.TotalMilliseconds + "]"::stats)
    printfn "%f" stopWatch.Elapsed.TotalMilliseconds

    //Write results and statistics
    writeFile outputFile results
    ignore(stats <- "Output file written at: [" + string stopWatch.Elapsed.TotalMilliseconds + "]"::stats)

    ignore(stats <- "Total Ellapsed Time (minus stats file write): [" + string (stopWatch.Elapsed.TotalMilliseconds / 60000.0) + "] minutes"::stats)
    printfn "%f" stopWatch.Elapsed.TotalMilliseconds

    writeFile statsfile (stats |> List.rev)
    stopWatch.Stop()
    ignore(Console.ReadLine())
Était-ce utile?

La solution

I haven't run your code but it looks like you're creating lots of linked lists. That is very inefficient but the representation of lists was changed in recent years and the new representation is slower.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top