Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(compile): code cache #26528

Merged
merged 25 commits into from
Nov 18, 2024
Merged

Conversation

dsherret
Copy link
Member

@dsherret dsherret commented Oct 24, 2024

Adds a lazily created code cache to deno compile by default.

The code cache is created on first run to a single file in the temp directory and is only written once. After it's been written, the code cache becomes read only on subsequent runs. Only the modules loaded during startup are cached (dynamic imports are not code cached).

The code cache can be disabled by compiling with --no-code-cache.

> hyperfine --warmup 2 scratch.exe scratch_new.exe
Benchmark 1: scratch.exe
  Time (mean ± σ):     282.9 ms ±   6.5 ms    [User: 78.1 ms, System: 15.6 ms]
  Range (min … max):   276.5 ms … 295.2 ms    10 runs

Benchmark 2: scratch_new.exe
  Time (mean ± σ):     129.7 ms ±   6.8 ms    [User: 17.1 ms, System: 9.7 ms]
  Range (min … max):   120.9 ms … 138.4 ms    21 runs

Summary
  scratch_new.exe ran
    2.18 ± 0.13 times faster than scratch.exe

Closes #26502

@dsherret dsherret added this to the 2.1.0 milestone Oct 24, 2024
@felipecrs
Copy link

This is very promising. Have you thought of including the initial code cache inside the compiled executable as well?

@dsherret
Copy link
Member Author

dsherret commented Nov 4, 2024

Yeah, maybe at a later time and as a separate option. The problem is it will make the binary much larger.

@felipecrs
Copy link

felipecrs commented Nov 4, 2024

It all depends on the use case. For some use cases, improving the startup time on the second attempt onwards as opposed to in the first attempt in favor of a reduced binary size will make a lot of sense.

For other cases, it will not make any sense at all. For example: containers. There's only one startup attempt in that case.

Copy link
Member

@bartlomieju bartlomieju left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@@ -337,6 +380,23 @@ impl ModuleLoader for EmbeddedModuleLoader {
))),
}
}

fn code_cache_ready(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated to this PR, we should make this method be able to return sync or async response to save some ticks maybe.

@dsherret dsherret enabled auto-merge (squash) November 18, 2024 20:03
@dsherret dsherret merged commit dd4570e into denoland:main Nov 18, 2024
17 checks passed
@dsherret dsherret deleted the perf_compile_code_cache branch November 18, 2024 20:31
@felipecrs
Copy link

@dsherret, how do I verify code cache is actually working on Deno 2.1.0?

@felipecrs
Copy link

felipecrs commented Nov 21, 2024

I ran a benchmark and the improvements I found are very subtle, I wonder if code cache is indeed working:

$ hyperfine --warmup 2 --shell none --runs 50 './pkgx-deno-2.0.6 [email protected] --version' './pkgx-deno-2.1.0 [email protected] --version'
Benchmark 1: ./pkgx-deno-2.0.6 [email protected] --version
  Time (mean ± σ):     560.8 ms ±  17.2 ms    [User: 580.2 ms, System: 216.7 ms]
  Range (min … max):   534.8 ms … 615.1 ms    50 runs
 
Benchmark 2: ./pkgx-deno-2.1.0 [email protected] --version
  Time (mean ± σ):     523.0 ms ±   8.3 ms    [User: 549.1 ms, System: 224.0 ms]
  Range (min … max):   508.6 ms … 549.8 ms    50 runs
 
Summary
  ./pkgx-deno-2.1.0 [email protected] --version ran
    1.07 ± 0.04 times faster than ./pkgx-deno-2.0.6 [email protected] --version

@bartlomieju
Copy link
Member

@felipecrs if you compile with --log-level debug you should be able to see logs like Loaded N code cache entries

@felipecrs
Copy link

felipecrs commented Nov 21, 2024

Thank you, I guess there's something wrong then:

./pkgx --version 2>&1 | grep cache
DEBUG RS - denort::cache::cache_db:170 - Opening cache /home/felipecrs/.cache/deno/node_analysis_cache_v2...
DEBUG RS - denort::standalone::code_cache:56 - Failed to deserialize code cache: Cache key mismatch./pkgx --version 2>&1 | grep cache
DEBUG RS - denort::cache::cache_db:170 - Opening cache /home/felipecrs/.cache/deno/node_analysis_cache_v2...
DEBUG RS - denort::standalone::code_cache:56 - Failed to deserialize code cache: Cache key mismatchdeno clean
Removed /home/felipecrs/.cache/deno (7865 files, 58.14MB)./pkgx --version 2>&1 | grep cache
DEBUG RS - denort::cache::cache_db:170 - Opening cache /home/felipecrs/.cache/deno/node_analysis_cache_v2...
DEBUG RS - denort::standalone::code_cache:56 - Failed to deserialize code cache: Cache key mismatch
DEBUG RS - denort::cache::cache_db:389 - Created parent directory for cache db../pkgx --version 2>&1 | grep cache
DEBUG RS - denort::cache::cache_db:170 - Opening cache /home/felipecrs/.cache/deno/node_analysis_cache_v2...
DEBUG RS - denort::standalone::code_cache:56 - Failed to deserialize code cache: Cache key mismatch

Any ideas?

@dsherret
Copy link
Member Author

@felipecrs can you open an issue with a reproduction?

@felipecrs
Copy link

@felipecrs
Copy link

felipecrs commented Nov 21, 2024

Ok, I just benchmarked against --no-code-cache:

deno compile --lock=deno.lock --allow-all --output "$INIT_CWD/pkgx" ./entrypoint.ts
Check file:///home/felipecrs/repos/pkgx/entrypoint.ts
Compile file:///home/felipecrs/repos/pkgx/entrypoint.ts to /home/felipecrs/repos/pkgx/pkgxmv pkgx pkgx-ccdeno compile --lock=deno.lock --allow-all --output "$INIT_CWD/pkgx" --no-code-cache ./entrypoint.ts
Compile file:///home/felipecrs/repos/pkgx/entrypoint.ts to /home/felipecrs/repos/pkgx/pkgxmv pkgx pkgx-no-cchyperfine --warmup 2 --shell none --runs 50 './pkgx-no-cc [email protected] --version' './pkgx-cc [email protected] --version'
Benchmark 1: ./pkgx-no-cc [email protected] --version
  Time (mean ± σ):     550.1 ms ±  18.8 ms    [User: 575.0 ms, System: 219.5 ms]
  Range (min … max):   525.6 ms … 606.3 ms    50 runs
 
Benchmark 2: ./pkgx-cc [email protected] --version
  Time (mean ± σ):     532.3 ms ±  16.5 ms    [User: 560.5 ms, System: 212.0 ms]
  Range (min … max):   515.2 ms … 572.9 ms    50 runs
 
Summary
  ./pkgx-cc [email protected] --version ran
    1.03 ± 0.05 times faster than ./pkgx-no-cc [email protected] --version

And indeed, we have an improvement. It is not fair to say the improvement is subtle, because it depends entirely on the application being tested and how long it takes to start.

Thank you very much, this is a really nice addition to Deno.

@dsherret
Copy link
Member Author

dsherret commented Nov 21, 2024

The performance improvement will be most noticable when there's files that are quite large. For a bunch of smallish files it won't be that much (in the example above I'm importing a large bundled file)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use code cache in deno compile
3 participants