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

Implement a more responsive compilation thread in the the language server. #5429

Merged
merged 42 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
86b8cbb
add Arcs around QE types
JoshuaBatty Dec 13, 2023
6c0668a
clone engines
JoshuaBatty Dec 13, 2023
e9a33c4
pass a cloned engines into the compiler from the server
JoshuaBatty Dec 13, 2023
cf200c3
add cancel compilation atomic
JoshuaBatty Dec 13, 2023
e30e5f8
use crossbeam channel with only the most recent didChange event
JoshuaBatty Dec 14, 2023
7c13863
only publish diagnostics on open and save events
JoshuaBatty Dec 14, 2023
38bedd8
eow wip
JoshuaBatty Dec 15, 2023
d71744f
return from check with an error if compilation was cancelled
JoshuaBatty Dec 20, 2023
9cc3916
remove Arc from QE as it was causing sync issues
JoshuaBatty Dec 20, 2023
b5cceee
bump tower lsp version
JoshuaBatty Dec 20, 2023
02230a5
shutdown compilation thread on exit
JoshuaBatty Dec 20, 2023
5af9985
support partial semantic token responses
JoshuaBatty Dec 21, 2023
b3be954
synchronise atomic events
JoshuaBatty Dec 21, 2023
b9de23d
mahe shutdown server async
JoshuaBatty Dec 21, 2023
cac6a63
compilation checks
JoshuaBatty Dec 21, 2023
48b15eb
fix compilation benchmarks
JoshuaBatty Dec 21, 2023
658095b
fix tests
JoshuaBatty Dec 21, 2023
57edd74
remove old code
JoshuaBatty Dec 21, 2023
a090eec
re-enable gc
JoshuaBatty Dec 21, 2023
47cdc5c
re-enable on enter
JoshuaBatty Dec 22, 2023
6e797c0
using local version of std for benchmark example
JoshuaBatty Jan 3, 2024
1b71afc
rebase master
JoshuaBatty Jan 4, 2024
da82c91
renable gc
JoshuaBatty Jan 4, 2024
29591c5
rebase esdrubal/concurrent_slab_map
JoshuaBatty Jan 4, 2024
4863bbf
rebase and fmt
JoshuaBatty Jan 4, 2024
d7ea66d
better names and doc comments
JoshuaBatty Jan 4, 2024
6b8c46e
add Cargo.lock
JoshuaBatty Jan 4, 2024
f22e5e5
clippy and rebase
JoshuaBatty Jan 4, 2024
093adeb
tidy up check should abort
JoshuaBatty Jan 5, 2024
9b68c99
timings wip
JoshuaBatty Jan 5, 2024
43252bd
about to remove printlns
JoshuaBatty Jan 5, 2024
b0a91be
final clean up
JoshuaBatty Jan 5, 2024
d14665d
wait for parsing to finish in didChange test
JoshuaBatty Jan 5, 2024
c5c45fe
Grammar
JoshuaBatty Jan 7, 2024
95022ee
feedback
JoshuaBatty Jan 7, 2024
1c9fed4
Cargo.lock
JoshuaBatty Jan 7, 2024
61e6525
mem swap the compiled programs from ParseResult
JoshuaBatty Jan 8, 2024
643697f
update benchmark code
JoshuaBatty Jan 8, 2024
fcd0b37
remove unnecessary continue statement
JoshuaBatty Jan 8, 2024
2cf3c5d
clippy
JoshuaBatty Jan 8, 2024
f6d411f
Merge branch 'master' into josh/compiler_thread
JoshuaBatty Jan 8, 2024
50c93e0
Merge branch 'master' into josh/compiler_thread
JoshuaBatty Jan 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion forc-pkg/src/pkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use std::{
io::Write,
path::{Path, PathBuf},
str::FromStr,
sync::Arc,
sync::{atomic::AtomicBool, Arc},
};
pub use sway_core::Programs;
use sway_core::{
Expand Down Expand Up @@ -1776,6 +1776,7 @@ pub fn compile(
namespace,
Some(&sway_build_config),
&pkg.name,
None,
),
Some(sway_build_config.clone()),
metrics
Expand Down Expand Up @@ -2581,6 +2582,7 @@ pub fn check(
terse_mode: bool,
include_tests: bool,
engines: &Engines,
retrigger_compilation: Option<Arc<AtomicBool>>,
) -> anyhow::Result<Vec<(Option<Programs>, Handler)>> {
let mut lib_namespace_map = Default::default();
let mut source_map = SourceMap::new();
Expand Down Expand Up @@ -2636,8 +2638,17 @@ pub fn check(
dep_namespace,
Some(&build_config),
&pkg.name,
retrigger_compilation.clone(),
);

if retrigger_compilation
.as_ref()
.map(|b| b.load(std::sync::atomic::Ordering::SeqCst))
.unwrap_or(false)
{
bail!("compilation was retriggered")
}

let programs = match programs_res.as_ref() {
Ok(programs) => programs,
_ => {
Expand Down
1 change: 1 addition & 0 deletions forc-plugins/forc-doc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ pub fn compile_html(
build_instructions.silent,
tests_enabled,
&engines,
None,
)?;

let raw_docs = if !build_instructions.no_deps {
Expand Down
9 changes: 8 additions & 1 deletion forc/src/ops/forc_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,14 @@ pub fn check(command: CheckCommand, engines: &Engines) -> Result<(Option<ty::TyP
)?;
let tests_enabled = !disable_tests;

let mut v = pkg::check(&plan, build_target, terse_mode, tests_enabled, engines)?;
let mut v = pkg::check(
&plan,
build_target,
terse_mode,
tests_enabled,
engines,
None,
)?;
let (res, handler) = v
.pop()
.expect("there is guaranteed to be at least one elem in the vector");
Expand Down
19 changes: 19 additions & 0 deletions sway-core/src/decl_engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,25 @@ pub struct DeclEngine {
parents: RwLock<HashMap<AssociatedItemDeclId, Vec<AssociatedItemDeclId>>>,
}

impl Clone for DeclEngine {
fn clone(&self) -> Self {
DeclEngine {
function_slab: self.function_slab.clone(),
trait_slab: self.trait_slab.clone(),
trait_fn_slab: self.trait_fn_slab.clone(),
trait_type_slab: self.trait_type_slab.clone(),
impl_trait_slab: self.impl_trait_slab.clone(),
struct_slab: self.struct_slab.clone(),
storage_slab: self.storage_slab.clone(),
abi_slab: self.abi_slab.clone(),
constant_slab: self.constant_slab.clone(),
enum_slab: self.enum_slab.clone(),
type_alias_slab: self.type_alias_slab.clone(),
parents: RwLock::new(self.parents.read().unwrap().clone()),
}
}
}

pub trait DeclEngineGet<I, U> {
fn get(&self, index: &I) -> Arc<U>;
}
Expand Down
2 changes: 1 addition & 1 deletion sway-core/src/engine_threading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{
};
use sway_types::SourceEngine;

#[derive(Debug, Default)]
#[derive(Clone, Debug, Default)]
pub struct Engines {
type_engine: TypeEngine,
decl_engine: DeclEngine,
Expand Down
1 change: 1 addition & 0 deletions sway-core/src/ir_generation/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,7 @@ mod tests {
core_lib,
None,
"test",
None,
);

let (errors, _warnings) = handler.consume();
Expand Down
32 changes: 30 additions & 2 deletions sway-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use sway_ast::AttributeDecl;
use sway_error::handler::{ErrorEmitted, Handler};
Expand Down Expand Up @@ -467,6 +468,7 @@ pub fn parsed_to_ast(
initial_namespace: namespace::Module,
build_config: Option<&BuildConfig>,
package_name: &str,
retrigger_compilation: Option<Arc<AtomicBool>>,
) -> Result<ty::TyProgram, ErrorEmitted> {
// Type check the program.
let typed_program_opt = ty::TyProgram::type_check(
Expand All @@ -477,6 +479,8 @@ pub fn parsed_to_ast(
package_name,
);

check_should_abort(handler, retrigger_compilation.clone())?;

let mut typed_program = match typed_program_opt {
Ok(typed_program) => typed_program,
Err(e) => return Err(e),
Expand Down Expand Up @@ -524,6 +528,9 @@ pub fn parsed_to_ast(
),
None => (None, None),
};

check_should_abort(handler, retrigger_compilation.clone())?;

// Perform control flow analysis and extend with any errors.
let _ = perform_control_flow_analysis(
handler,
Expand Down Expand Up @@ -596,7 +603,10 @@ pub fn compile_to_ast(
initial_namespace: namespace::Module,
build_config: Option<&BuildConfig>,
package_name: &str,
retrigger_compilation: Option<Arc<AtomicBool>>,
) -> Result<Programs, ErrorEmitted> {
check_should_abort(handler, retrigger_compilation.clone())?;

let query_engine = engines.qe();
let mut metrics = PerformanceData::default();

Expand All @@ -612,7 +622,6 @@ pub fn compile_to_ast(
let (warnings, errors) = entry.handler_data;
let new_handler = Handler::from_parts(warnings, errors);
handler.append(new_handler);

return Ok(entry.programs);
};
}
Expand All @@ -626,6 +635,8 @@ pub fn compile_to_ast(
metrics
);

check_should_abort(handler, retrigger_compilation.clone())?;

let (lexed_program, mut parsed_program) = match parse_program_opt {
Ok(modules) => modules,
Err(e) => {
Expand Down Expand Up @@ -653,18 +664,20 @@ pub fn compile_to_ast(
initial_namespace,
build_config,
package_name,
retrigger_compilation.clone(),
),
build_config,
metrics
);

check_should_abort(handler, retrigger_compilation.clone())?;

handler.dedup();

let programs = Programs::new(lexed_program, parsed_program, typed_res, metrics);

if let Some(config) = build_config {
let path = config.canonical_root_module();

let cache_entry = ProgramsCacheEntry {
path,
programs: programs.clone(),
Expand Down Expand Up @@ -693,6 +706,7 @@ pub fn compile_to_asm(
initial_namespace,
Some(&build_config),
package_name,
None,
)?;
ast_to_asm(handler, engines, &ast_res, &build_config)
}
Expand Down Expand Up @@ -942,6 +956,20 @@ fn module_return_path_analysis(
}
}

/// Check if the retrigger compilation flag has been set to true in the language server.
/// If it has, there is a new compilation request, so we should abort the current compilation.
fn check_should_abort(
handler: &Handler,
retrigger_compilation: Option<Arc<AtomicBool>>,
) -> Result<(), ErrorEmitted> {
if let Some(ref retrigger_compilation) = retrigger_compilation {
if retrigger_compilation.load(Ordering::SeqCst) {
return Err(handler.cancel());
}
}
Ok(())
}

#[test]
fn test_basic_prog() {
let handler = Handler::default();
Expand Down
14 changes: 13 additions & 1 deletion sway-core/src/query_engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ pub struct QueryEngine {
programs_cache: RwLock<ProgramsCacheMap>,
}

impl Clone for QueryEngine {
fn clone(&self) -> Self {
Self {
parse_module_cache: RwLock::new(self.parse_module_cache.read().unwrap().clone()),
programs_cache: RwLock::new(self.programs_cache.read().unwrap().clone()),
}
}
}

impl QueryEngine {
pub fn get_parse_module_cache_entry(&self, path: &ModuleCacheKey) -> Option<ModuleCacheEntry> {
let cache = self.parse_module_cache.read().unwrap();
Expand All @@ -67,7 +76,10 @@ impl QueryEngine {
}

pub fn get_programs_cache_entry(&self, path: &Arc<PathBuf>) -> Option<ProgramsCacheEntry> {
let cache = self.programs_cache.read().unwrap();
let cache = self
.programs_cache
.read()
.expect("Failed to read programs cache");
cache.get(path).cloned()
}

Expand Down
9 changes: 9 additions & 0 deletions sway-core/src/type_system/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ pub struct TypeEngine {
id_map: RwLock<HashMap<TypeSourceInfo, TypeId>>,
}

impl Clone for TypeEngine {
fn clone(&self) -> Self {
TypeEngine {
slab: self.slab.clone(),
id_map: RwLock::new(self.id_map.read().unwrap().clone()),
}
}
}

impl TypeEngine {
/// Inserts a [TypeInfo] into the [TypeEngine] and returns a [TypeId]
/// referring to that [TypeInfo].
Expand Down
5 changes: 5 additions & 0 deletions sway-error/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ impl Handler {
ErrorEmitted { _priv: () }
}

// Compilation should be cancelled.
pub fn cancel(&self) -> ErrorEmitted {
ErrorEmitted { _priv: () }
}

/// Emit the warning `warn`.
pub fn emit_warn(&self, warn: CompileWarning) {
self.inner.borrow_mut().warnings.push(warn);
Expand Down
3 changes: 2 additions & 1 deletion sway-lsp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ repository.workspace = true

[dependencies]
anyhow = "1.0.41"
crossbeam-channel = "0.5"
dashmap = "5.4"
fd-lock = "4.0"
forc-pkg = { version = "0.48.1", path = "../forc-pkg" }
Expand Down Expand Up @@ -46,7 +47,7 @@ tokio = { version = "1.3", features = [
"time",
] }
toml_edit = "0.19"
tower-lsp = { version = "0.19", features = ["proposed"] }
tower-lsp = { version = "0.20", features = ["proposed"] }
tracing = "0.1"
urlencoding = "2.1.2"

Expand Down
18 changes: 6 additions & 12 deletions sway-lsp/benches/lsp_benchmarks/compile.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,33 @@
use criterion::{black_box, criterion_group, Criterion};
use lsp_types::Url;
use sway_core::Engines;
use sway_lsp::core::session::{self, Session};
use tokio::runtime::Runtime;
use sway_lsp::core::session;

const NUM_DID_CHANGE_ITERATIONS: usize = 4;
const NUM_DID_CHANGE_ITERATIONS: usize = 10;

fn benchmarks(c: &mut Criterion) {
// Load the test project
let uri = Url::from_file_path(super::benchmark_dir().join("src/main.sw")).unwrap();
let session = Runtime::new().unwrap().block_on(async {
let session = Session::new();
session.handle_open_file(&uri).await;
session
});

c.bench_function("compile", |b| {
b.iter(|| {
let engines = Engines::default();
let _ = black_box(session::compile(&uri, &engines).unwrap());
let _ = black_box(session::compile(&uri, &engines, None).unwrap());
})
});

c.bench_function("traverse", |b| {
let engines = Engines::default();
let results = black_box(session::compile(&uri, &engines).unwrap());
let results = black_box(session::compile(&uri, &engines, None).unwrap());
b.iter(|| {
let _ = black_box(session::traverse(results.clone(), &engines).unwrap());
})
});

c.bench_function("did_change_with_caching", |b| {
let engines = Engines::default();
b.iter(|| {
for _ in 0..NUM_DID_CHANGE_ITERATIONS {
let _ = black_box(session::compile(&uri, &session.engines.read()).unwrap());
let _ = black_box(session::compile(&uri, &engines, None).unwrap());
}
})
});
Expand Down
Loading
Loading