Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache VT buffer line string to avoid (de)alloc on every paint #6840

Merged
merged 2 commits into from
Jul 8, 2020

Conversation

miniksa
Copy link
Member

@miniksa miniksa commented Jul 8, 2020

PR Checklist

  • Closes perf itch
  • I work here
  • Manual test
  • Documentation irrelevant.
  • Schema irrelevant.
  • Am core contributor.

Detailed Description of the Pull Request / Additional comments

A lot of time was spent between each individual line in the VT paint engine in allocating some scratch space to assemble the clusters then deallocating it only to have the next line do that again. Now we just hold onto that memory space since it should be approximately the size of a single line wide and will be used over and over and over as painting continues.

Validation Steps Performed

  • Run time cat big.txt under WPR. Checked before and after perf metrics.

@miniksa miniksa added Product-Conpty For console issues specifically related to conpty Area-Accessibility Issues related to accessibility Issue-Task It's a feature request, but it doesn't really need a major design. labels Jul 8, 2020
@miniksa miniksa self-assigned this Jul 8, 2020
@miniksa
Copy link
Member Author

miniksa commented Jul 8, 2020

Before:
before cached buffer line

After:
after cached buffer line

@miniksa miniksa changed the title Caches VT buffer line string to avoid alloc/dealloc on assembling every line for paint Cache VT buffer line string to avoid alloc/dealloc on assembling every line for paint Jul 8, 2020
@@ -479,8 +479,7 @@ using namespace Microsoft::Console::Types;
RETURN_IF_FAILED(_MoveCursor(coord));

// Write the actual text string
std::wstring wstr = std::wstring(unclusteredString.data(), cchActual);
RETURN_IF_FAILED(VtEngine::_WriteTerminalUtf8(wstr));
RETURN_IF_FAILED(VtEngine::_WriteTerminalUtf8({ _bufferLine.data(), cchActual }));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it not possible to pass the wstring directly as a view? bah.

were we literally making a whole copy of the wstring to a wstring?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know why the copy was there. It's probably because the _WriteTerminalUtf8 function converted to using std::wstring_view from std::wstring at a point in time after this paint function was last updated and this became a mechanical replace.

As for why we don't pass _bufferLine directly, the cchActual may be less than the length of the full buffer depending on trimming calculations performed above.

@@ -204,6 +204,9 @@ namespace Microsoft::Console::Render

bool _WillWriteSingleChar() const;

// buffer space for these two functions to build their lines
// so they don't have to alloc/free in a tight loop
std::wstring _bufferLine;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to til::manage?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed this a bit in Teams. This should max out at approximately (buffer width * sizeof(wchar_t) * 2). We could try to shrink it back down when we start getting small regions, but it would probably grow again when more complicated painting follows up immediately after. The amount of memory left around is arguably small for how much benefit we get from not doing the alloc/dealloc.

I could come up with some sort of time-based decay of the size of the allocation (if someone was doing big draws and has now been doing little draws for a while, it could release it back.... but I don't really have a justification to do all that to pay back ~240 bytes of memory.)

Also, we only have til::manage_vector not til::manage_string at this time. So we'd have to write something for that.

We decided together that this is a big MEH.

@DHowett DHowett changed the title Cache VT buffer line string to avoid alloc/dealloc on assembling every line for paint Cache VT buffer line string to avoid (de)alloc on every paint Jul 8, 2020
@DHowett DHowett merged commit 91f9211 into master Jul 8, 2020
@DHowett DHowett deleted the dev/miniksa/perf_bufferline_Cache branch July 8, 2020 23:30
@ghost
Copy link

ghost commented Jul 22, 2020

🎉Windows Terminal Preview v1.2.2022.0 has been released which incorporates this pull request.:tada:

Handy links:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Accessibility Issues related to accessibility Issue-Task It's a feature request, but it doesn't really need a major design. Product-Conpty For console issues specifically related to conpty
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants