Skip to content
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

Account already downloaded data when resetting a prefetcher #797

Merged
merged 7 commits into from
Mar 7, 2024

Conversation

vladem
Copy link
Contributor

@vladem vladem commented Mar 4, 2024

Description of change

This is a development if an idea from this PR: #795

The idea is to avoid discarding prefetched data if it is already downloaded. This optimises a certain read pattern, which reads data sequentially but skips chunks between reads.

Here is some benchmarking with fio job included in the pr (no cache usage, remounted in between fio invocations):

# MP built from main
$ fio --directory=/home/vlaad/mounted_s3 /home/vlaad/local/mountpoint-s3/mountpoint-s3/scripts/fio/read/seq_read_skip_read.fio | grep "bw="
  read : io=5888.0MB, bw=20035KB/s, iops=0, runt=300944msec
$ !!
  read : io=5888.0MB, bw=19642KB/s, iops=0, runt=306958msec
$ !!
  read : io=6400.0MB, bw=20691KB/s, iops=0, runt=316740msec
# MP built from this branch 
$ fio --directory=/home/vlaad/mounted_s3 /home/vlaad/local/mountpoint-s3/mountpoint-s3/scripts/fio/read/seq_read_skip_read.fio
  read : io=47616MB, bw=160757KB/s, iops=0, runt=303308msec
$ !!
  read : io=41728MB, bw=142388KB/s, iops=0, runt=300092msec
$ !!
  read : io=51712MB, bw=172735KB/s, iops=0, runt=306557msec

upd. updated benchmark results with longer runtime 300s and larger file 10gb, lowest observed improvement is 6.8x

Relevant issues: No

Does this change impact existing behavior?

This is not a functional change and thus not a breaking one. We should reason about possible performance regressions in certain read patterns before merging.


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and I agree to the terms of the Developer Certificate of Origin (DCO).

@vladem vladem temporarily deployed to PR integration tests March 4, 2024 20:27 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 4, 2024 20:27 — with GitHub Actions Inactive
@vladem vladem had a problem deploying to PR integration tests March 4, 2024 20:27 — with GitHub Actions Failure
@vladem vladem temporarily deployed to PR integration tests March 4, 2024 20:27 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 4, 2024 20:27 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 4, 2024 20:27 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 4, 2024 20:27 — with GitHub Actions Inactive
Copy link
Member

@jamesbornholt jamesbornholt left a comment

Choose a reason for hiding this comment

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

I like this idea better than #795. Just a couple notes.

mountpoint-s3/src/prefetch.rs Outdated Show resolved Hide resolved
mountpoint-s3/src/prefetch/part_queue.rs Outdated Show resolved Hide resolved
Signed-off-by: Vladislav Volodkin <[email protected]>
@vladem vladem force-pushed the optimize-read-skip-read branch from 4a302da to 451b2a2 Compare March 5, 2024 15:51
@vladem vladem temporarily deployed to PR integration tests March 5, 2024 15:51 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 5, 2024 15:51 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 5, 2024 15:51 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 5, 2024 15:51 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 5, 2024 15:51 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 5, 2024 15:51 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 5, 2024 15:51 — with GitHub Actions Inactive
let part_queue = PartQueue {
current_part: AsyncMutex::new(None),
receiver,
failed: AtomicBool::new(false),
downloaded: Arc::clone(&downloaded),
bytes_arrived_total: Arc::clone(&bytes_counter),
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: maybe bytes_received?

Copy link
Contributor Author

@vladem vladem Mar 5, 2024

Choose a reason for hiding this comment

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

well, I put some thinking in that tbh! bytes_received may be misleading because of PartQueue.receiver, which may imply that those bytes were received (i.e read through receiver), but what it actually tracks is the number of bytes arrived to the queue (which may also not have the clearest meaning, naming is complicated)

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, they are the bytes received by the receiver, so it still sounds good to be. I'd rather clarify in the rustdoc than add a different name.

Copy link
Member

Choose a reason for hiding this comment

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

I liked bytes_downloaded, but also not worth bikeshedding over the name.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll replace with bytes_received, may be not completely accurate, but symmetrical to the sending part and there is a comment with a clarification

// it. Otherwise, we're willing to wait for the bytes to download only if they're coming "soon", where
// soon is defined as up to `max_forward_seek_distance` bytes ahead of the available offset.
let available_offset = current_task.available_offset();
if offset > available_offset.saturating_add(self.config.max_forward_seek_distance) {
Copy link
Contributor

Choose a reason for hiding this comment

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

max_forward_seek_distance is now the maximum number of bytes we are happy to wait to be downloaded when seeking forward. Can we think of a more appropriate name?

Copy link
Member

Choose a reason for hiding this comment

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

max_forward_seek_wait_distance?

Also, there's a subtle thing here that it doesn't matter if available_offset + max_forward_seek_wait_distance > current_task.end_offset(), because the loop above guarantees that the offset lands within this task in the loop above. Maybe worth a comment on the line above this one that selects current_task?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh, yeah, not regarding this particular line, but I also thought about the case when offset is beyond the last task's range, I'll add a comment and will try to add a test (if possible without too much hacks)

max_forward_seek_wait_distance looks good to me, can not think about anything less wordy

Copy link
Member

@jamesbornholt jamesbornholt left a comment

Choose a reason for hiding this comment

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

Yeah I like this. We should think about how we want metrics for the prefetcher to work now, but let's do that in a separate PR.

// it. Otherwise, we're willing to wait for the bytes to download only if they're coming "soon", where
// soon is defined as up to `max_forward_seek_distance` bytes ahead of the available offset.
let available_offset = current_task.available_offset();
if offset > available_offset.saturating_add(self.config.max_forward_seek_distance) {
Copy link
Member

Choose a reason for hiding this comment

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

max_forward_seek_wait_distance?

Also, there's a subtle thing here that it doesn't matter if available_offset + max_forward_seek_wait_distance > current_task.end_offset(), because the loop above guarantees that the offset lands within this task in the loop above. Maybe worth a comment on the line above this one that selects current_task?

mountpoint-s3/src/prefetch/part_queue.rs Outdated Show resolved Hide resolved
mountpoint-s3/src/prefetch/part_queue.rs Outdated Show resolved Hide resolved
let part_queue = PartQueue {
current_part: AsyncMutex::new(None),
receiver,
failed: AtomicBool::new(false),
downloaded: Arc::clone(&downloaded),
bytes_arrived_total: Arc::clone(&bytes_counter),
Copy link
Member

Choose a reason for hiding this comment

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

I liked bytes_downloaded, but also not worth bikeshedding over the name.

mountpoint-s3/src/prefetch/part_queue.rs Outdated Show resolved Hide resolved
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 18:21 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 18:21 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 18:21 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 18:21 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 18:21 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 18:21 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 18:21 — with GitHub Actions Inactive
@vladem vladem marked this pull request as ready for review March 6, 2024 18:22
Signed-off-by: Vladislav Volodkin <[email protected]>
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 18:38 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 18:38 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 18:38 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 18:38 — with GitHub Actions Inactive
@vladem vladem had a problem deploying to PR integration tests March 6, 2024 18:38 — with GitHub Actions Failure
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 18:38 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 18:38 — with GitHub Actions Inactive
@vladem vladem requested a review from passaro March 6, 2024 18:39
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 20:03 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 20:03 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 20:03 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 20:03 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 20:03 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 20:03 — with GitHub Actions Inactive
@vladem vladem temporarily deployed to PR integration tests March 6, 2024 20:03 — with GitHub Actions Inactive
let send_result = self.sender.send_blocking(part);
if let Some(part_size) = part_size {
self.bytes_sent.fetch_add(part_size, Ordering::SeqCst);
if let Ok(ref part) = part {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: you can also use:

Suggested change
if let Ok(ref part) = part {
if let Ok(part) = &part {

@jamesbornholt jamesbornholt added this pull request to the merge queue Mar 7, 2024
Merged via the queue into awslabs:main with commit 896c6d3 Mar 7, 2024
25 checks passed
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