diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index 05ed1b9912..10e0bbb68b 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -5,7 +5,7 @@ use nu_protocol::{ Argument, Assignment, Bits, Block, Boolean, Call, Comparison, Expr, Expression, Math, Operator, PathMember, PipelineElement, Redirection, }, - engine::{EngineState, Stack}, + engine::{EngineState, ProfilingConfig, Stack}, Config, DataSource, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, PipelineMetadata, Range, ShellError, Span, Spanned, Unit, Value, VarId, ENV_VARIABLE_ID, }; @@ -1046,95 +1046,23 @@ pub fn eval_block( if let (Some(start_time), Some(end_time), Some(input_metadata)) = (start_time, end_time, input_metadata.as_deref_mut()) { - let span = pipeline.elements[i].span(); - let element_str = Value::string( - String::from_utf8_lossy( - engine_state.get_span_contents(&pipeline.elements[i].span()), - ), - span, + let element_span = pipeline.elements[i].span(); + let element_str = String::from_utf8_lossy( + engine_state.get_span_contents(&pipeline.elements[i].span()), + ) + .to_string(); + + collect_profiling_metadata( + pipeline_idx, + i, + element_str, + element_span, + start_time, + end_time, + &stack.profiling_config, + &eval_result, + input_metadata, ); - let time_ns = (end_time - start_time).as_nanos() as i64; - - let mut cols = vec![ - "pipeline_idx".to_string(), - "element_idx".to_string(), - "depth".to_string(), - "span".to_string(), - ]; - - let mut vals = vec![ - Value::int(pipeline_idx as i64, span), - Value::int(i as i64, span), - Value::int(stack.profiling_config.depth, span), - Value::record( - vec!["start".to_string(), "end".to_string()], - vec![ - Value::int(span.start as i64, span), - Value::int(span.end as i64, span), - ], - span, - ), - ]; - - if stack.profiling_config.collect_source { - cols.push("source".to_string()); - vals.push(element_str.clone()); - } - - if stack.profiling_config.collect_values { - let value = match &eval_result { - Ok((PipelineData::Value(val, ..), ..)) => val.clone(), - Ok((PipelineData::ListStream(..), ..)) => { - Value::string("list stream", span) - } - Ok((PipelineData::ExternalStream { .. }, ..)) => { - Value::string("raw stream", span) - } - Ok((PipelineData::Empty, ..)) => Value::Nothing { span }, - Err(err) => Value::Error { error: err.clone() }, - }; - - cols.push("value".to_string()); - vals.push(value); - } - - cols.push("time".to_string()); - vals.push(Value::Duration { val: time_ns, span }); - - let record = Value::Record { cols, vals, span }; - - let element_metadata = if let Ok((pipeline_data, ..)) = &eval_result { - pipeline_data.metadata() - } else { - None - }; - - if let PipelineMetadata { - data_source: DataSource::Profiling(tgt_vals), - } = input_metadata - { - tgt_vals.push(record); - } else { - *input_metadata = PipelineMetadata { - data_source: DataSource::Profiling(vec![record]), - }; - } - - if let Some(PipelineMetadata { - data_source: DataSource::Profiling(element_vals), - }) = element_metadata.map(|m| *m) - { - if let PipelineMetadata { - data_source: DataSource::Profiling(tgt_vals), - } = input_metadata - { - tgt_vals.extend(element_vals); - } else { - *input_metadata = PipelineMetadata { - data_source: DataSource::Profiling(element_vals), - }; - } - } } match (eval_result, redirect_stderr) { @@ -1441,3 +1369,105 @@ fn compute(size: i64, unit: Unit, span: Span) -> Value { }, } } + +#[allow(clippy::too_many_arguments)] +fn collect_profiling_metadata( + pipeline_idx: usize, + element_idx: usize, + element_str: String, + element_span: Span, + start_time: Instant, + end_time: Instant, + profiling_config: &ProfilingConfig, + eval_result: &Result<(PipelineData, bool), ShellError>, + input_metadata: &mut PipelineMetadata, +) { + let element_str = Value::string(element_str, element_span); + let time_ns = (end_time - start_time).as_nanos() as i64; + + let mut cols = vec![ + "pipeline_idx".to_string(), + "element_idx".to_string(), + "depth".to_string(), + "span".to_string(), + ]; + + let mut vals = vec![ + Value::int(pipeline_idx as i64, element_span), + Value::int(element_idx as i64, element_span), + Value::int(profiling_config.depth, element_span), + Value::record( + vec!["start".to_string(), "end".to_string()], + vec![ + Value::int(element_span.start as i64, element_span), + Value::int(element_span.end as i64, element_span), + ], + element_span, + ), + ]; + + if profiling_config.collect_source { + cols.push("source".to_string()); + vals.push(element_str); + } + + if profiling_config.collect_values { + let value = match &eval_result { + Ok((PipelineData::Value(val, ..), ..)) => val.clone(), + Ok((PipelineData::ListStream(..), ..)) => Value::string("list stream", element_span), + Ok((PipelineData::ExternalStream { .. }, ..)) => { + Value::string("raw stream", element_span) + } + Ok((PipelineData::Empty, ..)) => Value::Nothing { span: element_span }, + Err(err) => Value::Error { error: err.clone() }, + }; + + cols.push("value".to_string()); + vals.push(value); + } + + cols.push("time".to_string()); + vals.push(Value::Duration { + val: time_ns, + span: element_span, + }); + + let record = Value::Record { + cols, + vals, + span: element_span, + }; + + let element_metadata = if let Ok((pipeline_data, ..)) = &eval_result { + pipeline_data.metadata() + } else { + None + }; + + if let PipelineMetadata { + data_source: DataSource::Profiling(tgt_vals), + } = input_metadata + { + tgt_vals.push(record); + } else { + *input_metadata = PipelineMetadata { + data_source: DataSource::Profiling(vec![record]), + }; + } + + if let Some(PipelineMetadata { + data_source: DataSource::Profiling(element_vals), + }) = element_metadata.map(|m| *m) + { + if let PipelineMetadata { + data_source: DataSource::Profiling(tgt_vals), + } = input_metadata + { + tgt_vals.extend(element_vals); + } else { + *input_metadata = PipelineMetadata { + data_source: DataSource::Profiling(element_vals), + }; + } + } +}