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

Side by Side Diff: pkg/analysis_server/test/timing/timing_framework.dart

Issue 625973002: Initial timing framework and test for server (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 2 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2014, 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 test.timing;
6
7 import 'dart:async';
8 import 'dart:io';
9 import 'dart:math';
10
11 import 'package:path/path.dart';
12
13 import '../integration/integration_test_methods.dart';
14 import '../integration/integration_tests.dart';
15
16 /**
17 * The abstract class [TimingTest] defines the behavior of objects that measure
18 * the time required to perform some sequence of server operations.
19 */
20 abstract class TimingTest extends IntegrationTestMixin {
21 /**
22 * The connection to the analysis server.
23 */
24 Server server;
25
26 /**
27 * The temporary directory in which source files can be stored.
28 */
29 Directory sourceDirectory;
30
31 /**
32 * A flag indicating whether the teardown process should skip sending a
33 * "server.shutdown" request because the server is known to have already
34 * shutdown.
35 */
36 bool skipShutdown = false;
37
38 /**
39 * The number of times the test will be performed in order to warm up the VM.
40 */
41 static final int DEFAULT_WARMUP_COUNT = 10;
42
43 /**
44 * The number of times the test will be performed in order to compute a time.
45 */
46 static final int DEFAULT_TIMING_COUNT = 10;
47
48 /**
49 * The file suffix used to identify Dart files.
50 */
51 static final String DART_SUFFIX = '.dart';
52
53 /**
54 * The file suffix used to identify HTML files.
55 */
56 static final String HTML_SUFFIX = '.html';
57
58 /**
59 * The amount of time to give the server to respond to a shutdown request
60 * before forcibly terminating it.
61 */
62 static const Duration SHUTDOWN_TIMEOUT = const Duration(seconds: 5);
63
64 /**
65 * Initialize a newly created test.
66 */
67 TimingTest();
68
69 /**
70 * Return the number of iterations that should be performed in order to warm
71 * up the VM.
72 */
73 int get warmupCount => DEFAULT_WARMUP_COUNT;
74
75 /**
76 * Return the number of iterations that should be performed in order to
77 * compute a time.
78 */
79 int get timingCount => DEFAULT_TIMING_COUNT;
80
81 /**
82 * Perform any operations that need to be performed once before any iterations .
83 */
84 Future oneTimeSetUp() {
85 initializeInttestMixin();
86 server = new Server();
87 sourceDirectory = Directory.systemTemp.createTempSync('analysisServer');
88 Completer serverConnected = new Completer();
89 onServerConnected.listen((_) {
90 serverConnected.complete();
91 });
92 return server.start(dispatchNotification).then((params) {
93 server.exitCode.then((_) {
94 skipShutdown = true;
95 });
96 return serverConnected.future;
97 });
98 }
99
100 /**
101 * Perform any operations that need to be performed before each iteration.
102 */
103 Future setUp();
104
105 /**
106 * Perform any operations that part of a single iteration. It is the execution
107 * of this method that will be measured.
108 */
109 Future perform();
110
111 /**
112 * Perform any operations that need to be performed after each iteration.
113 */
114 Future tearDown();
115
116 /**
117 * Perform any operations that need to be performed once after all iterations.
118 */
119 Future oneTimeTearDown() {
120 return _shutdownIfNeeded().then((_) {
121 sourceDirectory.deleteSync(recursive: true);
122 });
123 }
124
125 /**
126 * Return a future that will complete with a timing result representing the
127 * number of milliseconds required to perform the operation the specified
128 * number of times.
129 */
130 Future<TimingResult> run() {
131 List<int> times = new List<int>();
132 return oneTimeSetUp().then((_) {
133 return _repeat(warmupCount, null).then((_) {
134 return _repeat(timingCount, times).then((_) {
135 return oneTimeTearDown().then((_) {
136 return new Future.value(new TimingResult(times));
137 });
138 });
139 });
140 });
141 }
142
143 /**
144 * Convert the given [relativePath] to an absolute path, by interpreting it
145 * relative to [sourceDirectory]. On Windows any forward slashes in
146 * [relativePath] are converted to backslashes.
147 */
148 String sourcePath(String relativePath) {
149 return join(sourceDirectory.path, relativePath.replaceAll('/', separator));
150 }
151
152 /**
153 * Write a source file with the given absolute [pathname] and [contents].
154 *
155 * If the file didn't previously exist, it is created. If it did, it is
156 * overwritten.
157 *
158 * Parent directories are created as necessary.
159 */
160 void writeFile(String pathname, String contents) {
161 new Directory(dirname(pathname)).createSync(recursive: true);
162 new File(pathname).writeAsStringSync(contents);
163 }
164
165 /**
166 * Return the number of nanoseconds that have elapsed since the given
167 * [stopwatch] was last stopped.
168 */
169 int _elapsedNanoseconds(Stopwatch stopwatch) {
170 return (stopwatch.elapsedTicks * 1000000000) ~/ stopwatch.frequency;
171 }
172
173 /**
174 * Repeatedly execute this test [count] times, adding timing information to
175 * the given list of [times] if it is non-`null`.
176 */
177 Future _repeat(int count, List<int> times) {
178 Stopwatch stopwatch = new Stopwatch();
179 return setUp().then((_) {
180 stopwatch..reset..start();
scheglov 2014/10/03 16:46:14 ..reset() ?
Brian Wilkerson 2014/10/03 17:17:37 Left over from an earlier timing framework that I
181 return perform().then((_) {
182 stopwatch.stop();
183 if (times != null) {
184 times.add(_elapsedNanoseconds(stopwatch));
185 }
186 return tearDown().then((_) {
187 if (count > 0) {
188 return _repeat(count - 1, times);
189 } else {
190 return new Future.value();
191 }
192 });
193 });
194 });
195 }
196
197 /**
198 * Shut the server down unless [skipShutdown] is `true`.
199 */
200 Future _shutdownIfNeeded() {
201 if (skipShutdown) {
202 return new Future.value();
203 }
204 // Give the server a short time to comply with the shutdown request; if it
205 // doesn't exit, then forcibly terminate it.
206 Completer processExited = new Completer();
207 sendServerShutdown();
208 return server.exitCode.timeout(SHUTDOWN_TIMEOUT, onTimeout: () {
209 return server.kill();
210 });
211 }
212 }
213
214 /**
215 * Instances of the class [TimingResult] represent the timing information
216 * gathered while executing a given timing test.
217 */
218 class TimingResult {
219 /**
220 * The amount of time spent executing each test, in nanoseconds.
221 */
222 List<int> times;
223
224 /**
225 * The number of nanoseconds in a millisecond.
226 */
227 static int NANOSECONDS_PER_MILLISECOND = 1000000;
228
229 /**
230 * Initialize a newly created timing result.
231 */
232 TimingResult(this.times);
233
234 /**
235 * The average amount of time spent executing a single iteration, in
236 * milliseconds.
237 */
238 int get averageTime {
239 return totalTime ~/ times.length;
240 }
241
242 /**
243 * The maximum amount of time spent executing a single iteration, in
244 * milliseconds.
245 */
246 int get maxTime {
247 int maxTime = 0;
248 int count = times.length;
249 for (int i = 0; i < count; i++) {
250 maxTime = max(maxTime, times[i]);
251 }
252 return maxTime ~/ NANOSECONDS_PER_MILLISECOND;
253 }
254
255 /**
256 * The minimum amount of time spent executing a single iteration, in
257 * milliseconds.
258 */
259 int get minTime {
260 int minTime = 0xFFFFFFFF;
Paul Berry 2014/10/03 16:58:35 0xFFFFFFFF nanoseconds ~= 4 seconds. I don't thin
Brian Wilkerson 2014/10/03 17:17:37 Done
261 int count = times.length;
262 for (int i = 0; i < count; i++) {
263 minTime = min(minTime, times[i]);
264 }
265 return minTime ~/ NANOSECONDS_PER_MILLISECOND;
266 }
267
268 /**
269 * The standard deviation of the times.
270 */
271 double get standardDeviation {
272 return computeStandardDeviation(toMilliseconds(times));
273 }
274
275 /**
276 * The total amount of time spent executing the test, in milliseconds.
277 */
278 int get totalTime {
279 int totalTime = 0;
280 int count = times.length;
281 for (int i = 0; i < count; i++) {
282 totalTime += times[i];
283 }
284 return totalTime ~/ NANOSECONDS_PER_MILLISECOND;
285 }
286
287 /**
288 * Compute the standard deviation of the given set of [values].
289 */
290 double computeStandardDeviation(List<int> values) {
291 int count = values.length;
292 double sumOfValues = 0.0;
293 for (int i = 0; i < count; i++) {
294 sumOfValues += values[i];
295 }
296 double average = sumOfValues / count;
297 double sumOfDiffSquared = 0.0;
298 for (int i = 0; i < count; i++) {
299 double diff = values[i] - average;
300 sumOfDiffSquared += diff * diff;
301 }
302 // If this were a sample we would divide by (count - 1).
303 return sqrt((sumOfDiffSquared / count));
Paul Berry 2014/10/03 16:58:35 Using (count - 1) is correct in this circumstance.
Brian Wilkerson 2014/10/03 17:17:37 Done
304 }
305
306 /**
307 * Convert the given [times], expressed in nanoseconds, to times expressed in
308 * milliseconds.
309 */
310 List<int> toMilliseconds(List<int> times) {
311 int count = times.length;
312 List<int> convertedValues = new List<int>();
313 for (int i = 0; i < count; i++) {
314 convertedValues.add(times[i] ~/ NANOSECONDS_PER_MILLISECOND);
315 }
316 return convertedValues;
317 }
318 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698