11open System
22open System.IO
3- open BenchmarkDotNet.Attributes
4- open BenchmarkDotNet.Running
3+ open System.Text
54open Microsoft.FSharp .Compiler .ErrorLogger
65open Microsoft.FSharp .Compiler .SourceCodeServices
76open Microsoft.FSharp .Compiler .Text
8- open System.Text
7+ open Microsoft.FSharp .Compiler .AbstractIL
8+ open Microsoft.FSharp .Compiler .AbstractIL .IL
9+ open Microsoft.FSharp .Compiler .AbstractIL .ILBinaryReader
910open Microsoft.CodeAnalysis .Text
11+ open BenchmarkDotNet.Attributes
12+ open BenchmarkDotNet.Running
1013
1114module private SourceText =
1215
@@ -77,8 +80,8 @@ type SourceText with
7780member this.ToFSharpSourceText () =
7881 SourceText.weakTable.GetValue( this, Runtime.CompilerServices.ConditionalWeakTable<_,_>. CreateValueCallback( SourceText.create))
7982
80- [<ClrJob ; MemoryDiagnoser>]
81- type CompilerServiceParsing () =
83+ [<MemoryDiagnoser>]
84+ type CompilerService () =
8285
8386let mutable checkerOpt = None
8487
@@ -95,6 +98,17 @@ type CompilerServiceParsing() =
9598 IsExe= false
9699}
97100
101+ let mutable assembliesOpt = None
102+
103+ let readerOptions =
104+ {
105+ pdbDirPath= None
106+ ilGlobals= mkILGlobals ILScopeRef.Local
107+ reduceMemoryUsage= ReduceMemoryFlag.No
108+ metadataOnly= MetadataOnlyFlag.Yes
109+ tryGetMetadataSnapshot= fun _ -> None
110+ }
111+
98112[<GlobalSetup>]
99113member __.Setup () =
100114match checkerOptwith
@@ -105,8 +119,16 @@ type CompilerServiceParsing() =
105119| None->
106120 sourceOpt<- Some<| SourceText.From( File.OpenRead( """ ..\..\..\..\..\src\fsharp\TypeChecker.fs""" ), Encoding.Default, SourceHashAlgorithm.Sha1, true )
107121| _ -> ()
122+
123+ match assembliesOptwith
124+ | None->
125+ assembliesOpt<-
126+ System.AppDomain.CurrentDomain.GetAssemblies()
127+ |> Array.map( fun x -> ( x.Location))
128+ |> Some
129+ | _ -> ()
108130
109- [<IterationSetup>]
131+ [<IterationSetup( Target = " Parsing " ) >]
110132member __.ParsingSetup () =
111133match checkerOptwith
112134| None-> failwith" no checker"
@@ -124,7 +146,59 @@ type CompilerServiceParsing() =
124146let results = checker.ParseFile( " TypeChecker.fs" , source.ToFSharpSourceText(), parsingOptions) |> Async.RunSynchronously
125147if results.ParseHadErrorsthen failwithf" parse had errors:%A " results.Errors
126148
149+ [<IterationSetup( Target= " ILReading" ) >]
150+ member __.ILReadingSetup () =
151+ // With caching, performance increases an order of magnitude when re-reading an ILModuleReader.
152+ // Clear it for benchmarking.
153+ ClearAllILModuleReaderCache()
154+
155+ [<Benchmark>]
156+ member __.ILReading () =
157+ match assembliesOptwith
158+ | None-> failwith" no assemblies"
159+ | Some( assemblies) ->
160+ // We try to read most of everything in the assembly that matter, mainly types with their properties, methods, and fields.
161+ // CustomAttrs and SecurityDecls are lazy until you call them, so we call them here for benchmarking.
162+ assemblies
163+ |> Array.iter( fun ( fileName ) ->
164+ let reader = OpenILModuleReader fileName readerOptions
165+
166+ let ilModuleDef = reader.ILModuleDef
167+
168+ let ilAssemblyManifest = ilModuleDef.Manifest.Value
169+
170+ ilAssemblyManifest.CustomAttrs|> ignore
171+ ilAssemblyManifest.SecurityDecls|> ignore
172+ ilAssemblyManifest.ExportedTypes.AsList
173+ |> List.iter( fun x ->
174+ x.CustomAttrs|> ignore
175+ )
176+
177+ ilModuleDef.CustomAttrs|> ignore
178+ ilModuleDef.TypeDefs.AsArray
179+ |> Array.iter( fun ilTypeDef ->
180+ ilTypeDef.CustomAttrs|> ignore
181+ ilTypeDef.SecurityDecls|> ignore
182+
183+ ilTypeDef.Methods.AsArray
184+ |> Array.iter( fun ilMethodDef ->
185+ ilMethodDef.CustomAttrs|> ignore
186+ ilMethodDef.SecurityDecls|> ignore
187+ )
188+
189+ ilTypeDef.Fields.AsList
190+ |> List.iter( fun ilFieldDef ->
191+ ilFieldDef.CustomAttrs|> ignore
192+ )
193+
194+ ilTypeDef.Properties.AsList
195+ |> List.iter( fun ilPropertyDef ->
196+ ilPropertyDef.CustomAttrs|> ignore
197+ )
198+ )
199+ )
200+
127201[<EntryPoint>]
128202let main argv =
129- let _ = BenchmarkRunner.Run< CompilerServiceParsing >()
130- 0
203+ let _ = BenchmarkRunner.Run< CompilerService >()
204+ 0