diff options
author | Jeremy Rifkin <51220084+jeremy-rifkin@users.noreply.github.com> | 2023-06-11 19:10:30 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-11 19:10:30 -0400 |
commit | 60ce06b02f8ece8bbbecb26cb69f9ad45e75aa16 (patch) | |
tree | a10d1bd160dd06f5b191adb1ad5cd12403790d48 /lib | |
parent | 910d69f233414ebfb0b680e012f44ced14505016 (diff) | |
download | compiler-explorer-gh-7689.tar.gz compiler-explorer-gh-7689.zip |
Improve cache handling on the frontend, cache executions on the backend, and improve controls on the exec pane (#5111)gh-7689
Diffstat (limited to 'lib')
-rw-r--r-- | lib/base-compiler.ts | 69 | ||||
-rw-r--r-- | lib/compilers/java.ts | 3 | ||||
-rw-r--r-- | lib/compilers/kotlin.ts | 3 | ||||
-rw-r--r-- | lib/compilers/win32-mingw-clang.ts | 11 | ||||
-rw-r--r-- | lib/compilers/win32-mingw-gcc.ts | 11 | ||||
-rw-r--r-- | lib/handlers/compile.interfaces.ts | 6 | ||||
-rw-r--r-- | lib/handlers/compile.ts | 25 | ||||
-rw-r--r-- | lib/llvm-ir.ts | 4 |
8 files changed, 94 insertions, 38 deletions
diff --git a/lib/base-compiler.ts b/lib/base-compiler.ts index d72adeda6..77aff9750 100644 --- a/lib/base-compiler.ts +++ b/lib/base-compiler.ts @@ -29,15 +29,18 @@ import * as PromClient from 'prom-client'; import temp from 'temp'; import _ from 'underscore'; -import type { +import { BufferOkFunc, BuildResult, BuildStep, + BypassCache, CompilationCacheKey, CompilationInfo, CompilationResult, CustomInputForTool, ExecutionOptions, + bypassCompilationCache, + bypassExecutionCache, } from '../types/compilation/compilation.interfaces.js'; import type { LLVMOptPipelineBackendOptions, @@ -489,7 +492,7 @@ export class BaseCompiler implements ICompiler { maxSize: number, intelAsm, demangle, - staticReloc: boolean, + staticReloc: boolean | undefined, dynamicReloc: boolean, filters: ParseFiltersAndOutputOptions, ) { @@ -1718,11 +1721,13 @@ export class BaseCompiler implements ICompiler { }; } - async getOrBuildExecutable(key) { + async getOrBuildExecutable(key, bypassCache: BypassCache) { const dirPath = await this.newTempDir(); - const buildResults = await this.loadPackageWithExecutable(key, dirPath); - if (buildResults) return buildResults; + if (!bypassCompilationCache(bypassCache)) { + const buildResults = await this.loadPackageWithExecutable(key, dirPath); + if (buildResults) return buildResults; + } let compilationResult; try { @@ -1843,9 +1848,11 @@ export class BaseCompiler implements ICompiler { }; } - async handleExecution(key, executeParameters): Promise<CompilationResult> { - if (this.compiler.interpreted) return this.handleInterpreting(key, executeParameters); - const buildResult = await this.getOrBuildExecutable(key); + async doExecution(key, executeParameters, bypassCache: BypassCache): Promise<CompilationResult> { + if (this.compiler.interpreted) { + return this.handleInterpreting(key, executeParameters); + } + const buildResult = await this.getOrBuildExecutable(key, bypassCache); if (buildResult.code !== 0) { return { code: -1, @@ -1892,6 +1899,23 @@ export class BaseCompiler implements ICompiler { }; } + async handleExecution(key, executeParameters, bypassCache: BypassCache): Promise<CompilationResult> { + // stringify now so shallow copying isn't a problem, I think the executeParameters get modified + const execKey = JSON.stringify({key, executeParameters}); + if (!bypassExecutionCache(bypassCache)) { + const cacheResult = await this.env.cacheGet(execKey as any); + if (cacheResult) { + return cacheResult; + } + } + + const result = await this.doExecution(key, executeParameters, bypassCache); + if (!bypassExecutionCache(bypassCache)) { + await this.env.cachePut(execKey, result, undefined); + } + return result; + } + getCacheKey(source, options, backendOptions, filters, tools, libraries, files) { return {compiler: this.compiler, source, options, backendOptions, filters, tools, libraries, files}; } @@ -2262,7 +2286,7 @@ export class BaseCompiler implements ICompiler { } } - async cmake(files, key) { + async cmake(files, key, bypassCache: BypassCache) { // key = {source, options, backendOptions, filters, bypassCache, tools, executionParameters, libraries}; if (!this.compiler.supportsBinary) { @@ -2300,7 +2324,9 @@ export class BaseCompiler implements ICompiler { const outputFilename = this.getExecutableFilename(path.join(dirPath, 'build'), this.outputFilebase, key); - let fullResult = await this.loadPackageWithExecutable(cacheKey, dirPath); + let fullResult = !bypassExecutionCache(bypassCache) + ? await this.loadPackageWithExecutable(cacheKey, dirPath) + : null; if (fullResult) { fullResult.fetchedFromCache = true; @@ -2421,6 +2447,7 @@ export class BaseCompiler implements ICompiler { cacheKey.filters, libsAndOptions.options, optOutput, + bypassCache, path.join(dirPath, 'build'), ); @@ -2469,7 +2496,17 @@ export class BaseCompiler implements ICompiler { } } - async compile(source, options, backendOptions, filters, bypassCache, tools, executionParameters, libraries, files) { + async compile( + source, + options, + backendOptions, + filters, + bypassCache: BypassCache, + tools, + executionParameters, + libraries, + files, + ) { const optionsError = this.checkOptions(options); if (optionsError) throw optionsError; const sourceError = this.checkSource(source); @@ -2494,7 +2531,7 @@ export class BaseCompiler implements ICompiler { filters = Object.assign({}, filters); filters.execute = false; - if (!bypassCache) { + if (!bypassCompilationCache(bypassCache)) { const cacheRetreiveTimeStart = process.hrtime.bigint(); // TODO: We should be able to eliminate this any cast. `key` should be cacheable (if it's not that's a big // problem) Because key coantains a CompilerInfo which contains a function member it can't be assigned to a @@ -2512,7 +2549,7 @@ export class BaseCompiler implements ICompiler { result.execResult = await this.env.enqueue(async () => { const start = performance.now(); executionQueueTimeHistogram.observe((start - queueTime) / 1000); - const res = await this.handleExecution(key, executeParameters); + const res = await this.handleExecution(key, executeParameters, bypassCache); executionTimeHistogram.observe((performance.now() - start) / 1000); return res; }); @@ -2532,7 +2569,7 @@ export class BaseCompiler implements ICompiler { source = this.preProcess(source, filters); if (backendOptions.executorRequest) { - const execResult = await this.handleExecution(key, executeParameters); + const execResult = await this.handleExecution(key, executeParameters, bypassCache); if (execResult && execResult.buildResult) { this.doTempfolderCleanup(execResult.buildResult); } @@ -2570,6 +2607,7 @@ export class BaseCompiler implements ICompiler { filters, options, optOutput, + bypassCache, ); })(); compilationTimeHistogram.observe((performance.now() - start) / 1000); @@ -2587,10 +2625,11 @@ export class BaseCompiler implements ICompiler { filters, options, optOutput, + bypassCache: BypassCache, customBuildPath?, ) { // Start the execution as soon as we can, but only await it at the end. - const execPromise = doExecute ? this.handleExecution(key, executeParameters) : null; + const execPromise = doExecute ? this.handleExecution(key, executeParameters, bypassCache) : null; if (result.hasOptOutput) { delete result.optPath; diff --git a/lib/compilers/java.ts b/lib/compilers/java.ts index 320469f6e..c01940c57 100644 --- a/lib/compilers/java.ts +++ b/lib/compilers/java.ts @@ -35,6 +35,7 @@ import {logger} from '../logger.js'; import * as utils from '../utils.js'; import {JavaParser} from './argument-parsers.js'; +import {BypassCache} from '../../types/compilation/compilation.interfaces.js'; export class JavaCompiler extends BaseCompiler { static get key() { @@ -128,7 +129,7 @@ export class JavaCompiler extends BaseCompiler { } override async handleInterpreting(key, executeParameters) { - const compileResult = await this.getOrBuildExecutable(key); + const compileResult = await this.getOrBuildExecutable(key, BypassCache.None); if (compileResult.code === 0) { executeParameters.args = [ '-Xss136K', // Reduce thread stack size diff --git a/lib/compilers/kotlin.ts b/lib/compilers/kotlin.ts index 0b5cce585..9b1bab103 100644 --- a/lib/compilers/kotlin.ts +++ b/lib/compilers/kotlin.ts @@ -22,6 +22,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +import {BypassCache} from '../../types/compilation/compilation.interfaces.js'; import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js'; import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js'; @@ -98,7 +99,7 @@ export class KotlinCompiler extends JavaCompiler { ...key, options: ['-include-runtime', '-d', 'example.jar'], }; - const compileResult = await this.getOrBuildExecutable(alteredKey); + const compileResult = await this.getOrBuildExecutable(alteredKey, BypassCache.None); executeParameters.args = [ '-Xss136K', // Reduce thread stack size '-XX:CICompilerCount=2', // Reduce JIT compilation threads. 2 is minimum diff --git a/lib/compilers/win32-mingw-clang.ts b/lib/compilers/win32-mingw-clang.ts index 83c98c52e..47a6159a8 100644 --- a/lib/compilers/win32-mingw-clang.ts +++ b/lib/compilers/win32-mingw-clang.ts @@ -24,7 +24,12 @@ import path from 'path'; -import {BuildResult, CompilationResult, ExecutionOptions} from '../../types/compilation/compilation.interfaces.js'; +import { + BuildResult, + BypassCache, + CompilationResult, + ExecutionOptions, +} from '../../types/compilation/compilation.interfaces.js'; import {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js'; import {copyNeededDlls} from '../win-utils.js'; @@ -102,8 +107,8 @@ export class Win32MingWClang extends ClangCompiler { return result; } - override async handleExecution(key, executeParameters): Promise<CompilationResult> { + override async handleExecution(key, executeParameters, bypassCache: BypassCache): Promise<CompilationResult> { const execOptions = this.getDefaultExecOptions(); - return super.handleExecution(key, {...executeParameters, env: execOptions.env}); + return super.handleExecution(key, {...executeParameters, env: execOptions.env}, bypassCache); } } diff --git a/lib/compilers/win32-mingw-gcc.ts b/lib/compilers/win32-mingw-gcc.ts index 4e3106bc5..04b43f985 100644 --- a/lib/compilers/win32-mingw-gcc.ts +++ b/lib/compilers/win32-mingw-gcc.ts @@ -24,7 +24,12 @@ import path from 'path'; -import {BuildResult, CompilationResult, ExecutionOptions} from '../../types/compilation/compilation.interfaces.js'; +import { + BuildResult, + BypassCache, + CompilationResult, + ExecutionOptions, +} from '../../types/compilation/compilation.interfaces.js'; import {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js'; import {copyNeededDlls} from '../win-utils.js'; @@ -102,8 +107,8 @@ export class Win32MingWGcc extends GCCCompiler { return result; } - override async handleExecution(key, executeParameters): Promise<CompilationResult> { + override async handleExecution(key, executeParameters, bypassCache: BypassCache): Promise<CompilationResult> { const execOptions = this.getDefaultExecOptions(); - return super.handleExecution(key, {...executeParameters, env: execOptions.env}); + return super.handleExecution(key, {...executeParameters, env: execOptions.env}, bypassCache); } } diff --git a/lib/handlers/compile.interfaces.ts b/lib/handlers/compile.interfaces.ts index 104450b44..af4204066 100644 --- a/lib/handlers/compile.interfaces.ts +++ b/lib/handlers/compile.interfaces.ts @@ -22,6 +22,8 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +import {BypassCache} from '../../types/compilation/compilation.interfaces.js'; + // IF YOU MODIFY ANYTHING HERE PLEASE UPDATE THE DOCUMENTATION! // This type models a request so all fields must be optional strings. @@ -52,12 +54,12 @@ export type CompilationRequestArgs = { export type CompileRequestJsonBody = { options: CompilationRequestArgs; source: string; - bypassCache: boolean; + bypassCache: BypassCache; }; export type CompileRequestTextBody = { source: string; - bypassCache: boolean; + bypassCache: BypassCache; options: any; userArguments: string; executeParametersArgs: any; diff --git a/lib/handlers/compile.ts b/lib/handlers/compile.ts index ac19c7972..6ec2782f6 100644 --- a/lib/handlers/compile.ts +++ b/lib/handlers/compile.ts @@ -50,6 +50,7 @@ import { } from './compile.interfaces.js'; import {remove} from '../common-utils.js'; import {CompilerOverrideOptions} from '../../types/compilation/compiler-overrides.interfaces.js'; +import {BypassCache, CompileChildLibraries, ExecutionParams} from '../../types/compilation/compilation.interfaces.js'; import {SentryCapture} from '../sentry.js'; temp.track(); @@ -82,20 +83,15 @@ function initialise(compilerEnv: CompilationEnvironment) { }, tempDirCleanupSecs * 1000); } -export type ExecutionParams = { - args: string[]; - stdin: string; -}; - type ParsedRequest = { source: string; options: string[]; backendOptions: Record<string, any>; filters: ParseFiltersAndOutputOptions; - bypassCache: boolean; + bypassCache: BypassCache; tools: any; executionParameters: ExecutionParams; - libraries: any[]; + libraries: CompileChildLibraries[]; }; export class CompileHandler { @@ -353,7 +349,7 @@ export class CompileHandler { options: string, backendOptions: Record<string, any> = {}, filters: ParseFiltersAndOutputOptions, - bypassCache = false, + bypassCache = BypassCache.None, tools; const execReqParams: ExecutionRequestParams = {}; let libraries: any[] = []; @@ -363,7 +359,7 @@ export class CompileHandler { const jsonRequest = this.checkRequestRequirements(req); const requestOptions = jsonRequest.options; source = jsonRequest.source; - if (jsonRequest.bypassCache) bypassCache = true; + if (jsonRequest.bypassCache) bypassCache = jsonRequest.bypassCache; options = requestOptions.userArguments; const execParams = requestOptions.executeParameters || {}; execReqParams.args = execParams.args; @@ -375,7 +371,7 @@ export class CompileHandler { } else if (req.body && req.body.compiler) { const textRequest = req.body as CompileRequestTextBody; source = textRequest.source; - if (textRequest.bypassCache) bypassCache = true; + if (textRequest.bypassCache) bypassCache = textRequest.bypassCache; options = textRequest.userArguments; execReqParams.args = textRequest.executeParametersArgs; execReqParams.stdin = textRequest.executeParametersStdin; @@ -423,6 +419,11 @@ export class CompileHandler { for (const tool of tools) { tool.args = utils.splitArguments(tool.args); } + + // Backwards compatibility: bypassCache used to be a boolean. + // Convert a boolean input to an enum's underlying numeric value + bypassCache = 1 * bypassCache; + return { source, options: utils.splitArguments(options), @@ -497,7 +498,9 @@ export class CompileHandler { this.cmakeCounter.inc({language: compiler.lang.id}); const options = this.parseRequest(req, compiler); compiler - .cmake(req.body.files, options) + // Backwards compatibility: bypassCache used to be a boolean. + // Convert a boolean input to an enum's underlying numeric value + .cmake(req.body.files, options, req.body.bypassCache * 1) .then(result => { if (result.didExecute || (result.execResult && result.execResult.didExecute)) this.cmakeExecuteCounter.inc({language: compiler.lang.id}); diff --git a/lib/llvm-ir.ts b/lib/llvm-ir.ts index 5bdf7e651..4ddf9e58f 100644 --- a/lib/llvm-ir.ts +++ b/lib/llvm-ir.ts @@ -249,9 +249,9 @@ export class LlvmIrParser { if (_.isString(ir)) { return await this.processIr(ir, { filterDebugInfo: !!filters.debugCalls, - filterIRMetadata: filters.directives, + filterIRMetadata: !!filters.directives, filterAttributes: false, - demangle: filters.demangle, + demangle: !!filters.demangle, // discard value names is handled earlier }); } |