-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
Initialize rows lazily #15524
Initialize rows lazily #15524
Conversation
c7b8783
to
11c2215
Compare
d74e8fb
to
f2934ad
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you answered this comment really, so i'm gonna submit it to get it out of my queue
@@ -495,7 +630,7 @@ void TextBuffer::_SetWrapOnCurrentRow() noexcept | |||
// - fSet - True if this row has a wrap. False otherwise. | |||
//Return Value: | |||
// - <none> | |||
void TextBuffer::_AdjustWrapOnCurrentRow(const bool fSet) noexcept | |||
void TextBuffer::_AdjustWrapOnCurrentRow(const bool fSet) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gut feeling: the current row should not need to be faulted in, and so should not be exposed to a commit exception. Is that a faulty understanding on my part?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible for the current row to fault if you use CUP (or whatever) to go somewhere that hasn't been previously accessed or rendered yet (which is also possible since the renderer is async). We should decide whether we want to crash under OOM. It'd be a valid strategy. Alternatively we can strategically make use of a hypothetical GetRowByOffsetNoInit
function that returns nullptr
when faulting. I would personally not prefer it because it makes the code more complex (= "is it safe to use NoInit
here? etc.), but I'm absolutely open to implement either change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, love how much simpler some of this is!
Honestly, once you gave me an explanation of _commitWatermark
, everything kinda just made sense. I suggest adding a big blurb at the top of textBuffer.hpp or near the _commitWatermark
declaration. That'll help a ton.
I'm gonna approve, but I really do think the _commitWatermark
comment will help. Nice work!
step = -1; | ||
} | ||
|
||
for (; y != end; y += step) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't completely understand why this doesn't have the same problem as memcpy. Depending on the direction you are moving, we need to copy end-to-start or start-to-end, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, i see. we are. this is just a generic loop that goes both ways. Oi.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you prefer we can make it 2 separate loops! I initially had 2 loops, and wrote this single loop because I was curious if I could.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deeply horrified that we are placement-new-ing and placement-delete-ing ROW
s inline in the buffer, but honestly at this point I would expect nothing less than that.
I've read the code over a couple times and I think I trust it. It scares me, but I trust it. Let's go!
|
||
// Retrieves a row from the buffer by its offset from the first row of the text buffer | ||
// (what corresponds to the top row of the screen buffer). | ||
ROW& TextBuffer::GetRowByOffset(const til::CoordType index) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for height=10
, GetRowByOffset(1)
and GetRowByOffset(11)
are the same... but there are measurably not 11 rows in the buffer.
This isn't something to worry about, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think that's actually good, because it makes writing code that loops around simpler and safer. For instance, when you accidentally scroll (= rotate) more rows than there are in the buffer. The result will be weird, but it'll not crash and behave consistently.
Edit: Also, just double checking, it used to work the same way before this PR right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, it's even preferable if you scroll less rows than there are in the buffer. For instance, let's say you want to copy the viewport contents of height 4 starting row 8. In your example it'll just copy row 8,9,10,11 = 8,9,0,1 and it'll not require the caller to perform any modulo or similar logic. It should just work. That's why I added the underflow / negative modulo if condition as well. It makes copying/scrolling rows backwards work correctly without extra logic.
auto& row = _getRowByOffsetDirect(0); | ||
row.Reset(_currentAttributes); | ||
return row; | ||
return _getRowByOffsetDirect(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wait, this wasn't explained in the new commit. why did it change? is this meaningful? the comment above the function is incorrect now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah sorry, I forgot to update the comment. I made the change because I wasn't sure what I'd need. Over the weekend I figured that out though, so in the PR I just opened I've fixed this. #15541
For a 120x9001 terminal, a01500f reduced the private working set of
conhost by roughly 0.7MB, presumably due to tighter
ROW
packing, butalso increased it by 2.1MB due to the addition of the
_charOffsets
array on each
ROW
instance. An option to fix this would be to onlyallocate a
_charOffsets
if the first wide or complex Unicode glyphis encountered. But on one hand this would be quite western-centric
and unfairly hurt most languages that exist and on another we can get
rid of the
_charOffsets
array entirely in the future by injectingZWNJs if a write begins with a combining glyph and just recount each
row from the start. That's still faster than fragmented memory.
This commit goes a different way and instead reduces the working
set of conhost after it launches from 7MB down to just 2MB,
by only committing ROWs when they're first used.
Finally, it adds a "scratchpad" row which can be used to build
more complex contents, for instance to horizontally scroll them.
Validation Steps Performed
^[[3J
erases scrollback ✅ScrollRows
with a positive delta ✅Reset
. ❔ Unit tests use it though