Skip to content

perf(vindex): split build timing logs by phase - #723

Merged
JingsongLi merged 2 commits into
apache:mainfrom
jerry-024:perf/vindex-build-timing
Aug 20, 2026
Merged

perf(vindex): split build timing logs by phase#723
JingsongLi merged 2 commits into
apache:mainfrom
jerry-024:perf/vindex-build-timing

Conversation

@jerry-024

@jerry-024 jerry-024 commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Purpose

Vector index build diagnostics currently do not distinguish storage I/O, Parquet decoding, index training, and index population costs. This change adds opt-in phase-level timing logs so build bottlenecks can be identified without adding log noise when diagnostics are not enabled.

Enable the logs with:

PAIMON_LOG_VECTOR_INDEX_BUILD_TIMING=1

Brief change log

  • Split source batch wait, OSS/file reads, and Parquet decoding into independent timings.
  • Split raw temporary-file writes/rereads, index training, and index add into independent timings.
  • Report serialization/upload, snapshot commit, total, unattributed time, and build counters in one structured log event.
  • Keep timing collection and logging disabled by default.

Tests

  • cargo test -p paimon
  • Run vector index build tests with timing disabled and enabled; verify logs are emitted only when enabled and phase fields are populated.
  • cargo fmt --all -- --check
  • git diff --check

API and Format

No public API or storage format changes.

Documentation

No documentation changes. The environment variable is intended for opt-in build diagnostics.

@jerry-024
jerry-024 marked this pull request as draft August 17, 2026 10:42
@jerry-024 jerry-024 changed the title perf(vindex): add detailed build timing logs perf(vindex): split build timing logs by phase Aug 17, 2026
The default_training_vector_count call was only used to populate a
timing log field, but it ran unconditionally and propagated errors,
introducing a new build failure path even when timing diagnostics
were disabled. Compute it only when timing is enabled and fall back
to 0 on error instead of failing the build.

Co-Authored-By: Claude <noreply@anthropic.com>
@jerry-024
jerry-024 marked this pull request as ready for review August 18, 2026 07:41

@shyjsarah shyjsarah left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the phase-level timing changes. The build path itself looks sound and CI is green, but I found four issues in the diagnostic semantics/implementation that are worth addressing so the emitted data remains actionable. Details are inline.

async fn read(&self, range: Range<u64>) -> crate::Result<bytes::Bytes> {
let start = Instant::now();
let result = self.inner.read(range).await;
self.timing.add_file_read(start.elapsed());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

file_read_nanos sums the elapsed time of every FileRead::read, but Parquet range fetching can run multiple reads concurrently (up to RANGE_FETCH_CONCURRENCY). Overlapping waits are therefore double-counted, so the emitted oss_read_ms is cumulative request wait rather than storage-I/O wall time and may exceed the enclosing phase/total. Could we either measure the wall-clock I/O span, or rename this to something like oss_read_wait_sum_ms and report the actual concurrency? The current hard-coded data_file_read_concurrency=1 is misleading for the same reason.

if let Some(commit_start) = commit_start {
let commit = commit_start.elapsed();
for timing in timings {
timing.log(&self.index_type, commit);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This applies the single operation-level commit duration to every shard-level timing event. For a multi-shard build, summing events counts commit N times; an early shard's total_ms also excludes time spent building later shards, so it is neither shard wall time nor operation wall time. Suggest keeping shard events limited to shard phases and emitting one operation-level event for all-shard build time, the single commit, and end-to-end total (ideally linked by a build ID).

);
let shard_count = shards.len();
let mut messages = Vec::with_capacity(shard_count);
let mut timings = Vec::with_capacity(shard_count);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reserves one VectorIndexBuildTiming slot per shard even when PAIMON_LOG_VECTOR_INDEX_BUILD_TIMING is disabled, leaving the default-off path with O(shard_count) diagnostic memory. Could we read the enable flag once and allocate/push only when enabled (or aggregate bounded operation-level stats instead)?

.saturating_add(self.serialize_upload)
.saturating_add(commit);
let unattributed = total.saturating_sub(accounted);
eprintln!(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this use the logging facade instead of eprintln!? Direct stderr bypasses the embedding application's filtering, targets, sinks, structured handlers, and test logger, and performs synchronous output in this async path. Nearby vector diagnostics already use log::debug!; a stable target such as paimon::vector_index_build would keep this routable while the env flag can still avoid timing overhead when disabled.

@JingsongLi JingsongLi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@JingsongLi
JingsongLi merged commit 53c17eb into apache:main Aug 20, 2026
13 checks passed
jerry-024 added a commit to jerry-024/paimon-rust that referenced this pull request Aug 21, 2026
* main:
  perf: vectorize raw vector search (apache#734)
  feat(file_index): add predicate evaluation foundation (apache#721)
  feat(go): add postpone fixed-bucket write bindings (apache#722)
  perf(vindex): split build timing logs by phase (apache#723)
  fix(avro): read TIME, BLOB, MULTISET and non-string-key map columns (apache#724)
  fix(datafusion): surface tag create-time and retention in $tags (apache#728)
  [core] Support multivalue global index (apache#731)
  feat: add Java-compatible array predicate pushdown (apache#732)
  fix: serialize unbounded varchar as string (apache#730)
  perf(vindex): decouple vector read threads and remove chunk barrier (apache#720)
  feat(vindex): add DiskANN and IVF-SQ/RQ support (apache#726)

# Conflicts:
#	crates/paimon/src/table/data_file_reader.rs
#	crates/paimon/src/table/vindex_index_build_builder.rs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants