Fixing CA2014 warnings, and removing suppressions#17982
Conversation
3cc72af to
f13d8a6
Compare
|
Pinging the original reviewers, to get a few more eyes on the PR. |
| { | ||
| var endOfLine = Environment.NewLine.AsSpan(); | ||
| var endOfLineLength = endOfLine.Length; | ||
| Span<char> outBufferLine = stackalloc char[outBuffer.Length + endOfLineLength]; |
There was a problem hiding this comment.
Here we could allocate ~16KB (MaxBufferSize) in stack. That it is not good. I suggest to output the tail before the condition if the tail >= MaxStackAlloc ( MaxStackAlloc = 512).
There was a problem hiding this comment.
@iSazonov
I think what you are suggesting is that we should further split the outBuffer into 2 pieces -> MaxBufferSize - 512b and 512b, such that the span that is stacalloc'ed is 512 bytes.
(assuming that the size of the outBuffer is MaxBufferSize, in the worst case)
The first MaxBufferSize - 512b piece will need additional memory. This will also end up going on the stack since we are using spans. This route does not seem any better than allocating the entire MaxBufferSize.
Also, this will mean that we would now need to make two WriteConsole calls to finish writing the contents of the outBuffer, rather than 1.
I don't think the memory allocation issue is significant enough to justify adding the perf of a whole other IO operation.
Let me know if I understood that right.
There was a problem hiding this comment.
I mean:
internal static void WriteConsole(ConsoleHandle consoleHandle, ReadOnlySpan<char> output, bool newLine)
{
Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid");
Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed");
const char MaxStackAlloc = 512;
Span<char> buffer = stackalloc char[MaxStackAlloc];
ReadOnlySpan<char> outBuffer;
// Native WriteConsole doesn't support output buffer longer than 64K.
// We need to chop the output string if it is too long.
// This records the chopping position in output string
int cursor = 0;
// this is 64K/4 - 1 to account for possible width of each character.
const int MaxBufferSize = 16383;
while (cursor <= output.Length - MaxBufferSize)
{
outBuffer = output.Slice(cursor, MaxBufferSize);
cursor += MaxBufferSize;
WriteConsole(consoleHandle, outBuffer);
}
if (cursor == output.Length)
{
if (newLine)
{
WriteConsole(consoleHandle, Environment.NewLine);
}
return;
}
outBuffer = output.Slice(cursor);
if (!newLine)
{
WriteConsole(consoleHandle, outBuffer);
return;
}
if (outBuffer.Length < MaxStackAlloc - 1)
{
// We expect it is a hot path.
var endOfLine = Environment.NewLine.AsSpan();
var endOfLineLength = endOfLine.Length;
buffer = buffer.Slice(0, outBuffer.Length + endOfLineLength); }
outBuffer.CopyTo(buffer);
endOfLine.CopyTo(buffer.Slice(buffer.Length - endOfLineLength));
WriteConsole(consoleHandle, buffer);
}
else
{
WriteConsole(consoleHandle, outBuffer);
WriteConsole(consoleHandle, Environment.NewLine);
}
}There was a problem hiding this comment.
@iSazonov I understand your concern here. But the while (cursor + MaxBufferSize < output.Length) comes from the existing if (cursor + MaxBufferSize < output.Length), so it's not a problem introduced by this cleanup change. So, I'm fine merging this PR as is, and submit a new PR to address your concern.
|
This PR has Quantification details
Why proper sizing of changes matters
Optimal pull request sizes drive a better predictable PR flow as they strike a
What can I do to optimize my changes
How to interpret the change counts in git diff output
Was this comment helpful? 👍 :ok_hand: :thumbsdown: (Email) |
|
@creative-cloud Thanks for your contribution! |
PR Summary
Fixes #13531 - No longer allocating memory in loops. Removed related suppress warnings.
Moved out the stackalloc statements for 2/3 cases, and removed the loop entirely for the other.
PR Context
Copying context over from the issue -
PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerWIP:or[ WIP ]to the beginning of the title (theWIPbot will keep its status check atPendingwhile the prefix is present) and remove the prefix when the PR is ready.(which runs in a different PS Host).