From 4ed80b62df9531db3863854c702809eb3b0e7bb7 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 16 Oct 2019 11:24:24 -0700 Subject: [PATCH] Stop pre-emptively creating directories Checking for directory existence is expensive and frequently indicates success. Instead of pre-emptively creating the directory containing a file to be written, attempt to create the file and only do the directory scaffolding if the write fails. Appears to reduce file write time by 10-20% for a file-I/O heavy partner build. Thanks to @rbuckton for the suggestion! --- src/compiler/program.ts | 22 +++++++++++++++++----- src/compiler/sys.ts | 17 +++++++++++++---- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 0c8444daa2f..b9495c787ca 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -151,13 +151,16 @@ namespace ts { function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) { try { performance.mark("beforeIOWrite"); - ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName))); - if (isWatchSet(options) && system.createHash && system.getModifiedTime) { - writeFileIfUpdated(fileName, data, writeByteOrderMark); + // PERF: Checking for directory existence is expensive. + // Instead, assume the directory exists and fall back + // to creating it if the file write fails. + try { + writeFileWorker(fileName, data, writeByteOrderMark); } - else { - system.writeFile(fileName, data, writeByteOrderMark); + catch (_) { + ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName))); + writeFileWorker(fileName, data, writeByteOrderMark); } performance.mark("afterIOWrite"); @@ -170,6 +173,15 @@ namespace ts { } } + function writeFileWorker(fileName: string, data: string, writeByteOrderMark: boolean) { + if (isWatchSet(options) && system.createHash && system.getModifiedTime) { + writeFileIfUpdated(fileName, data, writeByteOrderMark); + } + else { + system.writeFile(fileName, data, writeByteOrderMark); + } + } + function getDefaultLibLocation(): string { return getDirectoryPath(normalizePath(system.getExecutingFilePath())); } diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index ad866cba130..c85bb48bb9e 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -541,11 +541,20 @@ namespace ts { // patch writefile to create folder before writing the file const originalWriteFile = sys.writeFile; sys.writeFile = (path, data, writeBom) => { - const directoryPath = getDirectoryPath(normalizeSlashes(path)); - if (directoryPath && !sys.directoryExists(directoryPath)) { - recursiveCreateDirectory(directoryPath, sys); + // PERF: Checking for directory existence is expensive. + // Instead, assume the directory exists and fall back + // to creating it if the file write fails. + try { + originalWriteFile.call(sys, path, data, writeBom); + } + catch (_) { + const directoryPath = getDirectoryPath(normalizeSlashes(path)); + if (directoryPath && !sys.directoryExists(directoryPath)) { + recursiveCreateDirectory(directoryPath, sys); + } + + originalWriteFile.call(sys, path, data, writeBom); } - originalWriteFile.call(sys, path, data, writeBom); }; }