Skip to content

Improve LargeEncodedText performance - #569

Merged
pharring merged 11 commits into
dotnet:masterfrom
pharring:Fix516
Feb 20, 2015
Merged

Improve LargeEncodedText performance#569
pharring merged 11 commits into
dotnet:masterfrom
pharring:Fix516

Conversation

@pharring

Copy link
Copy Markdown
Contributor

Issue #516 talks about a performance problem with LargeEncodedText.
I fixed that, but along the way I had to reconcile the duplication of code between SourceText, EncodedStringText and LargeEncodedText.
LargeEncodedText is entirely portable, so it was easily moved into the Portable compiler assembly.
Most of EncodedStringText is portable. The class itself is just a re-implementation of StringText. The non-portable stuff remains: Using Encoding.Default as a fallback, throwing if a binary file is detected and special-casing FileStream and MemoryStream.

@tmeschter

Copy link
Copy Markdown
Contributor

Don't forget to run the API change by the compatibility council.

@tmat

tmat commented Feb 17, 2015

Copy link
Copy Markdown
Member

I don't think we need any new public surface nor change the current.

SourceText now includes the logic to decode efficiently from streams, throwing if binary files are detected and using LargeEncodedText to avoid the large object heap.
EncodedStringText, a shell of its former self, provides the 'desktop' entry point to detect FileStream and decode MemoryStream as byte arrays.
@pharring

Copy link
Copy Markdown
Contributor Author

Allow me to explain the public API changes. They're all in SourceText.

  1. De-virtualize the "Lines" property and add a protected virtual GetLinesCore method. This is the typical pattern. It's not expected that derived types have to call the base implementation. I could revert this change if it seems frivolous.
  2. Add an optional throwIfBinaryDetected parameter to SourceText.From. Defaults to false to maintain the original behavior. This is required because EncodedStringText and SourceText had deviated in their behaviors around binary files.
  3. Introduce a new SourceText.From overload that takes a byte array instead of a stream. This is required because the optimizations for (small) MemoryStream and FileStream read the original Stream into a byte[] buffer.

You might argue that 2 and 3 could have been done with internal methods. However, the wrinkle is that EncodedStringText (the Desktop entry point that contains optimizations for FileStream and MemoryStream, has the "throwIfBinaryDetected" behavior and uses Encoding.Default as the fallback instead of Utf8) is also used in the Workspaces.Desktop layer (there's a linked file reference). It therefore can't use any compiler internal APIs).

@pharring

Copy link
Copy Markdown
Contributor Author

@AnthonyDGreen For the attention of the compat council. Please let me know how you'd like me to proceed.

Use new property syntax in a few places.
Removed unused usings.
@tmat

tmat commented Feb 17, 2015

Copy link
Copy Markdown
Member

My comment re the parameter throwIfBinary is lost somewhere in the commits. Why couldn't the caller do the check for binary content after SourceText.From returns the SourceText instance?

@pharring

Copy link
Copy Markdown
Contributor Author

@tmat Re:"throwIfBinary". It's for the LargeEncodedText case. The 'throwIsBinary' implementation works on the chunks as they are being decoded. It would be inefficient to do the binary check after the fact because LargeEncodedText's indexer is slow.

@mattwar

mattwar commented Feb 18, 2015

Copy link
Copy Markdown
Contributor

👍

@pharring

Copy link
Copy Markdown
Contributor Author

@AnthonyDGreen I'm still waiting for a comment from the compat council. Please take a look at the public API changes and let me know what you think.

@tmat

tmat commented Feb 19, 2015

Copy link
Copy Markdown
Member

@pharring I still don't like the flag and throwing an exception. It would be better if we added a method IsBinary() on SourceText

@AnthonyDGreen

Copy link
Copy Markdown
Contributor

@pharring, is this a complete and accurate description of the compat impact of the change?

Source

  1. Source that extends SourceText and attempts to override the Lines property will now fail to compile.
  2. Source that called SourceText.From(Stream) will continue to compile but will silently call a new overload with a default value which preserves the current behavior.
    Binaries
  3. Binaries that extended SourceText and override the Lines property will now fail are runtime when running against the next version of Microsoft.CodeAnalysis.dll
  4. Binaries that call SourceText.From(Stream) will fail at runtime with MissingMethodException when running against the next version of Microsoft.CodeAnalysis.dll

Have I overlooked anything that you're aware of?

@pharring

Copy link
Copy Markdown
Contributor Author

@AnthonyDGreen Yes, that's complete and accurate.

@pharring

Copy link
Copy Markdown
Contributor Author

@tmat I tried to explain that already. SourceText.IsBinary() would have to be public and virtual.
Public so it could be called from the Workspaces Desktop assembly and virtual so it could be overridden in LargeEncodedText for efficiency.
We'd also lose the benefit of checking during decoding that LargeEncodedText does. If you have a giant binary file (e.g. you accidentally pass a 1GB binary file to SourceText.From), then we can detect "IsBinary" and throw before we've decoded the entire stream.

@tmat

tmat commented Feb 19, 2015

Copy link
Copy Markdown
Member

@pharring I see. OK. (Public IsBinary would be better imo, but I didn't realize we throw before we decode the entire stream, in that case sounds good).

@AnthonyDGreen

Copy link
Copy Markdown
Contributor

+1. I think this is a simple enough change with low risk. Go for it.

pharring added a commit that referenced this pull request Feb 20, 2015
Improve LargeEncodedText performance.

Includes the following public API changes:

Source
 1. Source that extends SourceText and attempts to override the Lines property will now fail to compile.
 2. Source that called SourceText.From(Stream) will continue to compile but will silently call a new overload with a default value which preserves the current behavior.

Binaries
 1. Binaries that extended SourceText and override the Lines property will now fail at runtime when running against the next version of Microsoft.CodeAnalysis.dll
 2. Binaries that call SourceText.From(Stream) will fail at runtime with MissingMethodException when running against the next version of Microsoft.CodeAnalysis.dll
@pharring
pharring merged commit 92476dc into dotnet:master Feb 20, 2015
@pharring
pharring deleted the Fix516 branch February 20, 2015 01:02
@pharring pharring added the Tenet-Performance Regression in measured performance of the product from goals. label Mar 10, 2015
dibarbet pushed a commit that referenced this pull request Aug 18, 2026
Automatically detect generated code configuration
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Compilers Tenet-Performance Regression in measured performance of the product from goals.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants