fsharp icon indicating copy to clipboard operation
fsharp copied to clipboard

Perf: ITypeProvider.ApplyStaticArguments is called multiple times

Open ovatsus opened this issue 7 years ago • 3 comments

In a fsx file like this:

  #r "System.Xml.Linq"
  #r "FSharp.Data.dll"
  open FSharp.Data

  type Schema1 = XmlProvider<"Metadata1.xml">
  let schema1 = Schema1.GetSample()

  type Schema2 = XmlProvider<"Metadata2.xml">
  let schema2 = Schema2.GetSample()

  type Schema3 = XmlProvider<"Metadata2.xml", Global=true>
  let schema3 = Schema3.GetSample()

  let wb = WorldBankData.GetDataContext()

  type WB = WorldBankDataProvider<Asynchronous=true>
  let wb2 = WB.GetDataContext()

In the process of opening that file in Visual Studio, the code to generate the provided types for WorldBankData is only executed once, but the code to generate the provided types for the other 4 type provider instances which have static parameters is executed 5 times each.

I've added caching to mitigate the issue on FSharp.Data, but I'd expect most type provider implementation to not do that, so it would be preferable to fix the issue in the compiler.

You can see the issue by compiling the current master branch of FSharp.Data and compiling FSharp.Data.DesignTime.dll with the LOGGING_ENABLED compilation symbol, and starting devenv file.fsx. You'll get a log file with the activity:

Creating TypeProviderForNamespaces ProviderImplementation.JsonProvider [0]
Creating TypeProviderForNamespaces ProviderImplementation.XmlProvider [1]
Creating TypeProviderForNamespaces ProviderImplementation.CsvProvider [2]
Creating TypeProviderForNamespaces ProviderImplementation.WorldBankProvider [3]
GeneratingProvidedType WorldBankData [3]
  Caching for 10 seconds
  Setting up dispose action
Finished GeneratingProvidedType [41ms]
Creating TypeProviderForNamespaces ProviderImplementation.HtmlProvider [4]
GeneratingProvidedType XmlProvider,Sample="Metadata1.xml" [1]
  LoadingSample Metadata1.xml
    Parsing Metadata1.xml
    Finished Parsing [4ms]
  Finished LoadingSample [166ms]
  Inference Metadata1.xml
  Finished Inference [551ms]
  TypeGeneration Metadata1.xml
  Finished TypeGeneration [200ms]
  CommonTypeGeneration Metadata1.xml
  Finished CommonTypeGeneration [16ms]
  Caching for 10 seconds
  Setting up dispose action
  Setting up C:\Users\guguer\Desktop\Metadata1.xml watcher
Finished GeneratingProvidedType [1199ms]
GeneratingProvidedType XmlProvider,Sample="Metadata1.xml" [1]
  Retrieved from cache
Finished GeneratingProvidedType [2ms]
GeneratingProvidedType XmlProvider,Sample="Metadata1.xml" [1]
  Retrieved from cache
Finished GeneratingProvidedType [28ms]
GeneratingProvidedType XmlProvider,Sample="Metadata2.xml" [1]
  LoadingSample Metadata2.xml
    Parsing Metadata2.xml
    Finished Parsing [13ms]
  Finished LoadingSample [32ms]
  Inference Metadata2.xml
  Finished Inference [256ms]
  TypeGeneration Metadata2.xml
  Finished TypeGeneration [4ms]
  CommonTypeGeneration Metadata2.xml
  Finished CommonTypeGeneration [0ms]
  Caching for 10 seconds
  Setting up dispose action
  Setting up C:\Users\guguer\Desktop\Metadata2.xml watcher
Finished GeneratingProvidedType [329ms]
GeneratingProvidedType XmlProvider,Sample="Metadata2.xml" [1]
  Retrieved from cache
Finished GeneratingProvidedType [1ms]
GeneratingProvidedType XmlProvider,Sample="Metadata2.xml" [1]
  Retrieved from cache
Finished GeneratingProvidedType [9ms]
GeneratingProvidedType XmlProvider,Sample="Metadata2.xml",Global="True" [1]
  LoadingSample Metadata2.xml
    Parsing Metadata2.xml
    Finished Parsing [11ms]
  Finished LoadingSample [29ms]
  Inference Metadata2.xml
  Finished Inference [619ms]
  TypeGeneration Metadata2.xml
  Finished TypeGeneration [3ms]
  CommonTypeGeneration Metadata2.xml
  Finished CommonTypeGeneration [0ms]
  Caching for 10 seconds
  Setting up dispose action
  Reusing C:\Users\guguer\Desktop\Metadata2.xml watcher
Finished GeneratingProvidedType [725ms]
GeneratingProvidedType XmlProvider,Sample="Metadata2.xml",Global="True" [1]
  Retrieved from cache
Finished GeneratingProvidedType [1ms]
GeneratingProvidedType XmlProvider,Sample="Metadata2.xml",Global="True" [1]
  Retrieved from cache
Finished GeneratingProvidedType [5ms]
GeneratingProvidedType WorldBankDataProvider,Asynchronous="True" [3]
  Caching for 10 seconds
  Setting up dispose action
Finished GeneratingProvidedType [11ms]
GeneratingProvidedType WorldBankDataProvider,Asynchronous="True" [3]
  Retrieved from cache
Finished GeneratingProvidedType [18ms]
GeneratingProvidedType WorldBankDataProvider,Asynchronous="True" [3]
  Retrieved from cache
Finished GeneratingProvidedType [10ms]
GeneratingProvidedType XmlProvider,Sample="Metadata1.xml" [1]
  Retrieved from cache
Finished GeneratingProvidedType [43ms]
GeneratingProvidedType XmlProvider,Sample="Metadata1.xml" [1]
  Retrieved from cache
Finished GeneratingProvidedType [36ms]
GeneratingProvidedType XmlProvider,Sample="Metadata2.xml" [1]
  Retrieved from cache
Finished GeneratingProvidedType [0ms]
GeneratingProvidedType XmlProvider,Sample="Metadata2.xml" [1]
  Retrieved from cache
Finished GeneratingProvidedType [1ms]
GeneratingProvidedType XmlProvider,Sample="Metadata2.xml",Global="True" [1]
  Retrieved from cache
Finished GeneratingProvidedType [1ms]
GeneratingProvidedType XmlProvider,Sample="Metadata2.xml",Global="True" [1]
  Retrieved from cache
Finished GeneratingProvidedType [1ms]
GeneratingProvidedType WorldBankDataProvider,Asynchronous="True" [3]
  Retrieved from cache
Finished GeneratingProvidedType [1ms]
GeneratingProvidedType WorldBankDataProvider,Asynchronous="True" [3]
  Retrieved from cache
Finished GeneratingProvidedType [1ms]

ovatsus avatar Apr 09 '18 18:04 ovatsus

Additionally, even when calling fsc on a single fs file that uses types provider without loading into the editor, it also seems ApplyStaticArguments is called more than once

ovatsus avatar Apr 09 '18 19:04 ovatsus

When just typing schema1. at the end of the file, ApplyStaticArguments is called again as well.

ovatsus avatar Apr 09 '18 22:04 ovatsus

@ovatsus Yes, we do call ApplyStaticArguments many times, basically each time the file is checked. The type provider should cache to give good performance in these cases

However in the fsc.exe case I would expect only one call.

dsyme avatar Apr 12 '18 13:04 dsyme