forked from DonJayamanne/pythonVSCode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathperformanceTest.ts
More file actions
181 lines (155 loc) · 7.53 KB
/
performanceTest.ts
File metadata and controls
181 lines (155 loc) · 7.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';
/*
Comparing performance metrics is not easy (the metrics can and always get skewed).
One approach is to run the tests multile times and gather multiple sample data.
For Extension activation times, we load both extensions x times, and re-load the window y times in each x load.
I.e. capture averages by giving the extensions sufficient time to warm up.
This block of code merely launches the tests by using either the dev or release version of the extension,
and spawning the tests (mimic user starting tests from command line), this way we can run tests multiple times.
*/
// tslint:disable:no-console no-require-imports no-var-requires
import { spawn } from 'child_process';
import * as download from 'download';
import * as fs from 'fs-extra';
import * as path from 'path';
import * as request from 'request';
import { EXTENSION_ROOT_DIR, PVSC_EXTENSION_ID } from '../client/common/constants';
const NamedRegexp = require('named-js-regexp');
const StreamZip = require('node-stream-zip');
const del = require('del');
const tmpFolder = path.join(EXTENSION_ROOT_DIR, 'tmp');
const publishedExtensionPath = path.join(tmpFolder, 'ext', 'testReleaseExtensionsFolder');
const logFilesPath = path.join(tmpFolder, 'test', 'logs');
enum Version {
Dev, Release
}
class TestRunner {
public async start() {
await del([path.join(tmpFolder, '**')]);
await this.extractLatestExtension(publishedExtensionPath);
const timesToLoadEachVersion = 2;
const devLogFiles: string[] = [];
const releaseLogFiles: string[] = [];
const languageServerLogFiles: string[] = [];
for (let i = 0; i < timesToLoadEachVersion; i += 1) {
await this.enableLanguageServer(false);
const devLogFile = path.join(logFilesPath, `dev_loadtimes${i}.txt`);
console.log(`Start Performance Tests: Counter ${i}, for Dev version with Jedi`);
await this.capturePerfTimes(Version.Dev, devLogFile);
devLogFiles.push(devLogFile);
const releaseLogFile = path.join(logFilesPath, `release_loadtimes${i}.txt`);
console.log(`Start Performance Tests: Counter ${i}, for Release version with Jedi`);
await this.capturePerfTimes(Version.Release, releaseLogFile);
releaseLogFiles.push(releaseLogFile);
// Language server.
await this.enableLanguageServer(true);
const languageServerLogFile = path.join(logFilesPath, `languageServer_loadtimes${i}.txt`);
console.log(`Start Performance Tests: Counter ${i}, for Release version with Language Server`);
await this.capturePerfTimes(Version.Release, languageServerLogFile);
languageServerLogFiles.push(languageServerLogFile);
}
console.log('Compare Performance Results');
await this.runPerfTest(devLogFiles, releaseLogFiles, languageServerLogFiles);
}
private async enableLanguageServer(enable: boolean) {
const settings = `{ "python.jediEnabled": ${!enable} }`;
await fs.writeFile(path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'performance', 'settings.json'), settings);
}
private async capturePerfTimes(version: Version, logFile: string) {
const releaseVersion = await this.getReleaseVersion();
const devVersion = await this.getDevVersion();
await fs.ensureDir(path.dirname(logFile));
const env: { [key: string]: {} } = {
ACTIVATION_TIMES_LOG_FILE_PATH: logFile,
ACTIVATION_TIMES_EXT_VERSION: version === Version.Release ? releaseVersion : devVersion,
CODE_EXTENSIONS_PATH: version === Version.Release ? publishedExtensionPath : EXTENSION_ROOT_DIR
};
await this.launchTest(env);
}
private async runPerfTest(devLogFiles: string[], releaseLogFiles: string[], languageServerLogFiles: string[]) {
const env: { [key: string]: {} } = {
ACTIVATION_TIMES_DEV_LOG_FILE_PATHS: JSON.stringify(devLogFiles),
ACTIVATION_TIMES_RELEASE_LOG_FILE_PATHS: JSON.stringify(releaseLogFiles),
ACTIVATION_TIMES_DEV_LANGUAGE_SERVER_LOG_FILE_PATHS: JSON.stringify(languageServerLogFiles)
};
await this.launchTest(env);
}
private async launchTest(customEnvVars: { [key: string]: {} }) {
await new Promise((resolve, reject) => {
const env: { [key: string]: {} } = {
TEST_FILES_SUFFIX: 'perf.test',
CODE_TESTS_WORKSPACE: path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'performance'),
...process.env,
...customEnvVars
};
const proc = spawn('node', [path.join(__dirname, 'standardTest.js')], { cwd: EXTENSION_ROOT_DIR, env });
proc.stdout.pipe(process.stdout);
proc.stderr.pipe(process.stderr);
proc.on('error', reject);
proc.on('close', code => {
if (code === 0) {
resolve();
} else {
reject(`Failed with code ${code}.`);
}
});
});
}
private async extractLatestExtension(targetDir: string): Promise<void> {
const extensionFile = await this.downloadExtension();
await this.unzip(extensionFile, targetDir);
}
private async getReleaseVersion(): Promise<string> {
const url = `https://marketplace.visualstudio.com/items?itemName=${PVSC_EXTENSION_ID}`;
const content = await new Promise<string>((resolve, reject) => {
request(url, (error, response, body) => {
if (error) {
return reject(error);
}
if (response.statusCode === 200) {
return resolve(body);
}
reject(`Status code of ${response.statusCode} received.`);
});
});
const re = NamedRegexp('"version"\S?:\S?"(:<version>\\d{4}\\.\\d{1,2}\\.\\d{1,2})"', 'g');
const matches = re.exec(content);
return matches.groups().version;
}
private async getDevVersion(): Promise<string> {
// tslint:disable-next-line:non-literal-require
return require(path.join(EXTENSION_ROOT_DIR, 'package.json')).version;
}
private async unzip(zipFile: string, targetFolder: string): Promise<void> {
await fs.ensureDir(targetFolder);
return new Promise<void>((resolve, reject) => {
const zip = new StreamZip({
file: zipFile,
storeEntries: true
});
zip.on('ready', async () => {
zip.extract('extension', targetFolder, err => {
if (err) {
reject(err);
} else {
resolve();
}
zip.close();
});
});
});
}
private async downloadExtension(): Promise<string> {
const version = await this.getReleaseVersion();
const url = `https://marketplace.visualstudio.com/_apis/public/gallery/publishers/ms-python/vsextensions/python/${version}/vspackage`;
const destination = path.join(__dirname, `extension${version}.zip`);
if (await fs.pathExists(destination)) {
return destination;
}
await download(url, path.dirname(destination), { filename: path.basename(destination) });
return destination;
}
}
new TestRunner().start().catch(ex => console.error('Error in running Performance Tests', ex));