Skip to content

Commit

Permalink
Improve perf by caching generators (#65)
Browse files Browse the repository at this point in the history
Small change, order of magintude improvement. Tested on 185 page blog:

Pre-change - Generation time: 00:04:59.3250690
Post-change - Generation time: 00:00:19.2490206

Co-authored-by: Robert Pickering <[email protected]>
  • Loading branch information
robertpi and Robert Pickering authored May 3, 2020
1 parent 62fb09a commit 0a7c669
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/Fornax/Fornax.fs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ let createFileWatcher dir handler =
/// Adding handler to trigger websocket/live refresh
let contentChangedHandler _ =
signalContentChanged.Trigger(Choice<unit,Error>.Choice1Of2 ())
GeneratorEvaluator.removeItemFromGeneratorCache()

signalContentChanged.Trigger(Choice<unit,Error>.Choice1Of2 ())
fileSystemWatcher.Created.Add contentChangedHandler
fileSystemWatcher.Changed.Add contentChangedHandler
Expand Down
26 changes: 23 additions & 3 deletions src/Fornax/Generator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
module Generator

open System
open System.Collections.Concurrent
open System.Diagnostics
open System.IO
open System.Text
open Config
Expand Down Expand Up @@ -166,15 +168,30 @@ module GeneratorEvaluator =
|> fun s -> s.Trim(Environment.NewLine.ToCharArray())
Error completeErrorReport

let private generatorCache = new ConcurrentDictionary<_,_>()

/// allows the cache to be cleared when running in watch mode and a change is detected
let removeItemFromGeneratorCache() =
generatorCache.Clear()

///`generatorPath` - absolute path to `.fsx` file containing the generator
///`projectRoot` - path to root of the site project
///`page` - path to the file that should be transformed
let evaluate (fsi : FsiEvaluationSession) (siteContent : SiteContents) (generatorPath : string) (projectRoot: string) (page: string) =
getGeneratorContent fsi generatorPath
|> Result.bind (fun ft ->
let generator = compileExpression ft

let ok, generator = generatorCache.TryGetValue(generatorPath)
let generator =
if ok then
generator
else
let generator =
getGeneratorContent fsi generatorPath
|> Result.bind (compileExpression >> Ok)
generatorCache.AddOrUpdate(generatorPath, generator, fun key value -> value) |> ignore
generator

generator
|> Result.bind (fun generator ->
let result = invokeFunction generator [box siteContent; box projectRoot; box page ]

result
Expand Down Expand Up @@ -423,6 +440,7 @@ module Logger =

///`projectRoot` - path to the root of website
let generateFolder (projectRoot : string) (isWatch: bool) =
let sw = Stopwatch.StartNew()

let relative toPath fromPath =
let toUri = Uri(toPath)
Expand Down Expand Up @@ -480,3 +498,5 @@ let generateFolder (projectRoot : string) (isWatch: bool) =
|> relative projectRoot
|> generate fsi config sc projectRoot
|> logResult)

Logger.informationfn "Generation time: %A" sw.Elapsed

0 comments on commit 0a7c669

Please sign in to comment.