-
Notifications
You must be signed in to change notification settings - Fork 4.2k
GH-33880: [C++] Improve I/O tracing #34168
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
Changes from 47 commits
3f24850
d106c42
8aba916
f9da7ad
10a80d6
ab34c08
4e48581
1a1307a
56b8535
56c52af
815d317
481bbe4
1f3adee
43a7fba
af56a27
24b5ff8
37e84e4
ed397fc
2f7fa97
38c4639
8764d34
58c9db4
ee28b21
1163ef1
07343d7
a3a126d
e1a0a0f
6a9b635
ecd80c4
a28a1db
a665bb6
2129678
06bcc1e
c8fa9f6
d315264
407bcb2
ccdf2ec
45f03fa
4e0d497
42fc7b6
b64ca22
898b093
78ea497
4028cd6
19522e5
b9df0be
07d5012
14874ca
50e808c
fc9c659
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,12 +43,14 @@ | |
| #include "arrow/type.h" | ||
| #include "arrow/type_fwd.h" | ||
| #include "arrow/util/async_generator.h" | ||
| #include "arrow/util/byte_size.h" | ||
| #include "arrow/util/future.h" | ||
| #include "arrow/util/iterator.h" | ||
| #include "arrow/util/logging.h" | ||
| #include "arrow/util/macros.h" | ||
| #include "arrow/util/task_group.h" | ||
| #include "arrow/util/thread_pool.h" | ||
| #include "arrow/util/tracing_internal.h" | ||
| #include "arrow/util/utf8_internal.h" | ||
| #include "arrow/util/vector.h" | ||
|
|
||
|
|
@@ -401,6 +403,8 @@ class BlockParsingOperator { | |
| num_rows_seen_(first_row) {} | ||
|
|
||
| Result<ParsedBlock> operator()(const CSVBlock& block) { | ||
| util::tracing::Span span; | ||
| START_SPAN(span, "arrow::csv::BlockParsingOperator"); | ||
| constexpr int32_t max_num_rows = std::numeric_limits<int32_t>::max(); | ||
| auto parser = std::make_shared<BlockParser>( | ||
| io_context_.pool(), parse_options_, num_csv_cols_, num_rows_seen_, max_num_rows); | ||
|
|
@@ -431,6 +435,7 @@ class BlockParsingOperator { | |
| num_rows_seen_ += parser->total_num_rows(); | ||
| } | ||
| RETURN_NOT_OK(block.consume_bytes(parsed_size)); | ||
| ATTRIBUTE_ON_CURRENT_SPAN("parsed_size", parsed_size); | ||
| return ParsedBlock{std::move(parser), block.block_index, | ||
| static_cast<int64_t>(parsed_size) + block.bytes_skipped}; | ||
| } | ||
|
|
@@ -448,6 +453,8 @@ class BlockParsingOperator { | |
| class BlockDecodingOperator { | ||
| public: | ||
| Future<DecodedBlock> operator()(const ParsedBlock& block) { | ||
| util::tracing::Span span; | ||
| START_SPAN(span, "arrow::csv::BlockDecodingOperator"); | ||
| DCHECK(!state_->column_decoders.empty()); | ||
| std::vector<Future<std::shared_ptr<Array>>> decoded_array_futs; | ||
| for (auto& decoder : state_->column_decoders) { | ||
|
|
@@ -456,6 +463,23 @@ class BlockDecodingOperator { | |
| auto bytes_parsed_or_skipped = block.bytes_parsed_or_skipped; | ||
| auto decoded_arrays_fut = All(std::move(decoded_array_futs)); | ||
| auto state = state_; | ||
| #ifdef ARROW_WITH_OPENTELEMETRY | ||
| opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span> raw_span = | ||
| ::arrow::internal::tracing::UnwrapSpan(span.details.get()); | ||
| return decoded_arrays_fut.Then( | ||
| [state, bytes_parsed_or_skipped, raw_span]( | ||
| const std::vector<Result<std::shared_ptr<Array>>>& maybe_decoded_arrays) | ||
| -> Result<DecodedBlock> { | ||
| ARROW_ASSIGN_OR_RAISE(auto decoded_arrays, | ||
| arrow::internal::UnwrapOrRaise(maybe_decoded_arrays)); | ||
|
|
||
| ARROW_ASSIGN_OR_RAISE(auto batch, | ||
| state->DecodedArraysToBatch(std::move(decoded_arrays))); | ||
| raw_span->SetAttribute("arrow.csv.output_batch_size_bytes", | ||
| util::TotalBufferSize(*batch)); | ||
| return DecodedBlock{std::move(batch), bytes_parsed_or_skipped}; | ||
| }); | ||
| #else | ||
| return decoded_arrays_fut.Then( | ||
| [state, bytes_parsed_or_skipped]( | ||
| const std::vector<Result<std::shared_ptr<Array>>>& maybe_decoded_arrays) | ||
|
|
@@ -467,6 +491,7 @@ class BlockDecodingOperator { | |
| state->DecodedArraysToBatch(std::move(decoded_arrays))); | ||
| return DecodedBlock{std::move(batch), bytes_parsed_or_skipped}; | ||
| }); | ||
| #endif | ||
| } | ||
|
|
||
| static Result<BlockDecodingOperator> Make(io::IOContext io_context, | ||
|
|
@@ -881,7 +906,27 @@ class StreamingReaderImpl : public ReaderMixin, | |
| } | ||
|
|
||
| Future<std::shared_ptr<RecordBatch>> ReadNextAsync() override { | ||
| return record_batch_gen_(); | ||
| util::tracing::Span span; | ||
| START_SPAN(span, "arrow::csv::ReadNextAsync"); | ||
| auto future = record_batch_gen_(); | ||
| #ifdef ARROW_WITH_OPENTELEMETRY | ||
| auto longer_living_span = std::make_unique<util::tracing::Span>(std::move(span)); | ||
| future.AddCallback( | ||
| [span = std::move(longer_living_span)]( | ||
| const arrow::Result<std::shared_ptr<arrow::RecordBatch>>& result) { | ||
| opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span> raw_span = | ||
| ::arrow::internal::tracing::UnwrapSpan(span->details.get()); | ||
| if (result.ok()) { | ||
| auto result_batch = result.ValueOrDie(); | ||
| if (result_batch) { | ||
| raw_span->SetAttribute("batch.size_bytes", | ||
| ::arrow::util::TotalBufferSize(*result_batch)); | ||
| } | ||
| } | ||
| END_SPAN((*span)); | ||
| }); | ||
| #endif | ||
| return future; | ||
| } | ||
|
|
||
| protected: | ||
|
|
@@ -892,6 +937,14 @@ class StreamingReaderImpl : public ReaderMixin, | |
| return Status::Invalid("Empty CSV file"); | ||
| } | ||
|
|
||
| util::tracing::Span init_span; | ||
| START_SPAN(init_span, "arrow::csv::InitAfterFirstBuffer"); | ||
|
|
||
| // Create a arrow::csv::ReadNextAsync span so that grouping by that name does not | ||
| // ignore the work performed for this first block. | ||
| util::tracing::Span read_span; | ||
| auto scope = START_SCOPED_SPAN(read_span, "arrow::csv::ReadNextAsync"); | ||
|
|
||
| std::shared_ptr<Buffer> after_header; | ||
| ARROW_ASSIGN_OR_RAISE(auto header_bytes_consumed, | ||
| ProcessHeader(first_buffer, &after_header)); | ||
|
|
@@ -911,9 +964,25 @@ class StreamingReaderImpl : public ReaderMixin, | |
| auto rb_gen = MakeMappedGenerator(std::move(parsed_block_gen), std::move(decoder_op)); | ||
|
|
||
| auto self = shared_from_this(); | ||
| return rb_gen().Then([self, rb_gen, max_readahead](const DecodedBlock& first_block) { | ||
| return self->InitFromBlock(first_block, std::move(rb_gen), max_readahead, 0); | ||
| auto init_finished = rb_gen().Then([self, rb_gen, max_readahead | ||
| #ifdef ARROW_WITH_OPENTELEMETRY | ||
| , | ||
| init_span = std::move(init_span), | ||
| read_span = std::move(read_span) | ||
| #endif | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this |
||
| ](const DecodedBlock& first_block) { | ||
| auto fut = self->InitFromBlock(first_block, std::move(rb_gen), max_readahead, 0); | ||
| #ifdef ARROW_WITH_OPENTELEMETRY | ||
| opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span> raw_span = | ||
| ::arrow::internal::tracing::UnwrapSpan(read_span.details.get()); | ||
| raw_span->SetAttribute("batch.size_bytes", | ||
| util::TotalBufferSize(*first_block.record_batch)); | ||
| #endif | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not |
||
| END_SPAN(read_span); | ||
| END_SPAN(init_span); | ||
| return fut; | ||
| }); | ||
| return init_finished; | ||
| } | ||
|
|
||
| Future<> InitFromBlock(const DecodedBlock& block, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there is too much duplicated code in these alternate paths. Is there any way we can just pass
spanto the callback's capture list and useATTRIBUTE_ON_CURRENT_SPAN? Also, what happened toEND_SPAN_ON_FUTURE_COMPLETION?