Remove database-related functionality from perf tool (#378)

* [perf] Remove all database-related functionality

* Throw error on comparison attempt for new package

* Update tests
This commit is contained in:
Andrew Branch
2022-01-13 09:48:02 -08:00
committed by GitHub
parent e79ad8f902
commit 170e87dca9
24 changed files with 110 additions and 927 deletions

View File

@@ -15,7 +15,6 @@
"url": "git://github.com/andrewbranch/definitely-not-slow.git"
},
"dependencies": {
"@azure/cosmos": "^3.6.3",
"@definitelytyped/definitions-parser": "^0.0.101-next.7",
"@definitelytyped/header-parser": "^0.0.100",
"@definitelytyped/utils": "^0.0.100",

View File

@@ -1,5 +1,5 @@
import { mean } from "../measure/utils";
import { PackageBenchmarkSummary, Document, config, getPercentDiff, supportsMemoryUsage, not } from "../common";
import { PackageBenchmarkSummary, config, getPercentDiff } from "../common";
import { assertNever } from "@definitelytyped/utils";
export interface FormatOptions {
@@ -19,8 +19,8 @@ export type GetSignificance = (
percentDiff: number,
beforeValue: number,
afterValue: number,
beforeDoc: Document<PackageBenchmarkSummary>,
afterDoc: Document<PackageBenchmarkSummary>
beforeDoc: PackageBenchmarkSummary,
afterDoc: PackageBenchmarkSummary
) => SignificanceLevel | undefined;
export type CreateGetSignificance = (getSignificance: GetSignificance) => GetSignificance;
@@ -29,7 +29,7 @@ export interface Metric {
columnName: string;
sentenceName: string;
formatOptions?: FormatOptions;
getValue: (x: Document<PackageBenchmarkSummary>) => number | undefined;
getValue: (x: PackageBenchmarkSummary) => number | undefined;
getSignificance: GetSignificance;
}
@@ -139,21 +139,6 @@ function withThreshold(fineIf: FineIf, threshold: number) {
};
}
function ignoreIfEitherBenchmark(predicate: (document: Document<PackageBenchmarkSummary>) => boolean) {
return (getSignificance: GetSignificance): GetSignificance => (
percentDiff,
beforeValue,
afterValue,
beforeDoc,
afterDoc
) => {
if (predicate(beforeDoc) || predicate(afterDoc)) {
return undefined;
}
return getSignificance(percentDiff, beforeValue, afterValue, beforeDoc, afterDoc);
};
}
function compose(x: CreateGetSignificance, ...xs: CreateGetSignificance[]): CreateGetSignificance {
return getSignificance => {
let current = x(getSignificance);
@@ -169,7 +154,7 @@ export const metrics: { [K in MetricName]: Metric } = {
columnName: "Type count",
sentenceName: "type count",
formatOptions: { precision: 0 },
getValue: x => x.body.typeCount,
getValue: x => x.typeCount,
getSignificance: compose(
proportionalTo("identifierCount"),
withThreshold(FineIf.LessThan, 5000)
@@ -178,18 +163,17 @@ export const metrics: { [K in MetricName]: Metric } = {
memoryUsage: {
columnName: "Memory usage (MiB)",
sentenceName: "memory usage",
getValue: x => x.body.memoryUsage / 2 ** 20,
getValue: x => x.memoryUsage / 2 ** 20,
getSignificance: compose(
proportionalTo("identifierCount"),
withThreshold(FineIf.LessThan, 65),
ignoreIfEitherBenchmark(not(supportsMemoryUsage))
)(getOrderOfMagnitudeSignificance)
},
assignabilityCacheSize: {
columnName: "Assignability cache size",
sentenceName: "assignability cache size",
formatOptions: { precision: 0 },
getValue: x => x.body.relationCacheSizes && x.body.relationCacheSizes.assignable,
getValue: x => x.relationCacheSizes && x.relationCacheSizes.assignable,
getSignificance: compose(
proportionalTo("identifierCount"),
withThreshold(FineIf.LessThan, 1000)
@@ -199,64 +183,64 @@ export const metrics: { [K in MetricName]: Metric } = {
columnName: "Samples taken",
sentenceName: "number of samples taken",
formatOptions: { precision: 0 },
getValue: x => Math.max(x.body.completions.trials, x.body.quickInfo.trials),
getValue: x => Math.max(x.completions.trials, x.quickInfo.trials),
getSignificance: getInsignificant
},
identifierCount: {
columnName: "Identifiers in tests",
sentenceName: "number of identifiers present in test files",
formatOptions: { precision: 0 },
getValue: x => x.body.testIdentifierCount,
getValue: x => x.testIdentifierCount,
getSignificance: getInsignificant
},
completionsMean: {
columnName: "Mean duration (ms)",
sentenceName: "mean duration for getting completions at a position",
getValue: x => x.body.completions.mean,
getValue: x => x.completions.mean,
getSignificance: withThreshold(FineIf.LessThan, 150)(getDefaultSignificance)
},
completionsStdDev: {
columnName: "Std. deviation (ms)",
sentenceName: "standard deviation of the durations for getting completions at a position",
getValue: x => x.body.completions.standardDeviation,
getValue: x => x.completions.standardDeviation,
getSignificance: getInsignificant
},
completionsAvgCV: {
columnName: "Mean [CV](https://en.wikipedia.org/wiki/Coefficient_of_variation)",
sentenceName: "mean coefficient of variation of samples measured for completions time",
getValue: x => x.body.completions.meanCoefficientOfVariation,
getValue: x => x.completions.meanCoefficientOfVariation,
getSignificance: getInsignificant,
formatOptions: { percentage: true, noDiff: true }
},
completionsWorstMean: {
columnName: "Worst duration (ms)",
sentenceName: "worst-case duration for getting completions at a position",
getValue: x => mean(x.body.completions.worst.completionsDurations),
getValue: x => mean(x.completions.worst.completionsDurations),
getSignificance: withThreshold(FineIf.LessThan, 200)(getDefaultSignificance)
},
quickInfoMean: {
columnName: "Mean duration (ms)",
sentenceName: "mean duration for getting quick info at a position",
getValue: x => x.body.quickInfo.mean,
getValue: x => x.quickInfo.mean,
getSignificance: withThreshold(FineIf.LessThan, 150)(getDefaultSignificance)
},
quickInfoStdDev: {
columnName: "Std. deviation (ms)",
sentenceName: "standard deviation of the durations for getting quick info at a position",
getValue: x => x.body.quickInfo.standardDeviation,
getValue: x => x.quickInfo.standardDeviation,
getSignificance: getInsignificant
},
quickInfoAvgCV: {
columnName: "Mean [CV](https://en.wikipedia.org/wiki/Coefficient_of_variation)",
sentenceName: "mean coefficient of variation of samples measured for quick info time",
getValue: x => x.body.quickInfo.meanCoefficientOfVariation,
getValue: x => x.quickInfo.meanCoefficientOfVariation,
getSignificance: getInsignificant,
formatOptions: { percentage: true, noDiff: true }
},
quickInfoWorstMean: {
columnName: "Worst duration (ms)",
sentenceName: "worst-case duration for getting quick info at a position",
getValue: x => mean(x.body.quickInfo.worst.quickInfoDurations),
getValue: x => mean(x.quickInfo.worst.quickInfoDurations),
getSignificance: withThreshold(FineIf.LessThan, 200)(getDefaultSignificance)
}
};
@@ -268,8 +252,8 @@ export interface ComparedMetric {
}
export function getInterestingMetrics(
before: Document<PackageBenchmarkSummary>,
after: Document<PackageBenchmarkSummary>
before: PackageBenchmarkSummary,
after: PackageBenchmarkSummary
): ComparedMetric[] {
return Object.values(metrics).reduce(
(acc: { metric: Metric; percentDiff: number; significance: SignificanceLevel }[], metric) => {

View File

@@ -1,8 +1,8 @@
import { PackageBenchmarkSummary, Document } from "../common";
import { PackageBenchmarkSummary } from "../common";
import { getInterestingMetrics, SignificanceLevel } from "./metrics";
import { assertNever } from "@definitelytyped/utils";
type BeforeAndAfter = [Document<PackageBenchmarkSummary> | undefined, Document<PackageBenchmarkSummary>];
type BeforeAndAfter = [PackageBenchmarkSummary, PackageBenchmarkSummary];
export enum OverallChange {
Same = 0,
@@ -12,8 +12,8 @@ export enum OverallChange {
}
export function getOverallChangeForSingleComparison(
before: Document<PackageBenchmarkSummary>,
after: Document<PackageBenchmarkSummary>
before: PackageBenchmarkSummary,
after: PackageBenchmarkSummary
) {
let change = OverallChange.Same;
for (const { significance } of getInterestingMetrics(before, after)) {

View File

@@ -1,16 +1,12 @@
import * as os from "os";
import * as path from "path";
import {
getDatabase,
DatabaseAccessLevel,
config,
getParsedPackages,
assertString,
assertNumber,
getSystemInfo
} from "../common";
import { getTypeScript } from "../measure/getTypeScript";
import { insertDocument } from "../write";
import { printSummary, measurePerf } from "../measure";
import { summarize } from "../analysis";
import { PackageId, formatDependencyVersion, tryParsePackageVersion } from "@definitelytyped/definitions-parser";
@@ -21,7 +17,6 @@ export interface BenchmarkPackageOptions {
groups?: PackageId[][];
agentIndex?: number;
package?: string;
upload: boolean;
tsVersion: string;
progress: boolean;
iterations: number;
@@ -87,7 +82,6 @@ export async function benchmarkPackage(
options: BenchmarkPackageOptions
) {
const {
upload,
progress,
iterations,
nProcesses,
@@ -129,16 +123,5 @@ export async function benchmarkPackage(
printSummary([summary]);
}
if (upload) {
const { packageBenchmarks } = await getDatabase(DatabaseAccessLevel.Write);
const item = await insertDocument(
summary,
config.database.packageBenchmarksDocumentSchemaVersion,
packageBenchmarks
);
return { benchmark, summary, id: item.id };
}
return { benchmark, summary, id: undefined };
}

View File

@@ -1,20 +1,12 @@
import * as os from "os";
import {
getDatabase,
DatabaseAccessLevel,
config,
getChangedPackages,
packageIdsAreEqual,
PackageBenchmarkSummary,
getParsedPackages,
Document,
createDocument,
shuffle,
systemsAreCloseEnough,
getSystemInfo,
forEachWithTimeLimit
} from "../common";
import { getLatestBenchmark } from "../query";
import { benchmarkPackage } from "./benchmark";
import { printSummary } from "../measure";
import { getTypeScript } from "../measure/getTypeScript";
@@ -23,12 +15,9 @@ import { postDependentsComparisonResult } from "../github/postDependentsComparis
import {
AllPackages,
DependencyVersion,
formatDependencyVersion,
getAffectedPackages,
PackageId
} from "@definitelytyped/definitions-parser";
import { execAndThrowErrors } from "@definitelytyped/utils";
const currentSystem = getSystemInfo();
export interface CompareOptions {
allPackages: AllPackages;
@@ -67,7 +56,7 @@ export async function compare({
await getTypeScript(tsVersion);
const affectedPackages = getAffectedPackages(allPackages, changedPackages);
const comparisons: [Document<PackageBenchmarkSummary> | undefined, Document<PackageBenchmarkSummary>][] = [];
const comparisons: [PackageBenchmarkSummary, PackageBenchmarkSummary][] = [];
const maxRunMs = (maxRunSeconds ?? Infinity) * 1000;
const { overtime } = await forEachWithTimeLimit(
maxRunMs,
@@ -104,7 +93,7 @@ export async function compare({
}
}
const dependentComparisons: [Document<PackageBenchmarkSummary> | undefined, Document<PackageBenchmarkSummary>][] = [];
const dependentComparisons: [PackageBenchmarkSummary, PackageBenchmarkSummary][] = [];
await forEachWithTimeLimit(
maxRunMs,
dependentsToTest,
@@ -136,79 +125,35 @@ export async function compare({
}
export async function compareBenchmarks({
allPackages,
definitelyTypedPath,
typeScriptVersionMajorMinor,
packageName,
packageVersion,
maxRunSeconds,
upload = true
}: CompareOptions): Promise<[Document<PackageBenchmarkSummary> | undefined, Document<PackageBenchmarkSummary>]> {
const typings = allPackages.getTypingsData({ name: packageName, version: packageVersion });
const { packageBenchmarks: container } = await getDatabase(DatabaseAccessLevel.Read);
const latestBenchmarkDocument = await getLatestBenchmark({
container,
typeScriptVersionMajorMinor,
packageName,
packageVersion: typings.id.version,
matchMinor: allPackages.hasSeparateMinorVersions(packageName)
});
}: CompareOptions): Promise<[PackageBenchmarkSummary, PackageBenchmarkSummary]> {
await execAndThrowErrors("git checkout -f origin/master && git clean -xdf types", definitelyTypedPath);
const baseBenchmark = (await benchmarkPackage(packageName, packageVersion.toString(), new Date(), {
definitelyTypedPath,
printSummary: false,
iterations: config.benchmarks.languageServiceIterations,
progress: false,
tsVersion: typeScriptVersionMajorMinor,
nProcesses: os.cpus().length,
failOnErrors: true,
installTypeScript: false,
maxRunSeconds
}))?.summary;
let latestBenchmark: PackageBenchmarkSummary | undefined = latestBenchmarkDocument && latestBenchmarkDocument.body;
const packageId: PackageId = {
name: packageName,
version: packageVersion
};
const changedPackagesBetweenLastRunAndMaster =
latestBenchmark &&
(await getChangedPackages({
diffFrom: "origin/master",
diffTo: latestBenchmark.sourceVersion,
definitelyTypedPath
}));
if (latestBenchmarkDocument && !systemsAreCloseEnough(currentSystem, latestBenchmarkDocument.system)) {
latestBenchmark = undefined;
if (!baseBenchmark) {
throw new Error(`Package ${packageName} does not exist in master so cannot be compared.`);
}
if (changedPackagesBetweenLastRunAndMaster || !latestBenchmark) {
let needsRerun = !latestBenchmark;
if (changedPackagesBetweenLastRunAndMaster) {
const affectedPackages = getAffectedPackages(allPackages, changedPackagesBetweenLastRunAndMaster);
const affected = [...affectedPackages.changedPackages, ...affectedPackages.dependentPackages];
needsRerun = affected.some(affectedPackage => packageIdsAreEqual(packageId, affectedPackage.id));
}
if (needsRerun) {
console.log(
`No comparable benchmark for ${packageName}/v${formatDependencyVersion(
packageVersion
)}. Checking out master and running one...`
);
await execAndThrowErrors("git checkout -f origin/master && git clean -xdf types", definitelyTypedPath);
const latest = await benchmarkPackage(packageName, packageVersion.toString(), new Date(), {
definitelyTypedPath,
printSummary: false,
iterations: config.benchmarks.languageServiceIterations,
progress: false,
upload,
tsVersion: typeScriptVersionMajorMinor,
nProcesses: os.cpus().length,
failOnErrors: true,
installTypeScript: false,
maxRunSeconds
});
await execAndThrowErrors(`git checkout -f . && git checkout - && git clean -xdf types`, definitelyTypedPath);
latestBenchmark = latest && latest.summary;
}
}
const currentBenchmark = (await benchmarkPackage(packageName, packageVersion.toString(), new Date(), {
await execAndThrowErrors(`git checkout -f . && git checkout - && git clean -xdf types`, definitelyTypedPath);
const headBenchmark = (await benchmarkPackage(packageName, packageVersion.toString(), new Date(), {
definitelyTypedPath,
printSummary: true,
iterations: config.benchmarks.languageServiceIterations,
progress: false,
upload: false,
tsVersion: typeScriptVersionMajorMinor,
nProcesses: os.cpus().length,
failOnErrors: true,
@@ -216,18 +161,17 @@ export async function compareBenchmarks({
maxRunSeconds
}))!.summary;
if (latestBenchmark) {
if (baseBenchmark) {
console.log("\nmaster");
console.log("======");
console.log(printSummary([latestBenchmark]));
console.log(printSummary([baseBenchmark]));
}
console.log("\nHEAD");
console.log("====");
console.log(printSummary([currentBenchmark]));
console.log(printSummary([headBenchmark]));
return [
latestBenchmarkDocument ||
(latestBenchmark && createDocument(latestBenchmark, config.database.packageBenchmarksDocumentSchemaVersion)),
createDocument(currentBenchmark, config.database.packageBenchmarksDocumentSchemaVersion)
baseBenchmark,
headBenchmark,
];
}

View File

@@ -1,272 +0,0 @@
import * as os from "os";
import * as fs from "fs";
import * as path from "path";
import { promisify } from "util";
import {
getDatabase,
DatabaseAccessLevel,
Document,
PackageBenchmarkSummary,
getChangedPackages,
packageIdsAreEqual,
getParsedPackages,
config,
toPackageKey,
parsePackageKey,
createDocument,
assertString,
getSystemInfo,
systemsAreCloseEnough,
JSONDocument,
deserializeSummary,
QueryResult,
TypeScriptComparisonRun,
getSourceVersion
} from "../common";
import { Container, FeedResponse } from "@azure/cosmos";
import { benchmarkPackage } from "./benchmark";
import { getTypeScript } from "../measure/getTypeScript";
import { postTypeScriptComparisonResults } from "../github/postTypeScriptComparisonResult";
import { insertDocument } from "../write";
import { PackageId, AllPackages, formatDependencyVersion } from "@definitelytyped/definitions-parser";
import { assertDefined } from "@definitelytyped/utils";
const writeFile = promisify(fs.writeFile);
const currentSystem = getSystemInfo();
export interface CompareTypeScriptOptions {
compareAgainstVersion: string;
definitelyTypedPath: string;
packages?: PackageId[];
maxRunSeconds?: number;
localTypeScriptPath: string;
outFile?: string;
groups?: { [key: string]: QueryResult<JSONDocument<PackageBenchmarkSummary>> }[];
agentCount?: number;
agentIndex?: number;
upload?: boolean;
}
export interface CompareTypeScriptCLIArgs {
file?: string;
compareAgainstVersion: string;
definitelyTypedPath: string;
localTypeScriptPath: string;
maxRunSeconds?: number;
outFile?: string;
upload?: boolean;
packages?: PackageId[];
}
function convertArgs({ file, ...args }: CompareTypeScriptCLIArgs): CompareTypeScriptOptions {
if (file) {
// tslint:disable-next-line:non-literal-require -- filename comes from Azure artifact
const jsonContent = require(path.resolve(assertString(file, "file")));
return {
...args,
...jsonContent.options,
groups: jsonContent.groups
};
}
return args;
}
export function compareTypeScriptCLI(args: CompareTypeScriptCLIArgs) {
return compareTypeScript(convertArgs(args));
}
export async function compareTypeScript({
compareAgainstVersion,
definitelyTypedPath,
packages,
maxRunSeconds,
localTypeScriptPath: typeScriptPath,
upload,
outFile,
groups,
...opts
}: CompareTypeScriptOptions) {
const { packageBenchmarks, typeScriptComparisons } = await getDatabase(
upload && !outFile ? DatabaseAccessLevel.Write : DatabaseAccessLevel.Read
);
const agentIndex = groups && assertDefined(opts.agentIndex, "agentIndex");
const priorResults = groups
? new Map<string, QueryResult<Document<PackageBenchmarkSummary>>>(
Object.keys(groups[agentIndex!]).map(key => [key, deserializeSummary(groups[agentIndex!][key])] as const)
)
: await getPackagesToTestAndPriorResults(
packageBenchmarks,
compareAgainstVersion,
definitelyTypedPath,
(await getParsedPackages(definitelyTypedPath)).allPackages,
packages
);
if (outFile) {
const agentCount = assertDefined(opts.agentCount, "agentCount");
const fileContent = JSON.stringify(
{
options: {
compareAgainstVersion,
definitelyTypedPath,
maxRunSeconds,
typeScriptPath,
upload
},
groups: Array.from(priorResults.keys()).reduce((groups, key, index) => {
const agentIndex = index % agentCount;
if (groups[agentIndex]) {
groups[agentIndex][key] = priorResults.get(key)!;
} else {
groups[agentIndex] = { [key]: priorResults.get(key)! };
}
return groups;
}, [] as { [key: string]: Document<PackageBenchmarkSummary> }[])
},
undefined,
2
);
return writeFile(outFile, fileContent, "utf8");
}
await getTypeScript(compareAgainstVersion);
const packagesToTest = packages
? packages.map(p => `${p.name}/v${formatDependencyVersion(p.version)}`)
: Array.from(priorResults.keys());
const now = new Date();
const comparisons: [Document<PackageBenchmarkSummary>, Document<PackageBenchmarkSummary>][] = [];
for (const packageKey of packagesToTest) {
const { name, version } = parsePackageKey(packageKey);
let priorResult:
| Document<PackageBenchmarkSummary>
| QueryResult<Document<PackageBenchmarkSummary>>
| undefined = priorResults.get(packageKey);
const priorResultId = priorResult && "id" in priorResult && priorResult.id;
if (priorResult) {
if (!systemsAreCloseEnough(currentSystem, priorResult.system)) {
console.log(`Skipping ${packageKey} because the system is too different`);
continue;
}
} else {
const benchmark = await benchmarkPackage(name, formatDependencyVersion(version), now, {
definitelyTypedPath,
iterations: config.benchmarks.languageServiceIterations,
tsVersion: compareAgainstVersion,
nProcesses: os.cpus().length,
printSummary: true,
progress: false,
upload: !!upload,
installTypeScript: false,
failOnErrors: false,
maxRunSeconds
});
if (!benchmark) {
console.log(`Skipping ${packageKey} because it was deleted`);
continue;
}
priorResult = {
id: benchmark.id,
...createDocument(benchmark.summary, config.database.packageBenchmarksDocumentSchemaVersion)
};
}
const currentResult = createDocument(
(await benchmarkPackage(name, formatDependencyVersion(version), now, {
definitelyTypedPath,
iterations: config.benchmarks.languageServiceIterations,
tsVersion: "local",
localTypeScriptPath: typeScriptPath,
nProcesses: os.cpus().length,
printSummary: true,
progress: false,
upload: false,
installTypeScript: false,
failOnErrors: false,
maxRunSeconds
}))!.summary,
config.database.packageBenchmarksDocumentSchemaVersion
);
comparisons.push([priorResult!, currentResult]);
if (upload && priorResultId) {
const comparison: TypeScriptComparisonRun = {
sourceVersion: getSourceVersion(typeScriptPath),
compareAgainstPackageBenchmarkId: priorResultId,
headBenchmark: currentResult.body
};
await insertDocument(
comparison,
config.database.typeScriptComparisonsDocumentSchemaVersion,
typeScriptComparisons
);
}
}
const comment = await postTypeScriptComparisonResults({ comparisons, dryRun: true });
console.log(comment);
}
async function getPackagesToTestAndPriorResults(
container: Container,
typeScriptVersion: string,
definitelyTypedPath: string,
allPackages: AllPackages,
packageList?: PackageId[]
) {
const iterator: AsyncIterable<FeedResponse<QueryResult<Document<PackageBenchmarkSummary>>>> = await container.items
.query({
query:
`SELECT * FROM ${config.database.packageBenchmarksContainerId} b` +
` WHERE b.body.typeScriptVersionMajorMinor = @typeScriptVersion` +
(packageList
? ` AND b.body.packageName IN (${packageList!.map(({ name }) => `"${name}"`).join(", ")})` // Couldnt figure out how to do this with parameters
: ""),
parameters: [{ name: "@typeScriptVersion", value: typeScriptVersion }]
})
.getAsyncIterator();
const packageKeys = packageList && packageList.map(id => toPackageKey(allPackages.resolve(id)));
const packages = new Map<string, QueryResult<Document<PackageBenchmarkSummary>>>();
for await (const x of iterator) {
for (const result of x.resources) {
if (!result) continue;
const packageKey = toPackageKey(result.body);
if (packageKeys && !packageKeys.includes(packageKey)) {
continue;
}
const candidate = packages.get(packageKey);
if (candidate && candidate.createdAt > result.createdAt) {
continue;
}
const packageId: PackageId = {
name: result.body.packageName,
version: { major: result.body.packageVersionMajor, minor: result.body.packageVersionMinor }
};
const changedPackages = await getChangedPackages({ diffTo: result.body.sourceVersion, definitelyTypedPath });
if (changedPackages && changedPackages.some(packageIdsAreEqual(packageId))) {
console.log(`Skipping ${packageKey} because it changed`);
continue;
} else if (changedPackages) {
const dependencies = allPackages.getTypingsData(packageId).dependencies;
if (
Object.entries(dependencies).some(([name, version]) =>
changedPackages.some(packageIdsAreEqual({ name, version }))
)
) {
console.log(`Skipping ${packageKey} because one or more of its dependencies changed`);
continue;
}
}
packages.set(packageKey, result);
}
}
return packages;
}

View File

@@ -1,108 +0,0 @@
import * as fs from "fs";
import { promisify } from "util";
import {
getDatabase,
getParsedPackages,
DatabaseAccessLevel,
compact,
getSystemInfo,
getChangedPackages,
packageIdsAreEqual,
systemsAreCloseEnough
} from "../common";
import { BenchmarkPackageOptions } from "./benchmark";
import { getLatestBenchmark } from "../query";
import { nAtATime } from "@definitelytyped/utils";
import { getAffectedPackages, PackageId, formatDependencyVersion } from "@definitelytyped/definitions-parser";
const writeFile = promisify(fs.writeFile);
const currentSystem = getSystemInfo();
export interface GetPackagesToBenchmarkOptions {
definitelyTypedPath: string;
tsVersion: string;
agentCount: number;
outFile: string;
}
export async function getPackagesToBenchmark({
definitelyTypedPath,
agentCount,
tsVersion,
outFile
}: GetPackagesToBenchmarkOptions) {
if (tsVersion.split(".").length !== 2) {
throw new Error(`Argument 'typeScriptVersion' must be in format 'major.minor' (e.g. '3.1')`);
}
const { allPackages } = await getParsedPackages(definitelyTypedPath);
const { packageBenchmarks: container } = await getDatabase(DatabaseAccessLevel.Read);
const changedPackages = await nAtATime(10, allPackages.allTypings(), async typingsData => {
const result = await getLatestBenchmark({
container,
typeScriptVersionMajorMinor: tsVersion,
packageName: typingsData.id.name,
packageVersion: typingsData.id.version,
matchMinor: allPackages.hasSeparateMinorVersions(typingsData.name)
});
// No previous run exists; run one
if (!result) {
return typingsData.id;
}
// System specs are different; run it
if (!systemsAreCloseEnough(result.system, currentSystem)) {
console.log(
`Queueing ${typingsData.id.name}/v${formatDependencyVersion(typingsData.id.version)} due to system change`
);
return typingsData.id;
}
const changedPackages = await getChangedPackages({ diffTo: result.body.sourceVersion, definitelyTypedPath });
if (!changedPackages) {
return undefined;
}
if (changedPackages.some(packageIdsAreEqual(typingsData.id))) {
// Package has changed; run it
return typingsData.id;
}
return undefined;
});
const affectedPackages = getAffectedPackages(allPackages, compact(changedPackages));
const packagesToBenchmark = [...affectedPackages.changedPackages, ...affectedPackages.dependentPackages];
const groups = packagesToBenchmark.reduce((groups: PackageId[][], typingsData, index) => {
const agentIndex = index % agentCount;
if (groups[agentIndex]) {
groups[agentIndex].push(typingsData.id);
} else {
groups[agentIndex] = [typingsData.id];
}
return groups;
}, []);
const benchmarkOptions: Partial<BenchmarkPackageOptions> = {
definitelyTypedPath,
tsVersion,
upload: true
};
await writeFile(
outFile,
JSON.stringify(
{
changedPackageCount: affectedPackages.changedPackages.length,
dependentPackageCount: affectedPackages.dependentPackages.length,
totalPackageCount: packagesToBenchmark.length,
system: currentSystem,
options: benchmarkOptions,
groups
},
undefined,
2
),
"utf8"
);
}

View File

@@ -3,10 +3,7 @@ import path from "path";
import process from "process";
import yargs from "yargs";
import { benchmark } from "./benchmark";
import { getPackagesToBenchmark } from "./getPackagesToBenchmark";
import { compare } from "./compare";
import { compareTypeScriptCLI } from "./compareTypeScript";
import { parsePackageKey } from "../common";
const maxRunSeconds = {
type: "number",
@@ -91,33 +88,6 @@ void yargs
},
benchmark
)
.command(
"getPackagesToBenchmark",
"generates a benchmark manifest file to be run by multiple agents",
{
definitelyTypedPath: {
...definitelyTypedPath,
coerce: (dtPath: string) => (path.isAbsolute(dtPath) ? dtPath : path.resolve(process.cwd(), dtPath))
},
agentCount: {
type: "number",
requiresArg: true,
description: "the number of agents that will run the benchmarks",
demandOption: true
},
tsVersion: {
...tsVersion,
demandOption: true
},
outFile: {
type: "string",
requiresArg: true,
description: "the path to the manifest file to be written",
demandOption: true
}
},
getPackagesToBenchmark
)
.command(
"compare",
"compare packages modified in a PR to those packages in the main branch",
@@ -147,29 +117,6 @@ void yargs
},
compare
)
.command(
"compareTypeScript",
"compare packages performance between different TypeScript versions",
{
file,
compareAgainstVersion: {
type: "string",
requiresArg: true,
description: "the TypeScript major/minor version to compare against",
demandOption: true
},
packages: {
type: ("array" as unknown) as undefined, // yargs seems to have a problem with "array" + `coerce`
description: "list of packages to benchmark",
requiresArg: true,
coerce: (packages: string[]) => packages.map(parsePackageKey)
},
maxRunSeconds,
definitelyTypedPath,
localTypeScriptPath
},
compareTypeScriptCLI
)
.help().argv;
process.on("unhandledRejection", err => {

View File

@@ -4,26 +4,6 @@ export const config = {
benchmarks: {
languageServiceIterations: 5
},
database: {
benchmarksDatabaseId: "benchmarks",
packageBenchmarksContainerId: "packageBenchmarks",
packageBenchmarksDocumentSchemaVersion: 5,
typeScriptComparisonsContainerId: "typeScriptComparisons",
typeScriptComparisonsDocumentSchemaVersion: 1,
endpoint: "https://dt-perf.documents.azure.com:443/",
get writeKey() {
return assertDefined(
process.env.DATABASE_WRITE_KEY,
`Required environment variable 'DATABASE_WRITE_KEY' was not set`
);
},
get readKey() {
return assertDefined(
process.env.DATABASE_READ_KEY,
`Required environment variable 'DATABASE_READ_KEY' was not set`
);
}
},
github: {
userAgent: "definitely-not-slow",
typeScriptBotUsername: "typescript-bot",

View File

@@ -1,49 +0,0 @@
import { CosmosClient, Database, Container } from "@azure/cosmos";
import { config } from "./config";
import { assertNever } from "@definitelytyped/utils";
export const enum DatabaseAccessLevel {
Read = "read",
Write = "write"
}
function getKey(accessLevel: DatabaseAccessLevel) {
switch (accessLevel) {
case DatabaseAccessLevel.Read:
return config.database.readKey;
case DatabaseAccessLevel.Write:
return config.database.writeKey;
default:
assertNever(accessLevel);
}
}
export async function getDatabase(
accessLevel: DatabaseAccessLevel
): Promise<{
database: Database;
packageBenchmarks: Container;
typeScriptComparisons: Container;
}> {
const client = new CosmosClient({
endpoint: config.database.endpoint,
key: getKey(accessLevel)
});
const { database } = await client.databases.createIfNotExists({
id: config.database.benchmarksDatabaseId
});
const { container: packageBenchmarks } = await database.containers.createIfNotExists({
id: config.database.packageBenchmarksContainerId,
partitionKey: {
paths: ["/body/packageName"]
}
});
const { container: typeScriptComparisons } = await database.containers.createIfNotExists({
id: config.database.typeScriptComparisonsContainerId
});
return { database, packageBenchmarks, typeScriptComparisons };
}

View File

@@ -1,6 +1,4 @@
export * from "./config";
export * from "./db";
export * from "./getParsedPackages";
export * from "./types";
export * from "./utils";
export * from "./support";

View File

@@ -1,5 +0,0 @@
import { Document, PackageBenchmarkSummary } from "./types";
export function supportsMemoryUsage(doc: Document<PackageBenchmarkSummary>) {
return doc.version >= 4;
}

View File

@@ -87,35 +87,3 @@ export interface SystemInfo {
hash: string;
nodeVersion: string;
}
export interface Document<T> {
version: number;
createdAt: Date;
system: SystemInfo;
body: T;
}
type Serialized<T extends {}> = {
[K in keyof T]: T[K] extends string
? string
: T[K] extends number
? number
: T[K] extends boolean
? boolean
: T[K] extends Date
? string
: T[K] extends readonly (infer U)[]
? Serialized<U>[]
: T[K] extends {}
? Serialized<T[K]>
: never;
};
export interface JSONDocument<T extends {}> {
version: number;
createdAt: string;
system: SystemInfo;
body: Serialized<T>;
}
export type QueryResult<T extends {}> = T & { id: string };

View File

@@ -3,7 +3,7 @@ import * as fs from "fs";
import { randomBytes, createHash } from "crypto";
import { promisify } from "util";
import { execSync } from "child_process";
import { SystemInfo, Document, JSONDocument, PackageBenchmarkSummary, QueryResult, PackageBenchmark } from "./types";
import { SystemInfo, PackageBenchmarkSummary, PackageBenchmark } from "./types";
import { assertDefined, execAndThrowErrors } from "@definitelytyped/utils";
import {
PackageId,
@@ -104,31 +104,6 @@ export function isWithin(actual: number, expected: number, tolerance: number): b
return Math.abs(getPercentDiff(actual, expected)) <= tolerance;
}
export function systemsAreCloseEnough(a: SystemInfo, b: SystemInfo, cpuSpeedTolerance = 0.1): boolean {
if (a.hash === b.hash) {
return true;
}
return (
a.arch === b.arch &&
a.platform === b.platform &&
a.nodeVersion === b.nodeVersion &&
a.cpus.length === b.cpus.length &&
a.cpus.every((cpu, index) => {
const otherCPU = b.cpus[index];
return cpu.model === otherCPU.model && isWithin(cpu.speed, otherCPU.speed, cpuSpeedTolerance);
})
);
}
export function createDocument<T>(body: T, version: number): Document<T> {
return {
version,
createdAt: new Date(),
system: getSystemInfo(),
body
};
}
export function isVersionedBenchmark(
obj: any
): obj is Pick<PackageBenchmark, "packageVersionMajor" | "packageVersionMinor"> {
@@ -176,20 +151,6 @@ export function toPackageKey(
return `${packageId.name}/${formatDependencyVersion(packageId.version)}`;
}
export function deserializeSummary(
doc: QueryResult<JSONDocument<PackageBenchmarkSummary>>
): QueryResult<Document<PackageBenchmarkSummary>>;
export function deserializeSummary(doc: JSONDocument<PackageBenchmarkSummary>): Document<PackageBenchmarkSummary> {
return {
...doc,
createdAt: new Date(doc.createdAt),
body: {
...doc.body,
batchRunStart: new Date(doc.body.batchRunStart)
}
};
}
export function getSourceVersion(cwd: string) {
return execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
}

View File

@@ -14,9 +14,6 @@ function assertCommentSafe(str: string) {
export interface CommentData {
overallChange?: OverallChange;
benchmarks: {
createdAt: Date;
}[];
}
export function createPerfCommentBody(data: CommentData, body: string): string {

View File

@@ -1,11 +1,11 @@
import table from "markdown-table";
import { PackageBenchmarkSummary, Document, config, getPercentDiff, compact, supportsMemoryUsage } from "../common";
import { PackageBenchmarkSummary, config, getPercentDiff, compact } from "../common";
import { metrics, Metric, FormatOptions, SignificanceLevel } from "../analysis";
import { assertNever } from "@definitelytyped/utils";
export function createComparisonTable(
before: Document<PackageBenchmarkSummary>,
after: Document<PackageBenchmarkSummary>,
before: PackageBenchmarkSummary,
after: PackageBenchmarkSummary,
beforeTitle: string,
afterTitle: string
) {
@@ -13,9 +13,7 @@ export function createComparisonTable(
compact([
["", beforeTitle, afterTitle, "diff"],
["**Batch compilation**"],
supportsMemoryUsage(before) && supportsMemoryUsage(after)
? createComparisonRowFromMetric(metrics.memoryUsage, before, after)
: undefined,
createComparisonRowFromMetric(metrics.memoryUsage, before, after),
createComparisonRowFromMetric(metrics.typeCount, before, after),
createComparisonRowFromMetric(metrics.assignabilityCacheSize, before, after),
[],
@@ -32,10 +30,10 @@ export function createComparisonTable(
after,
x =>
sourceLink(
x.body.completions.worst.identifierText,
x.body.sourceVersion,
x.body.completions.worst.fileName,
x.body.completions.worst.line
x.completions.worst.identifierText,
x.sourceVersion,
x.completions.worst.fileName,
x.completions.worst.line
),
undefined,
{ indent: 1 }
@@ -50,35 +48,19 @@ export function createComparisonTable(
after,
x =>
sourceLink(
x.body.quickInfo.worst.identifierText,
x.body.sourceVersion,
x.body.quickInfo.worst.fileName,
x.body.quickInfo.worst.line
x.quickInfo.worst.identifierText,
x.sourceVersion,
x.quickInfo.worst.fileName,
x.quickInfo.worst.line
),
undefined,
{ indent: 1 }
),
// Only show system info if theyre not identical
...(before.system.hash === after.system.hash
? []
: [
[],
["**System information**"],
createComparisonRow("Node version", before, after, x => x.system.nodeVersion),
createComparisonRow("CPU count", before, after, x => x.system.cpus.length, undefined, { precision: 0 }),
createComparisonRow("CPU speed", before, after, x => `${x.system.cpus[0].speed / 1000} GHz`),
createComparisonRow("CPU model", before, after, x => x.system.cpus[0].model),
createComparisonRow("CPU Architecture", before, after, x => x.system.arch),
createComparisonRow("Memory", before, after, x => `${format(x.system.totalmem / 2 ** 30)} GiB`),
createComparisonRow("Platform", before, after, x => x.system.platform),
createComparisonRow("Release", before, after, x => x.system.release)
])
])
);
}
export function createSingleRunTable(benchmark: Document<PackageBenchmarkSummary>) {
export function createSingleRunTable(benchmark: PackageBenchmarkSummary) {
return table([
["**Batch compilation**"],
// createSingleRunRowFromMetric(metrics.memoryUsage, benchmark),
@@ -97,10 +79,10 @@ export function createSingleRunTable(benchmark: Document<PackageBenchmarkSummary
benchmark,
x =>
sourceLink(
x.body.completions.worst.identifierText,
x.body.sourceVersion,
x.body.completions.worst.fileName,
x.body.completions.worst.line
x.completions.worst.identifierText,
x.sourceVersion,
x.completions.worst.fileName,
x.completions.worst.line
),
{ indent: 1 }
),
@@ -113,23 +95,13 @@ export function createSingleRunTable(benchmark: Document<PackageBenchmarkSummary
benchmark,
x =>
sourceLink(
x.body.quickInfo.worst.identifierText,
x.body.sourceVersion,
x.body.quickInfo.worst.fileName,
x.body.quickInfo.worst.line
x.quickInfo.worst.identifierText,
x.sourceVersion,
x.quickInfo.worst.fileName,
x.quickInfo.worst.line
),
{ indent: 1 }
),
[],
["**System information**"],
createSingleRunRow("Node version", benchmark, x => x.system.nodeVersion),
createSingleRunRow("CPU count", benchmark, x => x.system.cpus.length, { precision: 0 }),
createSingleRunRow("CPU speed", benchmark, x => `${x.system.cpus[0].speed / 1000} GHz`),
createSingleRunRow("CPU model", benchmark, x => x.system.cpus[0].model),
createSingleRunRow("CPU Architecture", benchmark, x => x.system.arch),
createSingleRunRow("Memory", benchmark, x => `${format(x.system.totalmem / 2 ** 30)} GiB`),
createSingleRunRow("Platform", benchmark, x => x.system.platform),
createSingleRunRow("Release", benchmark, x => x.system.release)
]);
}
@@ -141,8 +113,8 @@ function sourceLink(text: string, sourceVersion: string, fileName: string, line:
function createComparisonRowFromMetric(
metric: Metric,
before: Document<PackageBenchmarkSummary>,
after: Document<PackageBenchmarkSummary>,
before: PackageBenchmarkSummary,
after: PackageBenchmarkSummary,
formatOptions: FormatOptions = {}
) {
const beforeValue = metric.getValue(before);
@@ -169,7 +141,7 @@ function createComparisonRowFromMetric(
function createSingleRunRowFromMetric(
metric: Metric,
benchmark: Document<PackageBenchmarkSummary>,
benchmark: PackageBenchmarkSummary,
formatOptions?: FormatOptions
) {
return createSingleRunRow(metric.columnName, benchmark, metric.getValue, {
@@ -180,9 +152,9 @@ function createSingleRunRowFromMetric(
function createComparisonRow(
title: string,
a: Document<PackageBenchmarkSummary>,
b: Document<PackageBenchmarkSummary>,
getValue: (x: Document<PackageBenchmarkSummary>) => number | string | undefined,
a: PackageBenchmarkSummary,
b: PackageBenchmarkSummary,
getValue: (x: PackageBenchmarkSummary) => number | string | undefined,
diff?: string,
formatOptions: FormatOptions = {}
): string[] {
@@ -199,8 +171,8 @@ function createComparisonRow(
function createSingleRunRow(
title: string,
benchmark: Document<PackageBenchmarkSummary>,
getValue: (x: Document<PackageBenchmarkSummary>) => number | string | undefined,
benchmark: PackageBenchmarkSummary,
getValue: (x: PackageBenchmarkSummary) => number | string | undefined,
formatOptions: FormatOptions = {}
): string[] {
const value = getValue(benchmark);

View File

@@ -1,8 +1,6 @@
import { createComparisonTable, createSingleRunTable } from "./createTable";
import {
PackageBenchmarkSummary,
systemsAreCloseEnough,
Document,
compact,
toPackageKey,
packageVersionsAreEqual
@@ -10,7 +8,7 @@ import {
import { getInterestingMetrics, SignificanceLevel, ComparedMetric } from "../analysis";
export function createTablesWithAnalysesMessage(
pairs: [Document<PackageBenchmarkSummary> | undefined, Document<PackageBenchmarkSummary>][],
pairs: [PackageBenchmarkSummary, PackageBenchmarkSummary][],
prNumber: number,
alwaysWriteHeading = false,
alwaysCollapseDetails = false
@@ -24,12 +22,11 @@ export function createTablesWithAnalysesMessage(
? createComparisonTable(before, after, getBeforeTitle(before, after), getAfterTitle(before, after, prNumber))
: createSingleRunTable(after),
``,
before && getSystemMismatchMessage(before, after)
].join("\n");
return compact([
pairs.length > 1 || alwaysWriteHeading
? `### ${after.body.packageName}/v${after.body.packageVersionMajor}.${after.body.packageVersionMinor}`
? `### ${after.packageName}/v${after.packageVersionMajor}.${after.packageVersionMinor}`
: undefined,
getIntroMessage(before, after),
``,
@@ -43,47 +40,47 @@ export function createTablesWithAnalysesMessage(
.join("\n\n");
}
function getDetailsSummaryTitle(comparisonsCount: number, benchmark: Document<PackageBenchmarkSummary>) {
function getDetailsSummaryTitle(comparisonsCount: number, benchmark: PackageBenchmarkSummary) {
let titleStart = "<strong>Comparison details";
if (comparisonsCount > 1) {
titleStart += ` for ${toPackageKey(benchmark.body)}`;
titleStart += ` for ${toPackageKey(benchmark)}`;
}
return titleStart + "</strong> 📊";
}
function getBeforeTitle(before: Document<PackageBenchmarkSummary>, after: Document<PackageBenchmarkSummary>) {
if (packageVersionsAreEqual(before.body, after.body)) {
function getBeforeTitle(before: PackageBenchmarkSummary, after: PackageBenchmarkSummary) {
if (packageVersionsAreEqual(before, after)) {
return "master";
}
return `${before.body.packageVersionMajor}.${before.body.packageVersionMinor}@master`;
return `${before.packageVersionMajor}.${before.packageVersionMinor}@master`;
}
function getAfterTitle(
before: Document<PackageBenchmarkSummary>,
after: Document<PackageBenchmarkSummary>,
before: PackageBenchmarkSummary,
after: PackageBenchmarkSummary,
prNumber: number
) {
if (packageVersionsAreEqual(before.body, after.body)) {
if (packageVersionsAreEqual(before, after)) {
return `#${prNumber}`;
}
return `${after.body.packageVersionMajor}.${after.body.packageVersionMinor} in #${prNumber}`;
return `${after.packageVersionMajor}.${after.packageVersionMinor} in #${prNumber}`;
}
function getIntroMessage(
before: Document<PackageBenchmarkSummary> | undefined,
after: Document<PackageBenchmarkSummary>
before: PackageBenchmarkSummary | undefined,
after: PackageBenchmarkSummary
) {
if (before && packageVersionsAreEqual(before.body, after.body)) {
if (before && packageVersionsAreEqual(before, after)) {
return;
}
if (before) {
return `These typings are for a version of ${before.body.packageName} that doesnt yet exist on master, so Ive compared them with v${before.body.packageVersionMajor}.${before.body.packageVersionMinor}.`;
return `These typings are for a version of ${before.packageName} that doesnt yet exist on master, so Ive compared them with v${before.packageVersionMajor}.${before.packageVersionMinor}.`;
}
return `These typings are for a package that doesnt yet exist on master, so I dont have anything to compare against yet! In the future, Ill be able to compare PRs to ${after.body.packageName} with its source on master.`;
return `These typings are for a package that doesnt yet exist on master, so I dont have anything to compare against yet! In the future, Ill be able to compare PRs to ${after.packageName} with its source on master.`;
}
function getLanguageServiceCrashMessage(benchmark: Document<PackageBenchmarkSummary>) {
if (benchmark.body.languageServiceCrashed) {
function getLanguageServiceCrashMessage(benchmark: PackageBenchmarkSummary) {
if (benchmark.languageServiceCrashed) {
return (
`Before we get into it, I need to mention that **the language service crashed** while taking these measurements. ` +
`This isnt your fault—on the contrary, you helped us find a probably TypeScript bug! But, be aware that these results ` +
@@ -94,12 +91,6 @@ function getLanguageServiceCrashMessage(benchmark: Document<PackageBenchmarkSumm
return;
}
function getSystemMismatchMessage(a: Document<PackageBenchmarkSummary>, b: Document<PackageBenchmarkSummary>) {
return !systemsAreCloseEnough(a.system, b.system)
? `First off, note that the system varied slightly between these two runs, so youll have to take these measurements with a grain of salt.`
: undefined;
}
function getInterestingMetricsMessage(interestingMetrics: readonly ComparedMetric[]) {
if (!interestingMetrics.length) {
return `It looks like nothing changed too much. I wont post performance data again unless it gets worse.`;

View File

@@ -1,11 +1,11 @@
import { PackageBenchmarkSummary, Document, config, compact } from "../common";
import { PackageBenchmarkSummary, config, compact } from "../common";
import { getOctokit } from "./getOctokit";
import { createTablesWithAnalysesMessage } from "./createTablesWithAnalysesMessage";
import { createPerfCommentBody } from "./comment";
import { getOverallChangeForComparisons } from "../analysis";
import { assertDefined } from "@definitelytyped/utils";
type BeforeAndAfter = [Document<PackageBenchmarkSummary> | undefined, Document<PackageBenchmarkSummary>];
type BeforeAndAfter = [PackageBenchmarkSummary, PackageBenchmarkSummary];
export interface PostDependentsComparisonResultOptions {
comparisons: BeforeAndAfter[];
@@ -37,7 +37,6 @@ export async function postDependentsComparisonResult({ comparisons, dryRun }: Po
body: createPerfCommentBody(
{
overallChange: getOverallChangeForComparisons(comparisons),
benchmarks: comparisons.map(([, b]) => ({ createdAt: b.createdAt }))
},
message
)

View File

@@ -1,4 +1,4 @@
import { PackageBenchmarkSummary, Document, config, compact, findLast } from "../common";
import { PackageBenchmarkSummary, config, compact, findLast } from "../common";
import { getOctokit } from "./getOctokit";
import { createTablesWithAnalysesMessage } from "./createTablesWithAnalysesMessage";
import { isPerfComment, createPerfCommentBody, getCommentData, CommentData } from "./comment";
@@ -6,7 +6,7 @@ import { OverallChange, getOverallChangeForComparisons } from "../analysis";
import { setLabels } from "./setLabels";
import { assertDefined } from "@definitelytyped/utils";
type BeforeAndAfter = [Document<PackageBenchmarkSummary> | undefined, Document<PackageBenchmarkSummary>];
type BeforeAndAfter = [PackageBenchmarkSummary, PackageBenchmarkSummary];
export interface PostInitialComparisonResultsOptions {
comparisons: BeforeAndAfter[];
@@ -45,7 +45,6 @@ export async function postInitialComparisonResults({
const mostRecentComment = findLast(comments.data, isPerfComment);
const commentData: CommentData = {
overallChange: currentOverallChange,
benchmarks: comparisons.map(([, b]) => ({ createdAt: b.createdAt }))
};
if (mostRecentComment) {
const lastOverallChange = getCommentData(mostRecentComment)?.overallChange;
@@ -64,7 +63,7 @@ export async function postInitialComparisonResults({
/*alwaysWriteHeader*/ false,
/*alwaysCollapseDetails*/ true
),
comparisons[0][1].body.sourceVersion
comparisons[0][1].sourceVersion
);
await octokit.issues.createComment({

View File

@@ -1,20 +0,0 @@
import { PackageBenchmarkSummary, Document, toPackageKey } from "../common";
import { createComparisonTable } from "./createTable";
type BeforeAndAfter = [Document<PackageBenchmarkSummary>, Document<PackageBenchmarkSummary>];
export interface PostTypeScriptComparisonResultsOptions {
comparisons: BeforeAndAfter[];
dryRun: boolean;
}
export async function postTypeScriptComparisonResults({ comparisons }: PostTypeScriptComparisonResultsOptions) {
return comparisons
.map(([baseline, head]) =>
[
`### ${toPackageKey(baseline.body)}`,
createComparisonTable(baseline, head, baseline.body.typeScriptVersion, "HEAD")
].join("\n")
)
.join("\n\n");
}

View File

@@ -1,38 +0,0 @@
import { Container } from "@azure/cosmos";
import { DirectoryParsedTypingVersion } from "@definitelytyped/definitions-parser";
import { config, PackageBenchmarkSummary, Document, QueryResult } from "../common";
export interface GetLatestBenchmarkOptions {
container: Container;
packageName: string;
packageVersion: DirectoryParsedTypingVersion;
matchMinor: boolean;
typeScriptVersionMajorMinor: string;
}
export async function getLatestBenchmark({
container,
packageName,
packageVersion,
matchMinor,
typeScriptVersionMajorMinor
}: GetLatestBenchmarkOptions): Promise<QueryResult<Document<PackageBenchmarkSummary>> | undefined> {
const response = await container.items
.query<QueryResult<Document<PackageBenchmarkSummary>>>({
query:
`SELECT TOP 1 * FROM ${config.database.packageBenchmarksContainerId} b` +
` WHERE b.body.packageName = @packageName` +
` AND b.body.packageVersionMajor = @packageVersionMajor` +
(matchMinor ? ` AND b.body.packageVersionMinor = @packageVersionMinor` : "") +
` AND b.body.typeScriptVersionMajorMinor = @tsVersion` +
` ORDER BY b.createdAt DESC`,
parameters: [
{ name: "@packageName", value: packageName },
{ name: "@packageVersionMajor", value: packageVersion.major },
{ name: "@packageVersionMinor", value: packageVersion.minor ?? "" },
{ name: "@tsVersion", value: typeScriptVersionMajorMinor }
]
})
.fetchNext();
return response.resources[0];
}

View File

@@ -1,11 +0,0 @@
import { Container, Item } from "@azure/cosmos";
import { PackageBenchmarkSummary, createDocument, TypeScriptComparisonRun } from "../common";
export async function insertDocument(
benchmark: PackageBenchmarkSummary | TypeScriptComparisonRun,
version: number,
container: Container
): Promise<Item> {
const response = await container.items.create(createDocument(benchmark, version));
return response.item;
}

View File

@@ -1,5 +1,5 @@
import { metrics, SignificanceLevel } from "../../src/analysis";
import { Document, PackageBenchmarkSummary, config } from "../../src/common";
import { PackageBenchmarkSummary, config } from "../../src/common";
describe("analysis", () => {
describe("metrics", () => {
@@ -8,8 +8,8 @@ describe("analysis", () => {
6,
1000,
6000,
{ body: { testIdentifierCount: 1000, typeCount: 1000 } } as Document<PackageBenchmarkSummary>,
{ body: { testIdentifierCount: 6000, typeCount: 6000 } } as Document<PackageBenchmarkSummary>
{ testIdentifierCount: 1000, typeCount: 1000 } as PackageBenchmarkSummary,
{ testIdentifierCount: 6000, typeCount: 6000 } as PackageBenchmarkSummary
);
expect(significance1).toBe(undefined);
@@ -18,8 +18,8 @@ describe("analysis", () => {
6,
1000,
6000,
{ body: { testIdentifierCount: 1000, typeCount: 1000 } } as Document<PackageBenchmarkSummary>,
{ body: { testIdentifierCount: 1000, typeCount: 6000 } } as Document<PackageBenchmarkSummary>
{ testIdentifierCount: 1000, typeCount: 1000 } as PackageBenchmarkSummary,
{ testIdentifierCount: 1000, typeCount: 6000 } as PackageBenchmarkSummary
);
expect(significance2).toBe(SignificanceLevel.Warning);
@@ -28,8 +28,8 @@ describe("analysis", () => {
config.comparison.percentDiffWarningThreshold + 0.01,
1000,
200,
{ body: { testIdentifierCount: 1000, typeCount: 1000 } } as Document<PackageBenchmarkSummary>,
{ body: { testIdentifierCount: 5000, typeCount: 2000 } } as Document<PackageBenchmarkSummary>
{ testIdentifierCount: 1000, typeCount: 1000 } as PackageBenchmarkSummary,
{ testIdentifierCount: 5000, typeCount: 2000 } as PackageBenchmarkSummary
);
expect(significance3).toBe(undefined);
@@ -40,8 +40,8 @@ describe("analysis", () => {
6,
100,
600,
{ body: { testIdentifierCount: 100, typeCount: 100 } } as Document<PackageBenchmarkSummary>,
{ body: { testIdentifierCount: 600, typeCount: 600 } } as Document<PackageBenchmarkSummary>
{ testIdentifierCount: 100, typeCount: 100 } as PackageBenchmarkSummary,
{ testIdentifierCount: 600, typeCount: 600 } as PackageBenchmarkSummary
);
expect(significance1).toBe(undefined);

View File

@@ -104,22 +104,6 @@
"@opentelemetry/api" "^1.0.1"
tslib "^2.2.0"
"@azure/cosmos@^3.6.3":
version "3.6.3"
resolved "https://registry.yarnpkg.com/@azure/cosmos/-/cosmos-3.6.3.tgz#bb53bde35fbf338160691d2b6a62f47b4a9a1cbb"
integrity sha512-JoCDxl0TnL6EHL4xD3KC9r2bMivK13q1jl7h69wd/YFLlt3aBTTCehtAX+y4alNSENpL53XdRdw/cna0mI2XDw==
dependencies:
"@types/debug" "^4.1.4"
debug "^4.1.1"
fast-json-stable-stringify "^2.0.0"
node-abort-controller "^1.0.4"
node-fetch "^2.6.0"
os-name "^3.1.0"
priorityqueuejs "^1.0.0"
semaphore "^1.0.5"
tslib "^1.10.0"
uuid "^3.3.2"
"@azure/functions@^1.2.3":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@azure/functions/-/functions-1.2.3.tgz#65765837e7319eedffbf8a971cb2f78d4e043d54"
@@ -1773,11 +1757,6 @@
resolved "https://registry.yarnpkg.com/@types/command-exists/-/command-exists-1.2.0.tgz#d97e0ed10097090e4ab0367ed425b0312fad86f3"
integrity sha512-ugsxEJfsCuqMLSuCD4PIJkp5Uk2z6TCMRCgYVuhRo5cYQY3+1xXTQkSlPtkpGHuvWMjS2KTeVQXxkXRACMbM6A==
"@types/debug@^4.1.4":
version "4.1.5"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd"
integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==
"@types/fs-extra@^5.0.2":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.1.0.tgz#2a325ef97901504a3828718c390d34b8426a10a1"
@@ -6367,11 +6346,6 @@ node-abi@^2.21.0:
dependencies:
semver "^5.4.1"
node-abort-controller@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-1.0.4.tgz#4095e41d58b2fae169d2f9892904d603e11c7a39"
integrity sha512-7cNtLKTAg0LrW3ViS2C7UfIzbL3rZd8L0++5MidbKqQVJ8yrH6+1VRSHl33P0ZjBTbOJd37d9EYekvHyKkB0QQ==
node-addon-api@^3.0.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161"
@@ -7120,11 +7094,6 @@ pretty-format@^25.2.1, pretty-format@^25.5.0:
ansi-styles "^4.0.0"
react-is "^16.12.0"
priorityqueuejs@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/priorityqueuejs/-/priorityqueuejs-1.0.0.tgz#2ee4f23c2560913e08c07ce5ccdd6de3df2c5af8"
integrity sha1-LuTyPCVgkT4IwHzlzN1t498sWvg=
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
@@ -7622,11 +7591,6 @@ saxes@^3.1.9:
dependencies:
xmlchars "^2.1.1"
semaphore@^1.0.5:
version "1.1.0"
resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa"
integrity sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA==
"semver@2 >=2.2.1 || 3.x || 4 || 5 || 7", semver@^7.1.1, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5:
version "7.3.5"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"