deno.land / x / deno@v1.28.2 / cli / bench / lsp.rs
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;use deno_core::serde::Deserialize;use deno_core::serde_json;use deno_core::serde_json::json;use deno_core::serde_json::Value;use deno_core::url::Url;use std::collections::HashMap;use std::path::Path;use std::time::Duration;use test_util::lsp::LspClient;use test_util::lsp::LspResponseError;use tower_lsp::lsp_types as lsp;
static FIXTURE_CODE_LENS_TS: &str = include_str!("testdata/code_lens.ts");static FIXTURE_DB_TS: &str = include_str!("testdata/db.ts");static FIXTURE_DB_MESSAGES: &[u8] = include_bytes!("testdata/db_messages.json");static FIXTURE_INIT_JSON: &[u8] = include_bytes!("testdata/initialize_params.json");
#[derive(Debug, Deserialize)]enum FixtureType { #[serde(rename = "action")] Action, #[serde(rename = "change")] Change, #[serde(rename = "completion")] Completion, #[serde(rename = "highlight")] Highlight, #[serde(rename = "hover")] Hover,}
#[derive(Debug, Deserialize)]struct FixtureMessage { #[serde(rename = "type")] fixture_type: FixtureType, params: Value,}
/// A benchmark that opens a 8000+ line TypeScript document, adds a function to/// the end of the document and does a level of hovering and gets quick fix/// code actions.fn bench_big_file_edits(deno_exe: &Path) -> Result<Duration, AnyError> { let mut client = LspClient::new(deno_exe, false)?;
let params: Value = serde_json::from_slice(FIXTURE_INIT_JSON)?; let (_, response_error): (Option<Value>, Option<LspResponseError>) = client.write_request("initialize", params)?; assert!(response_error.is_none());
client.write_notification("initialized", json!({}))?;
client.write_notification( "textDocument/didOpen", json!({ "textDocument": { "uri": "file:///testdata/db.ts", "languageId": "typescript", "version": 1, "text": FIXTURE_DB_TS } }), )?;
let (id, method, _): (u64, String, Option<Value>) = client.read_request()?; assert_eq!(method, "workspace/configuration");
client.write_response( id, json!({ "enable": true }), )?;
let (method, _): (String, Option<Value>) = client.read_notification()?; assert_eq!(method, "textDocument/publishDiagnostics"); let (method, _): (String, Option<Value>) = client.read_notification()?; assert_eq!(method, "textDocument/publishDiagnostics"); let (method, _): (String, Option<Value>) = client.read_notification()?; assert_eq!(method, "textDocument/publishDiagnostics");
let messages: Vec<FixtureMessage> = serde_json::from_slice(FIXTURE_DB_MESSAGES)?;
for msg in messages { match msg.fixture_type { FixtureType::Action => { client.write_request::<_, _, Value>( "textDocument/codeAction", msg.params, )?; } FixtureType::Change => { client.write_notification("textDocument/didChange", msg.params)?; } FixtureType::Completion => { client.write_request::<_, _, Value>( "textDocument/completion", msg.params, )?; } FixtureType::Highlight => { client.write_request::<_, _, Value>( "textDocument/documentHighlight", msg.params, )?; } FixtureType::Hover => { client .write_request::<_, _, Value>("textDocument/hover", msg.params)?; } } }
let (_, response_error): (Option<Value>, Option<LspResponseError>) = client.write_request("shutdown", json!(null))?; assert!(response_error.is_none());
client.write_notification("exit", json!(null))?;
Ok(client.duration())}
fn bench_code_lens(deno_exe: &Path) -> Result<Duration, AnyError> { let mut client = LspClient::new(deno_exe, false)?;
let params: Value = serde_json::from_slice(FIXTURE_INIT_JSON)?; let (_, maybe_err) = client.write_request::<_, _, Value>("initialize", params)?; assert!(maybe_err.is_none()); client.write_notification("initialized", json!({}))?;
client.write_notification( "textDocument/didOpen", json!({ "textDocument": { "uri": "file:///testdata/code_lens.ts", "languageId": "typescript", "version": 1, "text": FIXTURE_CODE_LENS_TS } }), )?;
let (id, method, _): (u64, String, Option<Value>) = client.read_request()?; assert_eq!(method, "workspace/configuration");
client.write_response( id, json!({ "enable": true }), )?;
let (method, _): (String, Option<Value>) = client.read_notification()?; assert_eq!(method, "textDocument/publishDiagnostics"); let (method, _): (String, Option<Value>) = client.read_notification()?; assert_eq!(method, "textDocument/publishDiagnostics"); let (method, _): (String, Option<Value>) = client.read_notification()?; assert_eq!(method, "textDocument/publishDiagnostics");
let (maybe_res, maybe_err) = client .write_request::<_, _, Vec<lsp::CodeLens>>( "textDocument/codeLens", json!({ "textDocument": { "uri": "file:///testdata/code_lens.ts" } }), ) .unwrap(); assert!(maybe_err.is_none()); assert!(maybe_res.is_some()); let res = maybe_res.unwrap(); assert!(!res.is_empty());
for code_lens in res { let (maybe_res, maybe_err) = client .write_request::<_, _, lsp::CodeLens>("codeLens/resolve", code_lens) .unwrap(); assert!(maybe_err.is_none()); assert!(maybe_res.is_some()); }
Ok(client.duration())}
fn bench_find_replace(deno_exe: &Path) -> Result<Duration, AnyError> { let mut client = LspClient::new(deno_exe, false)?;
let params: Value = serde_json::from_slice(FIXTURE_INIT_JSON)?; let (_, maybe_err) = client.write_request::<_, _, Value>("initialize", params)?; assert!(maybe_err.is_none()); client.write_notification("initialized", json!({}))?;
for i in 0..10 { client.write_notification( "textDocument/didOpen", json!({ "textDocument": { "uri": format!("file:///a/file_{}.ts", i), "languageId": "typescript", "version": 1, "text": "console.log(\"000\");\n" } }), )?; }
for _ in 0..10 { let (id, method, _) = client.read_request::<Value>()?; assert_eq!(method, "workspace/configuration"); client.write_response(id, json!({ "enable": true }))?; }
for _ in 0..3 { let (method, _): (String, Option<Value>) = client.read_notification()?; assert_eq!(method, "textDocument/publishDiagnostics"); }
for i in 0..10 { let file_name = format!("file:///a/file_{}.ts", i); client.write_notification( "textDocument/didChange", lsp::DidChangeTextDocumentParams { text_document: lsp::VersionedTextDocumentIdentifier { uri: Url::parse(&file_name).unwrap(), version: 2, }, content_changes: vec![lsp::TextDocumentContentChangeEvent { range: Some(lsp::Range { start: lsp::Position { line: 0, character: 13, }, end: lsp::Position { line: 0, character: 16, }, }), range_length: None, text: "111".to_string(), }], }, )?; }
for i in 0..10 { let file_name = format!("file:///a/file_{}.ts", i); let (maybe_res, maybe_err) = client.write_request::<_, _, Value>( "textDocument/formatting", lsp::DocumentFormattingParams { text_document: lsp::TextDocumentIdentifier { uri: Url::parse(&file_name).unwrap(), }, options: lsp::FormattingOptions { tab_size: 2, insert_spaces: true, ..Default::default() }, work_done_progress_params: Default::default(), }, )?; assert!(maybe_err.is_none()); assert!(maybe_res.is_some()); }
for _ in 0..3 { let (method, _): (String, Option<Value>) = client.read_notification()?; assert_eq!(method, "textDocument/publishDiagnostics"); }
let (_, response_error): (Option<Value>, Option<LspResponseError>) = client.write_request("shutdown", json!(null))?; assert!(response_error.is_none());
client.write_notification("exit", json!(null))?;
Ok(client.duration())}
/// A test that starts up the LSP, opens a single line document, and exits.fn bench_startup_shutdown(deno_exe: &Path) -> Result<Duration, AnyError> { let mut client = LspClient::new(deno_exe, false)?;
let params: Value = serde_json::from_slice(FIXTURE_INIT_JSON)?; let (_, response_error) = client.write_request::<_, _, Value>("initialize", params)?; assert!(response_error.is_none());
client.write_notification("initialized", json!({}))?;
client.write_notification( "textDocument/didOpen", json!({ "textDocument": { "uri": "file:///a/file.ts", "languageId": "typescript", "version": 1, "text": "console.log(Deno.args);\n" } }), )?;
let (id, method, _) = client.read_request::<Value>()?; assert_eq!(method, "workspace/configuration");
client.write_response( id, json!({ "enable": true }), )?;
let (method, _): (String, Option<Value>) = client.read_notification()?; assert_eq!(method, "textDocument/publishDiagnostics"); let (method, _): (String, Option<Value>) = client.read_notification()?; assert_eq!(method, "textDocument/publishDiagnostics"); let (method, _): (String, Option<Value>) = client.read_notification()?; assert_eq!(method, "textDocument/publishDiagnostics");
let (_, response_error): (Option<Value>, Option<LspResponseError>) = client.write_request("shutdown", json!(null))?; assert!(response_error.is_none());
client.write_notification("exit", json!(null))?;
Ok(client.duration())}
/// Generate benchmarks for the LSP server.pub fn benchmarks(deno_exe: &Path) -> Result<HashMap<String, i64>, AnyError> { println!("-> Start benchmarking lsp"); let mut exec_times = HashMap::new();
println!(" - Simple Startup/Shutdown "); let mut times = Vec::new(); for _ in 0..10 { times.push(bench_startup_shutdown(deno_exe)?); } let mean = (times.iter().sum::<Duration>() / times.len() as u32).as_millis() as i64; println!(" ({} runs, mean: {}ms)", times.len(), mean); exec_times.insert("startup_shutdown".to_string(), mean);
println!(" - Big Document/Several Edits "); let mut times = Vec::new(); for _ in 0..5 { times.push(bench_big_file_edits(deno_exe)?); } let mean = (times.iter().sum::<Duration>() / times.len() as u32).as_millis() as i64; println!(" ({} runs, mean: {}ms)", times.len(), mean); exec_times.insert("big_file_edits".to_string(), mean);
println!(" - Find/Replace"); let mut times = Vec::new(); for _ in 0..10 { times.push(bench_find_replace(deno_exe)?); } let mean = (times.iter().sum::<Duration>() / times.len() as u32).as_millis() as i64; println!(" ({} runs, mean: {}ms)", times.len(), mean); exec_times.insert("find_replace".to_string(), mean);
println!(" - Code Lens"); let mut times = Vec::new(); for _ in 0..10 { times.push(bench_code_lens(deno_exe)?); } let mean = (times.iter().sum::<Duration>() / times.len() as u32).as_millis() as i64; println!(" ({} runs, mean: {}ms)", times.len(), mean); exec_times.insert("code_lens".to_string(), mean);
println!("<- End benchmarking lsp");
Ok(exec_times)}
Version Info