-
Notifications
You must be signed in to change notification settings - Fork 91
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
Memory tuning #2619
Memory tuning #2619
Conversation
// reference to each scan target is put into a channel for hashing, | ||
// if hashing is enabled. | ||
Task<bool> hashFilesAndPutInAnalysisQueue = Task.Run(() => HashFilesAndPutInAnalysisQueueAsnc()); | ||
// 3: A dedicated set of threads pull scan targets and analyze them. |
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.
Skipped number 2 #Resolved
Task.WhenAll(hashWorkers) | ||
.ContinueWith(_ => { | ||
_loggerCache?.Clear(); | ||
Console.WriteLine("Done with hashing."); | ||
readyToScanChannel.Writer.Complete(); | ||
}) | ||
.Wait(); | ||
|
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 some of the tasks in hashWorkers
fail, does this ignore the error?
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.
Overall, if you're going to wait anyway, then I feel it would be clearer to use Task.WaitAll and then do _loggerCache?.Clear()
etc. afterwards. The error handling would then be different, though.
@michaelcfanning A PR description would be super helpful. |
@@ -10,7 +10,7 @@ public enum DefaultTraces | |||
{ | |||
None, | |||
ScanTime = 0x01, | |||
ScanExecution = 0x2, |
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.
@@ -30,7 +30,6 @@ public abstract class AnalyzeCommandBase<TContext, TOptions> : PluginDriverComma | |||
private Run _run; | |||
private Tool _tool; | |||
internal TContext _rootContext; | |||
private CacheByFileHashLogger _cacheByFileHashLogger; |
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.
|
||
return true; | ||
} | ||
private readonly ConcurrentDictionary<string, CachingLogger> _loggerCache = new ConcurrentDictionary<string, CachingLogger>(); |
Check failure
Code scanning / CodeQL
Container contents are never accessed
baseLoggerTestConcrete = new BaseLoggerTestConcrete(new[] { FailureLevel.Error }.ToImmutableHashSet(), | ||
new List<ResultKind> { ResultKind.Informational, ResultKind.Fail }.ToImmutableHashSet()); |
Check warning
Code scanning / CodeQL
Useless assignment to local variable
baseLoggerTestConcrete = new BaseLoggerTestConcrete(new[] { FailureLevel.Note }.ToImmutableHashSet(), | ||
BaseLogger.Fail); |
Check warning
Code scanning / CodeQL
Useless assignment to local variable
baseLoggerTestConcrete = new BaseLoggerTestConcrete(new[] { FailureLevel.None }.ToImmutableHashSet(), | ||
new List<ResultKind> { ResultKind.Informational }.ToImmutableHashSet()); |
Check warning
Code scanning / CodeQL
Useless assignment to local variable
Traces = new string[] { }; | ||
Kind = new List<ResultKind> { ResultKind.Fail }; | ||
Level = new List<FailureLevel> { FailureLevel.Warning, FailureLevel.Error }; | ||
Trace = new string[] { }; |
Check warning
Code scanning / CodeQL
Virtual call in constructor or destructor
public virtual IEnumerable<string> Trace { get; set; } | ||
|
||
private DefaultTraces? defaultTraces; | ||
public DefaultTraces Traces |
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.
readyToHashChannel = Channel.CreateBounded<int>(channelOptions); | ||
|
||
channelOptions = new BoundedChannelOptions(2000) | ||
var channelOptions = new BoundedChannelOptions(25000) |
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.
catch (Exception e) | ||
{ | ||
if (context != null) | ||
{ | ||
if (context != null) | ||
{ | ||
RuntimeErrors |= context.RuntimeErrors; | ||
context?.Dispose(); | ||
} | ||
context = default; | ||
Errors.LogUnhandledEngineException(rootContext, e); | ||
RuntimeErrors |= rootContext.RuntimeErrors; | ||
ThrowExitApplicationException(context, ExitReason.ExceptionWritingToLogFile, e); | ||
RuntimeErrors |= context.RuntimeErrors; | ||
context?.Dispose(); | ||
} | ||
context = default; | ||
Errors.LogUnhandledEngineException(rootContext, e); | ||
RuntimeErrors |= rootContext.RuntimeErrors; | ||
ThrowExitApplicationException(context, ExitReason.ExceptionWritingToLogFile, e); | ||
} |
Check notice
Code scanning / CodeQL
Generic catch clause
@@ -276,62 +278,68 @@ | |||
{ | |||
int currentIndex = 0; | |||
|
|||
ChannelReader<int> reader = _resultsWritingChannel.Reader; | |||
while (_fileContexts?.Count > 0 == false) |
Check notice
Code scanning / CodeQL
Unnecessarily complex Boolean expression
This change makes some tactical changes to the current threading model in order to maximize CPU utilization and limit memory consumption, while preserving the deterministic output required for certain current client tool users.
@kelewis has pointed out that building analysis around a limited number of flattened records designed to enable efficient results streaming would be much more efficient. This seems like the right approach to me; I am only uncertain about how we would retrofit determinism for those who need it. We could create a post-processing sorting API. We could design a new binary format for serialized records, optimized for reconstructing into sorted SARIF. Looking forward to the conversation.
As it turns out, our runaway memory usage was do to a simple bug, the context creating channel wasn't throttled on write. Oops.
Tactical changes include:
HashUtilities.FileSystem
, an unnecessary duplication of theFileSystem.Instance
test knob. Taking this change required adding anIFileSystem
instance to relevant API (a non-breaking change).tail.exe
to watch output as it's generated.