Hopefully speedup startup (#8913)

# Description

Trying a few different things to hopefully speedup startup a bit. I'm
seeing some improvement on my box for the profiles I have, but the data
I'm seeing is noisy.

- Remove allocations in a few places where we created vec's but could
use iterators
- Pre-allocate space for blocks based on the lite block
- Removed a few extra clones

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->

# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
- `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the
standard library

> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
This commit is contained in:
JT
2023-04-18 20:19:08 +12:00
committed by GitHub
parent 06996d8c7f
commit 32f098d91d
6 changed files with 236 additions and 245 deletions

View File

@@ -2145,7 +2145,12 @@ pub fn parse_datetime(working_set: &mut StateWorkingSet, span: Span) -> Expressi
let bytes = working_set.get_span_contents(span);
if bytes.is_empty() || !bytes[0].is_ascii_digit() {
if bytes.len() < 5
|| !bytes[0].is_ascii_digit()
|| !bytes[1].is_ascii_digit()
|| !bytes[2].is_ascii_digit()
|| !bytes[3].is_ascii_digit()
{
working_set.error(ParseError::Expected("datetime".into(), span));
return garbage(span);
}
@@ -2450,6 +2455,10 @@ pub fn unescape_string(bytes: &[u8], span: Span) -> (Vec<u8>, Option<ParseError>
let mut idx = 0;
if !bytes.contains(&b'\\') {
return (bytes.to_vec(), None);
}
'us_loop: while idx < bytes.len() {
if bytes[idx] == b'\\' {
// We're in an escape
@@ -4523,7 +4532,6 @@ pub fn parse_value(
}
}
working_set.error(ParseError::Expected("any shape".into(), span));
garbage(span)
}
}
@@ -5217,132 +5225,127 @@ pub fn parse_block(
}
}
let block: Block = lite_block
.block
.iter()
.enumerate()
.map(|(idx, pipeline)| {
if pipeline.commands.len() > 1 {
let mut output = pipeline
.commands
.iter()
.map(|command| match command {
LiteElement::Command(span, command) => {
trace!("parsing: pipeline element: command");
let expr =
parse_expression(working_set, &command.parts, is_subexpression);
working_set.type_scope.add_type(expr.ty.clone());
let mut block = Block::new_with_capacity(lite_block.block.len());
PipelineElement::Expression(*span, expr)
}
LiteElement::Redirection(span, redirection, command) => {
trace!("parsing: pipeline element: redirection");
let expr = parse_string(working_set, command.parts[0]);
for (idx, pipeline) in lite_block.block.iter().enumerate() {
if pipeline.commands.len() > 1 {
let mut output = pipeline
.commands
.iter()
.map(|command| match command {
LiteElement::Command(span, command) => {
trace!("parsing: pipeline element: command");
let expr = parse_expression(working_set, &command.parts, is_subexpression);
working_set.type_scope.add_type(expr.ty.clone());
working_set.type_scope.add_type(expr.ty.clone());
PipelineElement::Expression(*span, expr)
}
LiteElement::Redirection(span, redirection, command) => {
trace!("parsing: pipeline element: redirection");
let expr = parse_string(working_set, command.parts[0]);
PipelineElement::Redirection(*span, redirection.clone(), expr)
}
LiteElement::SeparateRedirection {
out: (out_span, out_command),
err: (err_span, err_command),
} => {
trace!("parsing: pipeline element: separate redirection");
let out_expr = parse_string(working_set, out_command.parts[0]);
working_set.type_scope.add_type(expr.ty.clone());
working_set.type_scope.add_type(out_expr.ty.clone());
PipelineElement::Redirection(*span, redirection.clone(), expr)
}
LiteElement::SeparateRedirection {
out: (out_span, out_command),
err: (err_span, err_command),
} => {
trace!("parsing: pipeline element: separate redirection");
let out_expr = parse_string(working_set, out_command.parts[0]);
let err_expr = parse_string(working_set, err_command.parts[0]);
working_set.type_scope.add_type(out_expr.ty.clone());
working_set.type_scope.add_type(err_expr.ty.clone());
let err_expr = parse_string(working_set, err_command.parts[0]);
PipelineElement::SeparateRedirection {
out: (*out_span, out_expr),
err: (*err_span, err_expr),
}
}
})
.collect::<Vec<PipelineElement>>();
working_set.type_scope.add_type(err_expr.ty.clone());
if is_subexpression {
for element in output.iter_mut().skip(1) {
if element.has_in_variable(working_set) {
*element = wrap_element_with_collect(working_set, element);
PipelineElement::SeparateRedirection {
out: (*out_span, out_expr),
err: (*err_span, err_expr),
}
}
} else {
for element in output.iter_mut() {
if element.has_in_variable(working_set) {
*element = wrap_element_with_collect(working_set, element);
}
})
.collect::<Vec<PipelineElement>>();
if is_subexpression {
for element in output.iter_mut().skip(1) {
if element.has_in_variable(working_set) {
*element = wrap_element_with_collect(working_set, element);
}
}
Pipeline { elements: output }
} else {
match &pipeline.commands[0] {
LiteElement::Command(_, command)
| LiteElement::Redirection(_, _, command)
| LiteElement::SeparateRedirection {
out: (_, command), ..
} => {
let mut pipeline =
parse_builtin_commands(working_set, command, is_subexpression);
for element in output.iter_mut() {
if element.has_in_variable(working_set) {
*element = wrap_element_with_collect(working_set, element);
}
}
}
if idx == 0 {
if let Some(let_decl_id) = working_set.find_decl(b"let", &Type::Any) {
if let Some(let_env_decl_id) =
working_set.find_decl(b"let-env", &Type::Any)
{
for element in pipeline.elements.iter_mut() {
if let PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) = element
block.pipelines.push(Pipeline { elements: output })
} else {
match &pipeline.commands[0] {
LiteElement::Command(_, command)
| LiteElement::Redirection(_, _, command)
| LiteElement::SeparateRedirection {
out: (_, command), ..
} => {
let mut pipeline =
parse_builtin_commands(working_set, command, is_subexpression);
if idx == 0 {
if let Some(let_decl_id) = working_set.find_decl(b"let", &Type::Any) {
if let Some(let_env_decl_id) =
working_set.find_decl(b"let-env", &Type::Any)
{
for element in pipeline.elements.iter_mut() {
if let PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) = element
{
if call.decl_id == let_decl_id
|| call.decl_id == let_env_decl_id
{
if call.decl_id == let_decl_id
|| call.decl_id == let_env_decl_id
// Do an expansion
if let Some(Expression {
expr: Expr::Keyword(_, _, expr),
..
}) = call.positional_iter_mut().nth(1)
{
// Do an expansion
if let Some(Expression {
expr: Expr::Keyword(_, _, expr),
..
}) = call.positional_iter_mut().nth(1)
{
if expr.has_in_variable(working_set) {
*expr = Box::new(wrap_expr_with_collect(
working_set,
expr,
));
}
if expr.has_in_variable(working_set) {
*expr = Box::new(wrap_expr_with_collect(
working_set,
expr,
));
}
continue;
} else if element.has_in_variable(working_set)
&& !is_subexpression
{
*element =
wrap_element_with_collect(working_set, element);
}
continue;
} else if element.has_in_variable(working_set)
&& !is_subexpression
{
*element =
wrap_element_with_collect(working_set, element);
}
} else if element.has_in_variable(working_set)
&& !is_subexpression
{
*element = wrap_element_with_collect(working_set, element);
}
}
}
}
pipeline
}
block.pipelines.push(pipeline)
}
}
})
.into();
}
}
if scoped {
working_set.exit_scope();
@@ -5663,6 +5666,7 @@ pub fn discover_captures_in_expr(
)?;
results
};
seen_blocks.insert(*block_id, results.clone());
for (var_id, span) in results.into_iter() {
if !seen.contains(&var_id) {