Box ShellError in Value::Error (#8375)

# Description

Our `ShellError` at the moment has a `std::mem::size_of<ShellError>` of
136 bytes (on AMD64). As a result `Value` directly storing the struct
also required 136 bytes (thanks to alignment requirements).

This change stores the `Value::Error` `ShellError` on the heap.

Pro:
- Value now needs just 80 bytes
- Should be 1 cacheline less (still at least 2 cachelines)

Con:
- More small heap allocations when dealing with `Value::Error`
  - More heap fragmentation
  - Potential for additional required memcopies

# Further code changes

Includes a small refactor of `try` due to a type mismatch in its large
match.

# User-Facing Changes

None for regular users.

Plugin authors may have to update their matches on `Value` if they use
`nu-protocol`

Needs benchmarking to see if there is a benefit in real world workloads.
**Update** small improvements in runtime for workloads with high volume
of values. Significant reduction in maximum resident set size, when many
values are held in memory.

# Tests + Formatting
This commit is contained in:
Stefan Holderbach
2023-03-12 09:57:27 +01:00
committed by GitHub
parent c26d91fb61
commit a52386e837
153 changed files with 648 additions and 520 deletions

View File

@@ -111,7 +111,7 @@ fn exists(path: &Path, span: Span, args: &Arguments) -> Value {
Ok(exists) => exists,
Err(err) => {
return Value::Error {
error: ShellError::IOErrorSpanned(err.to_string(), span),
error: Box::new(ShellError::IOErrorSpanned(err.to_string(), span)),
}
}
},

View File

@@ -136,7 +136,7 @@ fn expand(path: &Path, span: Span, args: &Arguments) -> Value {
}
}
Err(_) => Value::Error {
error: ShellError::GenericError(
error: Box::new(ShellError::GenericError(
"Could not expand path".into(),
"could not be expanded (path might not exist, non-final \
component is not a directory, or other cause)"
@@ -144,7 +144,7 @@ fn expand(path: &Path, span: Span, args: &Arguments) -> Value {
Some(span),
None,
Vec::new(),
),
)),
},
}
} else if args.not_follow_symlink {

View File

@@ -197,11 +197,11 @@ fn join_list(parts: &[Value], head: Span, span: Span, args: &Arguments) -> Value
Value::List { vals, span }
}
Err(_) => Value::Error {
error: ShellError::PipelineMismatch {
error: Box::new(ShellError::PipelineMismatch {
exp_input_type: "string or record".into(),
dst_span: head,
src_span: span,
},
}),
},
}
}
@@ -223,7 +223,9 @@ fn join_record(cols: &[String], vals: &[Value], head: Span, span: Span, args: &A
} else {
match merge_record(cols, vals, head, span) {
Ok(p) => join_single(p.as_path(), head, args),
Err(error) => Value::Error { error },
Err(error) => Value::Error {
error: Box::new(error),
},
}
}
}

View File

@@ -48,12 +48,12 @@ where
};
if col.is_empty() {
return Value::Error {
error: ShellError::UnsupportedInput(
error: Box::new(ShellError::UnsupportedInput(
String::from("when the input is a table, you must specify the columns"),
"value originates from here".into(),
name,
span,
),
)),
};
}
@@ -85,7 +85,7 @@ where
fn handle_invalid_values(rest: Value, name: Span) -> Value {
Value::Error {
error: err_from_value(&rest, name),
error: Box::new(err_from_value(&rest, name)),
}
}

View File

@@ -128,12 +128,12 @@ fn relative_to(path: &Path, span: Span, args: &Arguments) -> Value {
match lhs.strip_prefix(&rhs) {
Ok(p) => Value::string(p.to_string_lossy(), span),
Err(e) => Value::Error {
error: ShellError::CantConvert {
error: Box::new(ShellError::CantConvert {
to_type: e.to_string(),
from_type: "string".into(),
span,
help: None,
},
}),
},
}
}