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

Side by Side Diff: pkg/analysis_server/lib/src/status/memory_use.dart

Issue 2140583003: Initial memory use status page (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 5 months 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library analysis_server.src.status.memory_use;
6
7 import 'dart:collection';
8
9 import 'package:analysis_server/src/analysis_server.dart';
10 import 'package:analyzer/dart/ast/ast.dart';
11 import 'package:analyzer/dart/ast/visitor.dart';
12 import 'package:analyzer/dart/element/element.dart';
13 import 'package:analyzer/dart/element/visitor.dart';
14 import 'package:analyzer/src/context/cache.dart';
15 import 'package:analyzer/src/context/context.dart' show AnalysisContextImpl;
16 import 'package:analyzer/src/dart/element/element.dart';
17 import 'package:analyzer/src/generated/engine.dart';
18 import 'package:analyzer/src/generated/sdk.dart';
19 import 'package:analyzer/task/dart.dart';
20 import 'package:analyzer/task/model.dart';
21
22 /**
23 * A visitor that will count the number of instances of each type of AST node.
24 */
25 class AstNodeCounter extends UnifyingAstVisitor<Null> {
26 /**
27 * A table mapping the types of the AST nodes to the number of instances
28 * visited.
29 */
30 final Map<Type, int> nodeCounts;
31
32 /**
33 * Initialize a newly created counter to increment the counts in the given map
34 * of [nodeCounts].
35 */
36 AstNodeCounter(this.nodeCounts);
37
38 @override
39 visitNode(AstNode node) {
40 Type type = node.runtimeType;
41 int count = nodeCounts[type] ?? 0;
42 nodeCounts[type] = count + 1;
43 super.visitNode(node);
44 }
45 }
46
47 /**
48 * A visitor that will count the number of instances of each type of element.
49 */
50 class ElementCounter extends GeneralizingElementVisitor<Null> {
51 /**
52 * A table mapping the types of the elements to the number of instances
53 * visited.
54 */
55 final Map<Type, int> elementCounts;
56
57 /**
58 * A table mapping the types of the AST nodes to the number of instances
59 * visited.
60 */
61 final Map<Type, int> nodeCounts;
62
63 /**
64 * Initialize a newly created counter to increment the counts in the given map
65 * of [elementCounts].
66 */
67 ElementCounter(this.elementCounts, this.nodeCounts);
68
69 @override
70 visitConstructorElement(ConstructorElement element) {
71 if (element is ConstructorElementImpl) {
72 List<ConstructorInitializer> initializers = element.constantInitializers;
73 if (initializers != null) {
74 initializers.forEach((ConstructorInitializer initializer) {
75 _countNodes(initializer);
76 });
77 }
78 }
79 visitElement(element);
80 }
81
82 @override
83 visitElement(Element element) {
84 Type type = element.runtimeType;
85 int count = elementCounts[type] ?? 0;
86 elementCounts[type] = count + 1;
87 element.metadata.forEach((ElementAnnotation annotation) {
88 if (annotation is ElementAnnotationImpl) {
89 _countNodes(annotation.annotationAst);
90 }
91 });
92 super.visitElement(element);
93 }
94
95 visitFieldElement(FieldElement element) {
96 if (element is ConstVariableElement) {
97 _countInitializer(element as ConstVariableElement);
98 }
99 visitElement(element);
100 }
101
102 visitLocalVariableElement(LocalVariableElement element) {
103 if (element is ConstVariableElement) {
104 _countInitializer(element as ConstVariableElement);
105 }
106 visitElement(element);
107 }
108
109 visitParameterElement(ParameterElement element) {
110 if (element is ConstVariableElement) {
111 _countInitializer(element as ConstVariableElement);
112 }
113 visitElement(element);
114 }
115
116 visitTopLevelVariableElement(TopLevelVariableElement element) {
117 if (element is ConstVariableElement) {
118 _countInitializer(element as ConstVariableElement);
119 }
120 visitElement(element);
121 }
122
123 void _countInitializer(ConstVariableElement element) {
124 _countNodes(element.constantInitializer);
125 }
126
127 void _countNodes(AstNode node) {
128 if (node != null) {
129 node.accept(new AstNodeCounter(nodeCounts));
130 }
131 }
132 }
133
134 /**
135 * A set used when the number of instances of some type is too large to be kept.
136 */
137 class InfiniteSet implements Set {
138 /**
139 * The unique instance of this class.
140 */
141 static final InfiniteSet instance = new InfiniteSet();
142
143 @override
144 int get length => -1;
145
146 @override
147 dynamic noSuchMethod(Invocation invocation) {
148 throw new UnsupportedError('Do not use instances of InfiniteSet');
149 }
150 }
151
152 /**
153 * Computes memory usage data by traversing the data structures reachable from
154 * an analysis server.
155 */
156 class MemoryUseData {
157 /**
158 * The maximum size of an instance set.
159 */
160 static const int maxInstanceSetSize = 1000000;
161
162 /**
163 * A table mapping classes to instances of the class.
164 */
165 Map<Type, Set> instances = new HashMap<Type, Set>();
166
167 /**
168 * A set of all the library specific units, using equality rather than
169 * identity in order to determine whether re-using equal instances would save
170 * significant space.
171 */
172 Set<LibrarySpecificUnit> uniqueLSUs = new HashSet<LibrarySpecificUnit>();
173
174 /**
175 * A set of all the targeted results, using equality rather than identity in
176 * order to determine whether re-using equal instances would save significant
177 * space.
178 */
179 Set<TargetedResult> uniqueTargetedResults = new HashSet<TargetedResult>();
180
181 /**
182 * A table mapping the types of AST nodes to the number of instances being
183 * held directly (as values in the cache).
184 */
185 Map<Type, int> directNodeCounts = new HashMap<Type, int>();
186
187 /**
188 * A table mapping the types of AST nodes to the number of instances being
189 * held indirectly (such as nodes reachable from element models).
190 */
191 Map<Type, int> indirectNodeCounts = new HashMap<Type, int>();
192
193 /**
194 * A table mapping the types of the elements to the number of instances being
195 * held directly (as values in the cache).
196 */
197 final Map<Type, int> elementCounts = new HashMap<Type, int>();
198
199 /**
200 * Initialize a newly created instance.
201 */
202 MemoryUseData();
203
204 /**
205 * Traverse an analysis [server] to compute memory usage data.
206 */
207 void processAnalysisServer(AnalysisServer server) {
208 _recordInstance(server);
209 Iterable<AnalysisContext> contexts = server.analysisContexts;
210 for (AnalysisContextImpl context in contexts) {
211 _processAnalysisContext(context);
212 }
213 DartSdkManager manager = server.sdkManager;
214 List<SdkDescription> descriptors = manager.sdkDescriptors;
215 for (SdkDescription descriptor in descriptors) {
216 _processAnalysisContext(manager.getSdk(descriptor, () => null).context);
217 }
218 }
219
220 void _processAnalysisContext(AnalysisContextImpl context) {
221 _recordInstance(context);
222 _recordInstance(context.analysisCache);
223 Map<AnalysisTarget, CacheEntry> map =
224 context.privateAnalysisCachePartition.entryMap;
225 map.forEach((AnalysisTarget target, CacheEntry entry) {
226 _processAnalysisTarget(target);
227 _processCacheEntry(entry);
228 });
229 }
230
231 void _processAnalysisTarget(AnalysisTarget target) {
232 _recordInstance(target);
233 }
234
235 void _processCacheEntry(CacheEntry entry) {
236 _recordInstance(entry);
237 List<ResultDescriptor> descriptors = entry.nonInvalidResults;
238 for (ResultDescriptor descriptor in descriptors) {
239 _recordInstance(descriptor);
240 _processResultData(entry.getResultDataOrNull(descriptor));
241 }
242 }
243
244 void _processResultData(ResultData resultData) {
245 _recordInstance(resultData);
246 if (resultData != null) {
scheglov 2016/07/11 15:27:49 _recordInstance throws if resultData is null.
Brian Wilkerson 2016/07/11 17:26:36 I don't think that's true. It will invoke runtimeT
247 _recordInstance(resultData.state);
248 _recordInstance(resultData.value, onFirstOccurrence: (Object object) {
249 if (object is AstNode) {
250 object.accept(new AstNodeCounter(directNodeCounts));
251 } else if (object is Element) {
252 object.accept(new ElementCounter(elementCounts, indirectNodeCounts));
253 }
254 });
255 resultData.dependedOnResults.forEach(_processTargetedResult);
256 resultData.dependentResults.forEach(_processTargetedResult);
257 }
258 }
259
260 void _processTargetedResult(TargetedResult result) {
261 _recordInstance(result);
262 uniqueTargetedResults.add(result);
263 _recordInstance(result.target);
264 _recordInstance(result.result);
265 }
266
267 /**
268 * Record the given [instance] that was found. If this is the first time that
269 * the instance has been found, execute the [onFirstOccurrence] function.
270 *
271 * Note that instances will not be recorded if there are more than
272 * [maxInstanceSetSize] instances of the same type, and that the
273 * [onFirstOccurrence] function will not be executed if the instance is not
274 * recorded.
275 */
276 void _recordInstance(Object instance,
277 {void onFirstOccurrence(Object object)}) {
278 Type type = instance.runtimeType;
279 Set instanceSet =
280 instances.putIfAbsent(type, () => new HashSet(equals: identical));
scheglov 2016/07/11 15:27:49 Or just new HashSet.identity()
Brian Wilkerson 2016/07/11 17:26:36 Done.
281 if (instanceSet != InfiniteSet.instance) {
282 if (instanceSet.add(instance) && onFirstOccurrence != null) {
283 onFirstOccurrence(instance);
284 }
285 if (instanceSet.length >= maxInstanceSetSize) {
286 instances[type] = InfiniteSet.instance;
287 }
288 }
289 if (instance is LibrarySpecificUnit) {
290 uniqueLSUs.add(instance);
291 }
292 }
293 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698