Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(811)

Unified Diff: pkg/analysis_server/lib/src/domain_diagnostic.dart

Issue 1463923003: Rolling average work queue diagnostic (#24933). (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analysis_server/lib/src/domain_diagnostic.dart
diff --git a/pkg/analysis_server/lib/src/domain_diagnostic.dart b/pkg/analysis_server/lib/src/domain_diagnostic.dart
index e6c08c4e1664495f8cb0144531e957e7b4f353db..0e42abf1dc145e8a7dd541baa77885bb5036a2a2 100644
--- a/pkg/analysis_server/lib/src/domain_diagnostic.dart
+++ b/pkg/analysis_server/lib/src/domain_diagnostic.dart
@@ -4,6 +4,7 @@
library src.domain_diagnostic;
+import 'dart:async';
import 'dart:collection';
import 'dart:core' hide Resource;
@@ -19,42 +20,10 @@ import 'package:analyzer/src/generated/utilities_collection.dart';
import 'package:analyzer/src/task/driver.dart';
import 'package:analyzer/task/model.dart';
-/// Extract context data from the given [context].
-ContextData extractData(AnalysisContext context) {
- int explicitFiles = 0;
- int implicitFiles = 0;
- int workItems = 0;
- Set<String> exceptions = new HashSet<String>();
- if (context is AnalysisContextImpl) {
- // Work Item count.
- AnalysisDriver driver = context.driver;
- List<WorkItem> items = driver.currentWorkOrder?.workItems;
- workItems ??= items?.length;
- var cache = context.analysisCache;
- if (cache is AnalysisCache) {
- Set<AnalysisTarget> countedTargets = new HashSet<AnalysisTarget>();
- MapIterator<AnalysisTarget, CacheEntry> iterator = cache.iterator();
- while (iterator.moveNext()) {
- AnalysisTarget target = iterator.key;
- if (countedTargets.add(target)) {
- CacheEntry cacheEntry = iterator.value;
- if (target is Source) {
- if (cacheEntry.explicitlyAdded) {
- explicitFiles++;
- } else {
- implicitFiles++;
- }
- }
- // Caught exceptions.
- if (cacheEntry.exception != null) {
- exceptions.add(cacheEntry.exception.toString());
- }
- }
- }
- }
- }
- return new ContextData(context.name, explicitFiles, implicitFiles, workItems,
- exceptions.toList());
+int _workItemCount(AnalysisContextImpl context) {
+ AnalysisDriver driver = context.driver;
+ List<WorkItem> items = driver.currentWorkOrder?.workItems;
+ return items?.length ?? 0;
}
/// Instances of the class [DiagnosticDomainHandler] implement a
@@ -66,20 +35,65 @@ class DiagnosticDomainHandler implements RequestHandler {
/// The analysis server that is using this handler to process requests.
final AnalysisServer server;
+ /// The sampler tracking rolling work queue length averages.
+ Sampler sampler;
+
/// Initialize a newly created handler to handle requests for the given
/// [server].
DiagnosticDomainHandler(this.server);
/// Answer the `diagnostic.diagnostics` request.
Response computeDiagnostics(Request request) {
+ // Initialize sampler if needed.
+ if (sampler == null) {
+ sampler = new Sampler(server);
+ }
+
List<ContextData> infos = <ContextData>[];
server.folderMap.forEach((Folder folder, AnalysisContext context) {
- infos.add(extractData(context));
+ infos.add(extractData(folder, context));
});
return new DiagnosticGetDiagnosticsResult(infos).toResponse(request.id);
}
+ /// Extract context data from the given [context].
+ ContextData extractData(Folder folder, AnalysisContext context) {
+ int explicitFiles = 0;
+ int implicitFiles = 0;
+ int workItems = 0;
+ String workItemAverage = '-1';
+ Set<String> exceptions = new HashSet<String>();
+ if (context is AnalysisContextImpl) {
+ workItems = _workItemCount(context);
+ workItemAverage = sampler.getAverage(folder)?.toString() ?? '-1';
+ var cache = context.analysisCache;
+ if (cache is AnalysisCache) {
+ Set<AnalysisTarget> countedTargets = new HashSet<AnalysisTarget>();
+ MapIterator<AnalysisTarget, CacheEntry> iterator = cache.iterator();
+ while (iterator.moveNext()) {
+ AnalysisTarget target = iterator.key;
+ if (countedTargets.add(target)) {
+ CacheEntry cacheEntry = iterator.value;
+ if (target is Source) {
+ if (cacheEntry.explicitlyAdded) {
+ explicitFiles++;
+ } else {
+ implicitFiles++;
+ }
+ }
+ // Caught exceptions.
+ if (cacheEntry.exception != null) {
+ exceptions.add(cacheEntry.exception.toString());
+ }
+ }
+ }
+ }
+ }
+ return new ContextData(context.name, explicitFiles, implicitFiles,
+ workItems, workItemAverage, exceptions.toList());
+ }
+
@override
Response handleRequest(Request request) {
try {
@@ -93,3 +107,104 @@ class DiagnosticDomainHandler implements RequestHandler {
return null;
}
}
+
+/// Keeps track of a moving average of work item queue lengths mapped to
+/// contexts.
+///
+/// Sampling terminates after [maxSampleCount], if no one expresses interest
+/// by calling [reset].
+class Sampler {
+ /// Timer interval.
+ static const Duration duration = const Duration(seconds: 1);
+
+ /// Maximum number of samples taken between calls to [reset].
+ static const int maxSampleCount = 30;
+
+ /// Current sample count.
+ int sampleCount = 0;
+
+ /// The shared timer.
+ Timer timer;
+
+ /// Map of contexts (tracked as folders to avoid leaks) to averages.
+ Map<Folder, _Average> averages = new HashMap<Folder, _Average>();
+
+ final AnalysisServer server;
+ Sampler(this.server) {
+ start();
+ _sample();
+ }
+
+ /// Get the average for the context associated with the given [folder].
+ int getAverage(Folder folder) {
+ reset();
+ return averages[folder].value;
+ }
+
+ /// Check if we're currently sampling.
+ bool isSampling() => timer?.isActive ?? false;
+
+ /// Reset counter.
+ void reset() {
devoncarew 2015/11/20 22:17:06 Possibly resetTimerCountdown()? reset() is a bit a
pquitslund 2015/11/20 22:22:51 Done.
+ sampleCount = 0;
+ }
+
+ /// Start sampling.
+ void start() {
+ // No need to (re)start if already sampling.
+ if (isSampling()) {
+ return;
+ }
+ timer = new Timer.periodic(duration, (Timer timer) {
+ _sample();
+ if (sampleCount++ >= maxSampleCount) {
+ timer.cancel();
+ }
+ });
+ }
+
+ /// Stop sampling.
+ void stop() {
+ timer.cancel();
+ }
+
+ /// Take a sample.
+ void _sample() {
+ try {
+ server.folderMap.forEach((Folder folder, AnalysisContext context) {
+ if (context is AnalysisContextImpl) {
+ _Average average = averages[folder];
+ if (average == null) {
+ average = new _Average();
+ averages[folder] = average;
+ }
+ average.addSample(_workItemCount(context));
+ }
+ });
+ } on Exception {
+ stop();
+ }
+ }
+}
+
+/// Simple rolling average sample counter.
+class _Average {
+ num _val;
+
+ final int sampleCount;
+ _Average([this.sampleCount = 20]);
+
+ num get value => _val ?? 0;
+
+ void addSample(num sample) {
+ if (_val == null) {
+ _val = sample;
+ } else {
+ _val =
+ _val * ((sampleCount - 1) / sampleCount) + sample * (1 / sampleCount);
+ }
+ }
+
+ @override
+ String toString() => 'average: ${value}';
+}
« no previous file with comments | « pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart ('k') | pkg/analysis_server/test/domain_diagnostic_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698