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

Specialize io::copy for BufRead sources #71091

Closed
wants to merge 4 commits into from
Closed

Conversation

main--
Copy link
Contributor

@main-- main-- commented Apr 13, 2020

Allocating an additional buffer and then copying through it is completely unnecessary if the source we're copying from is BufRead (i.e. already maintains a buffer internally). Using specialization, we can detect this and handle it accordingly.

Note that this also makes it possible to specify a custom buffer size for copy operations by wrapping the source in a BufReader::with_capacity. This might fix #49921.

Here's why this is better:

io::copy 1GB: 64.019007ms
specialized copy 1GB: 63.741937ms
specialized copy 1GB with bigger buffer: 27.649244ms
io::copy 1GB BufRead: 124.040431ms
specialized copy 1GB BufRead: 688ns

I know this benchmark is unfair, but that's basically the point.

fn main() {
    // don't want to use std::io::sink() here because we don't want anything to get optimized out
    let mut null = File::create("/dev/null").unwrap();
    
    let now = Instant::now();
    io::copy(&mut io::repeat(42).take(1024 * 1024 * 1024), &mut null).unwrap();
    println!("io::copy 1GB: {:?}", now.elapsed());

    let now = Instant::now();
    copy(&mut io::repeat(42).take(1024 * 1024 * 1024), &mut null).unwrap();
    println!("specialized copy 1GB: {:?}", now.elapsed());
    
    let now = Instant::now();
    copy(&mut BufReader::with_capacity(64 * 1024, io::repeat(42).take(1024 * 1024 * 1024)), &mut null).unwrap();
    println!("specialized copy 1GB with bigger buffer: {:?}", now.elapsed());
    
    let testdata = vec![42u8; 1024 * 1024 * 1024];

    let now = Instant::now();
    io::copy(&mut testdata.as_slice(), &mut null).unwrap();
    println!("io::copy 1GB BufRead: {:?}", now.elapsed());

    let now = Instant::now();
    copy(&mut testdata.as_slice(), &mut null).unwrap();
    println!("specialized copy 1GB BufRead: {:?}", now.elapsed());
}

Allocating an additional buffer and then copying through it is completely unnecessary if the source we're copying from is BufRead (i.e. already maintains a buffer internally). Using specialization, we can detect this and handle it accordingly.

Note that this also makes it possible to specify a custom buffer size for copy operations by wrapping the source in a BufReader::with_capacity.
@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @Mark-Simulacrum (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Apr 13, 2020
@rust-highfive
Copy link
Collaborator

The job mingw-check of your PR failed (pretty log, raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
2020-04-13T10:51:28.2124697Z ========================== Starting Command Output ===========================
2020-04-13T10:51:28.2127277Z [command]/bin/bash --noprofile --norc /home/vsts/work/_temp/aff11ae5-9937-4f23-a438-c1afa590af65.sh
2020-04-13T10:51:28.2127547Z 
2020-04-13T10:51:28.2130823Z ##[section]Finishing: Disable git automatic line ending conversion
2020-04-13T10:51:28.2150218Z ##[section]Starting: Checkout rust-lang/rust@refs/pull/71091/merge to s
2020-04-13T10:51:28.2153671Z Task         : Get sources
2020-04-13T10:51:28.2153956Z Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
2020-04-13T10:51:28.2154232Z Version      : 1.0.0
2020-04-13T10:51:28.2154554Z Author       : Microsoft
---
2020-04-13T10:51:29.2148717Z ##[command]git remote add origin https://github.com/rust-lang/rust
2020-04-13T10:51:29.2153582Z ##[command]git config gc.auto 0
2020-04-13T10:51:29.2157028Z ##[command]git config --get-all http.https://github.com/rust-lang/rust.extraheader
2020-04-13T10:51:29.2160928Z ##[command]git config --get-all http.proxy
2020-04-13T10:51:29.2167137Z ##[command]git -c http.extraheader="AUTHORIZATION: basic ***" fetch --force --tags --prune --progress --no-recurse-submodules --depth=2 origin +refs/heads/*:refs/remotes/origin/* +refs/pull/71091/merge:refs/remotes/pull/71091/merge
---
2020-04-13T10:54:08.5988920Z  ---> 78ad2f4d4aca
2020-04-13T10:54:08.5989441Z Step 6/7 : ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
2020-04-13T10:54:08.5996624Z  ---> Using cache
2020-04-13T10:54:08.5997695Z  ---> 4d2dc61c4d00
2020-04-13T10:54:08.6000575Z Step 7/7 : ENV SCRIPT python3 ../x.py test src/tools/expand-yaml-anchors &&            python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu &&            python3 ../x.py build --stage 0 src/tools/build-manifest &&            python3 ../x.py test --stage 0 src/tools/compiletest &&            python3 ../x.py test src/tools/tidy &&            /scripts/validate-toolstate.sh
2020-04-13T10:54:08.6002752Z  ---> 776b6266a8b7
2020-04-13T10:54:08.6091886Z Successfully built 776b6266a8b7
2020-04-13T10:54:08.6121602Z Successfully tagged rust-ci:latest
2020-04-13T10:54:08.6434835Z Built container sha256:776b6266a8b7d63e2d3c2b5a784dbf521184a904fb10bf818c6b5c7e1ab74d4a
2020-04-13T10:54:08.6434835Z Built container sha256:776b6266a8b7d63e2d3c2b5a784dbf521184a904fb10bf818c6b5c7e1ab74d4a
2020-04-13T10:54:08.6452104Z Looks like docker image is the same as before, not uploading
2020-04-13T10:54:09.3079822Z [CI_JOB_NAME=mingw-check]
2020-04-13T10:54:09.3386407Z [CI_JOB_NAME=mingw-check]
2020-04-13T10:54:09.3421265Z == clock drift check ==
2020-04-13T10:54:09.3431800Z   local time: Mon Apr 13 10:54:09 UTC 2020
2020-04-13T10:54:09.6248802Z   network time: Mon, 13 Apr 2020 10:54:09 GMT
2020-04-13T10:54:09.6273837Z Starting sccache server...
2020-04-13T10:54:09.7491855Z configure: processing command line
2020-04-13T10:54:09.7492198Z configure: 
2020-04-13T10:54:09.7493214Z configure: rust.parallel-compiler := True
---
2020-04-13T10:58:07.8955041Z     Checking rustc_feature v0.0.0 (/checkout/src/librustc_feature)
2020-04-13T10:58:08.0207689Z     Checking fmt_macros v0.0.0 (/checkout/src/libfmt_macros)
2020-04-13T10:58:08.2281785Z     Checking rustc_ast_pretty v0.0.0 (/checkout/src/librustc_ast_pretty)
2020-04-13T10:58:08.3321516Z     Checking rustc_hir v0.0.0 (/checkout/src/librustc_hir)
2020-04-13T10:58:08.9057325Z     Checking rustc_query_system v0.0.0 (/checkout/src/librustc_query_system)
2020-04-13T10:58:11.4547159Z     Checking rustc_attr v0.0.0 (/checkout/src/librustc_attr)
2020-04-13T10:58:11.9724018Z     Checking rustc_parse v0.0.0 (/checkout/src/librustc_parse)
2020-04-13T10:58:14.2151306Z     Checking rustc_hir_pretty v0.0.0 (/checkout/src/librustc_hir_pretty)
2020-04-13T10:58:14.6861179Z     Checking rustc_ast_lowering v0.0.0 (/checkout/src/librustc_ast_lowering)
---
2020-04-13T11:00:08.4149673Z configure: rust.channel         := nightly
2020-04-13T11:00:08.4149998Z configure: llvm.assertions      := True
2020-04-13T11:00:08.4150524Z configure: dist.missing-tools   := True
2020-04-13T11:00:08.4151028Z configure: rust.dist-src        := False
2020-04-13T11:00:08.4151959Z configure: build.configure-args := ['--enable-sccache', '--disable-manage-submodu ...
2020-04-13T11:00:08.4152597Z configure: writing `config.toml` in current directory
2020-04-13T11:00:08.4152862Z configure: 
2020-04-13T11:00:08.4153324Z configure: run `python /checkout/x.py --help`
2020-04-13T11:00:08.4153576Z configure: 
---
2020-04-13T11:01:46.0539061Z Hugepagesize:       2048 kB
2020-04-13T11:01:46.0539309Z DirectMap4k:      131008 kB
2020-04-13T11:01:46.0539626Z DirectMap2M:     3014656 kB
2020-04-13T11:01:46.0539880Z DirectMap1G:     6291456 kB
2020-04-13T11:01:46.0558991Z + python3 ../x.py test src/tools/expand-yaml-anchors
2020-04-13T11:01:47.5130669Z Ensuring the YAML anchors in the GitHub Actions config were expanded
2020-04-13T11:01:47.5130669Z Ensuring the YAML anchors in the GitHub Actions config were expanded
2020-04-13T11:01:47.5138970Z Building stage0 tool expand-yaml-anchors (x86_64-unknown-linux-gnu)
2020-04-13T11:01:47.7744335Z    Compiling unicode-xid v0.2.0
2020-04-13T11:01:47.9116196Z    Compiling syn v1.0.11
2020-04-13T11:01:48.8004975Z    Compiling linked-hash-map v0.5.2
2020-04-13T11:01:48.8700258Z    Compiling lazy_static v1.4.0
2020-04-13T11:01:48.8700258Z    Compiling lazy_static v1.4.0
2020-04-13T11:01:49.0498171Z    Compiling yaml-rust v0.4.3
2020-04-13T11:01:53.6752718Z    Compiling quote v1.0.2
2020-04-13T11:02:09.4543427Z    Compiling thiserror-impl v1.0.5
2020-04-13T11:02:14.6364679Z    Compiling thiserror v1.0.5
2020-04-13T11:02:14.6967956Z    Compiling yaml-merge-keys v0.4.0
2020-04-13T11:02:16.0072536Z    Compiling expand-yaml-anchors v0.1.0 (/checkout/src/tools/expand-yaml-anchors)
2020-04-13T11:02:18.3224805Z Build completed successfully in 0:00:32
2020-04-13T11:02:18.3347270Z + python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu
2020-04-13T11:02:18.6399859Z     Finished dev [unoptimized] target(s) in 0.20s
2020-04-13T11:02:19.8980882Z Checking rustdoc artifacts (x86_64-unknown-linux-gnu -> i686-pc-windows-gnu)
---
2020-04-13T11:04:36.1676745Z     Checking rustc_feature v0.0.0 (/checkout/src/librustc_feature)
2020-04-13T11:04:36.2882828Z     Checking fmt_macros v0.0.0 (/checkout/src/libfmt_macros)
2020-04-13T11:04:36.4933458Z     Checking rustc_ast_pretty v0.0.0 (/checkout/src/librustc_ast_pretty)
2020-04-13T11:04:36.6266854Z     Checking rustc_hir v0.0.0 (/checkout/src/librustc_hir)
2020-04-13T11:04:37.1541243Z     Checking rustc_query_system v0.0.0 (/checkout/src/librustc_query_system)
2020-04-13T11:04:39.5495744Z     Checking rustc_attr v0.0.0 (/checkout/src/librustc_attr)
2020-04-13T11:04:40.0544361Z     Checking rustc_parse v0.0.0 (/checkout/src/librustc_parse)
2020-04-13T11:04:42.3057121Z     Checking rustc_hir_pretty v0.0.0 (/checkout/src/librustc_hir_pretty)
2020-04-13T11:04:42.7961325Z     Checking rustc_ast_lowering v0.0.0 (/checkout/src/librustc_ast_lowering)
---
2020-04-13T11:09:03.3728861Z skip untracked path cpu-usage.csv during rustfmt invocations
2020-04-13T11:09:03.3736399Z skip untracked path src/doc/book/ during rustfmt invocations
2020-04-13T11:09:03.3738132Z skip untracked path src/doc/rust-by-example/ during rustfmt invocations
2020-04-13T11:09:03.3742384Z skip untracked path src/llvm-project/ during rustfmt invocations
2020-04-13T11:09:06.0707150Z Diff in /checkout/src/libstd/io/util.rs at line 4:
2020-04-13T11:09:06.0712680Z  use crate::io::{self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Write};
2020-04-13T11:09:06.0722466Z  mod copy_specialization {
2020-04-13T11:09:06.0722466Z  mod copy_specialization {
2020-04-13T11:09:06.0727359Z +    use crate::io::{self, BufRead, ErrorKind, Read, Write};
2020-04-13T11:09:06.0760347Z -    use crate::io::{self, Read, BufRead, Write, ErrorKind};
2020-04-13T11:09:06.0760609Z  
2020-04-13T11:09:06.0760777Z      pub trait Copyable {
2020-04-13T11:09:06.0760777Z      pub trait Copyable {
2020-04-13T11:09:06.0761385Z          fn copy_to<W: ?Sized + Write>(&mut self, writer: &mut W) -> io::Result<u64>;
2020-04-13T11:09:06.0762529Z Running `"/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/rustfmt" "--config-path" "/checkout" "--edition" "2018" "--unstable-features" "--skip-children" "--check" "/checkout/src/libstd/io/util.rs"` failed.
2020-04-13T11:09:06.0766028Z If you're running `tidy`, try again with `--bless` flag. Or, you just want to format code, run `./x.py fmt` instead.
2020-04-13T11:09:06.0767308Z Build completed unsuccessfully in 0:00:41
2020-04-13T11:09:06.0864009Z == clock drift check ==
2020-04-13T11:09:06.0879334Z   local time: Mon Apr 13 11:09:06 UTC 2020
2020-04-13T11:09:06.0879334Z   local time: Mon Apr 13 11:09:06 UTC 2020
2020-04-13T11:09:06.2740461Z   network time: Mon, 13 Apr 2020 11:09:06 GMT
2020-04-13T11:09:07.9883568Z 
2020-04-13T11:09:07.9883568Z 
2020-04-13T11:09:07.9998991Z ##[error]Bash exited with code '1'.
2020-04-13T11:09:08.0019026Z ##[section]Finishing: Run build
2020-04-13T11:09:08.0093241Z ##[section]Starting: Checkout rust-lang/rust@refs/pull/71091/merge to s
2020-04-13T11:09:08.0098416Z Task         : Get sources
2020-04-13T11:09:08.0098743Z Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
2020-04-13T11:09:08.0099042Z Version      : 1.0.0
2020-04-13T11:09:08.0099267Z Author       : Microsoft
2020-04-13T11:09:08.0099267Z Author       : Microsoft
2020-04-13T11:09:08.0099761Z Help         : [More Information](https://go.microsoft.com/fwlink/?LinkId=798199)
2020-04-13T11:09:08.0100146Z ==============================================================================
2020-04-13T11:09:08.3945180Z Cleaning any cached credential from repository: rust-lang/rust (GitHub)
2020-04-13T11:09:08.4041152Z ##[section]Finishing: Checkout rust-lang/rust@refs/pull/71091/merge to s
2020-04-13T11:09:08.4128914Z Cleaning up task key
2020-04-13T11:09:08.4130139Z Start cleaning up orphan processes.
2020-04-13T11:09:08.4348441Z Terminate orphan process: pid (3477) (python)
2020-04-13T11:09:08.4529810Z ##[section]Finishing: Finalize Job

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @rust-lang/infra. (Feature Requests)

@rust-highfive
Copy link
Collaborator

The job mingw-check of your PR failed (pretty log, raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
2020-04-14T10:44:28.8898791Z ========================== Starting Command Output ===========================
2020-04-14T10:44:28.8902261Z [command]/bin/bash --noprofile --norc /home/vsts/work/_temp/b3c9809d-8689-4265-9c65-ef8374930783.sh
2020-04-14T10:44:28.8902750Z 
2020-04-14T10:44:28.8910500Z ##[section]Finishing: Disable git automatic line ending conversion
2020-04-14T10:44:28.8927522Z ##[section]Starting: Checkout rust-lang/rust@refs/pull/71091/merge to s
2020-04-14T10:44:28.8930122Z Task         : Get sources
2020-04-14T10:44:28.8930331Z Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
2020-04-14T10:44:28.8930535Z Version      : 1.0.0
2020-04-14T10:44:28.8930719Z Author       : Microsoft
---
2020-04-14T10:44:30.1287918Z ##[command]git remote add origin https://github.com/rust-lang/rust
2020-04-14T10:44:30.1296357Z ##[command]git config gc.auto 0
2020-04-14T10:44:30.1301718Z ##[command]git config --get-all http.https://github.com/rust-lang/rust.extraheader
2020-04-14T10:44:30.1309466Z ##[command]git config --get-all http.proxy
2020-04-14T10:44:30.1320550Z ##[command]git -c http.extraheader="AUTHORIZATION: basic ***" fetch --force --tags --prune --progress --no-recurse-submodules --depth=2 origin +refs/heads/*:refs/remotes/origin/* +refs/pull/71091/merge:refs/remotes/pull/71091/merge
---
2020-04-14T10:46:28.1798451Z  ---> 78ad2f4d4aca
2020-04-14T10:46:28.1798629Z Step 6/7 : ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
2020-04-14T10:46:28.1803095Z  ---> Using cache
2020-04-14T10:46:28.1803583Z  ---> 4d2dc61c4d00
2020-04-14T10:46:28.1804558Z Step 7/7 : ENV SCRIPT python3 ../x.py test src/tools/expand-yaml-anchors &&            python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu &&            python3 ../x.py build --stage 0 src/tools/build-manifest &&            python3 ../x.py test --stage 0 src/tools/compiletest &&            python3 ../x.py test src/tools/tidy &&            /scripts/validate-toolstate.sh
2020-04-14T10:46:28.1811186Z  ---> 776b6266a8b7
2020-04-14T10:46:28.1846306Z Successfully built 776b6266a8b7
2020-04-14T10:46:28.1885586Z Successfully tagged rust-ci:latest
2020-04-14T10:46:28.2121638Z Built container sha256:776b6266a8b7d63e2d3c2b5a784dbf521184a904fb10bf818c6b5c7e1ab74d4a
2020-04-14T10:46:28.2121638Z Built container sha256:776b6266a8b7d63e2d3c2b5a784dbf521184a904fb10bf818c6b5c7e1ab74d4a
2020-04-14T10:46:28.2140422Z Looks like docker image is the same as before, not uploading
2020-04-14T10:46:36.2182177Z [CI_JOB_NAME=mingw-check]
2020-04-14T10:46:36.2396950Z [CI_JOB_NAME=mingw-check]
2020-04-14T10:46:36.2430497Z == clock drift check ==
2020-04-14T10:46:36.2441926Z   local time: Tue Apr 14 10:46:36 UTC 2020
2020-04-14T10:46:36.5384002Z   network time: Tue, 14 Apr 2020 10:46:36 GMT
2020-04-14T10:46:36.5407218Z Starting sccache server...
2020-04-14T10:46:36.6426780Z configure: processing command line
2020-04-14T10:46:36.6427702Z configure: 
2020-04-14T10:46:36.6429585Z configure: rust.parallel-compiler := True
---
2020-04-14T10:50:07.5159778Z     Checking rustc_span v0.0.0 (/checkout/src/librustc_span)
2020-04-14T10:50:11.7054547Z     Checking rustc_errors v0.0.0 (/checkout/src/librustc_errors)
2020-04-14T10:50:12.8755044Z     Checking rustc_feature v0.0.0 (/checkout/src/librustc_feature)
2020-04-14T10:50:12.9206781Z     Checking fmt_macros v0.0.0 (/checkout/src/libfmt_macros)
2020-04-14T10:50:13.1163144Z     Checking rustc_query_system v0.0.0 (/checkout/src/librustc_query_system)
2020-04-14T10:50:13.8751224Z     Checking rustc_hir v0.0.0 (/checkout/src/librustc_hir)
2020-04-14T10:50:13.9181797Z     Checking rustc_session v0.0.0 (/checkout/src/librustc_session)
2020-04-14T10:50:15.3050096Z     Checking rustc_attr v0.0.0 (/checkout/src/librustc_attr)
2020-04-14T10:50:15.7967100Z     Checking rustc_parse v0.0.0 (/checkout/src/librustc_parse)
---
2020-04-14T10:52:03.3361000Z configure: build.submodules     := False
2020-04-14T10:52:03.3361226Z configure: llvm.ccache          := sccache
2020-04-14T10:52:03.3361476Z configure: rust.channel         := nightly
2020-04-14T10:52:03.3361842Z configure: build.locked-deps    := True
2020-04-14T10:52:03.3362301Z configure: build.configure-args := ['--enable-sccache', '--disable-manage-submodu ...
2020-04-14T10:52:03.3362744Z configure: writing `config.toml` in current directory
2020-04-14T10:52:03.3362928Z configure: 
2020-04-14T10:52:03.3363264Z configure: run `python /checkout/x.py --help`
2020-04-14T10:52:03.3363439Z configure: 
---
2020-04-14T10:53:31.6610120Z Hugepagesize:       2048 kB
2020-04-14T10:53:31.6610291Z DirectMap4k:      112576 kB
2020-04-14T10:53:31.6610477Z DirectMap2M:     4081664 kB
2020-04-14T10:53:31.6610638Z DirectMap1G:     5242880 kB
2020-04-14T10:53:31.6611327Z + python3 ../x.py test src/tools/expand-yaml-anchors
2020-04-14T10:53:32.9699904Z Ensuring the YAML anchors in the GitHub Actions config were expanded
2020-04-14T10:53:32.9699904Z Ensuring the YAML anchors in the GitHub Actions config were expanded
2020-04-14T10:53:32.9708565Z Building stage0 tool expand-yaml-anchors (x86_64-unknown-linux-gnu)
2020-04-14T10:53:33.2080750Z    Compiling unicode-xid v0.2.0
2020-04-14T10:53:33.3395030Z    Compiling syn v1.0.11
2020-04-14T10:53:34.1598701Z    Compiling linked-hash-map v0.5.2
2020-04-14T10:53:34.2004375Z    Compiling lazy_static v1.4.0
2020-04-14T10:53:34.2004375Z    Compiling lazy_static v1.4.0
2020-04-14T10:53:34.3889293Z    Compiling yaml-rust v0.4.3
2020-04-14T10:53:38.5604503Z    Compiling quote v1.0.2
2020-04-14T10:53:52.5411873Z    Compiling thiserror-impl v1.0.5
2020-04-14T10:53:57.1627433Z    Compiling thiserror v1.0.5
2020-04-14T10:53:57.2161480Z    Compiling yaml-merge-keys v0.4.0
2020-04-14T10:53:58.3115598Z    Compiling expand-yaml-anchors v0.1.0 (/checkout/src/tools/expand-yaml-anchors)
2020-04-14T10:54:01.4416371Z Build completed successfully in 0:00:29
2020-04-14T10:54:01.4553876Z + python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu
2020-04-14T10:54:01.7485048Z     Finished dev [unoptimized] target(s) in 0.18s
2020-04-14T10:54:02.7813311Z Checking rustdoc artifacts (x86_64-unknown-linux-gnu -> i686-pc-windows-gnu)
---
2020-04-14T10:56:02.5786909Z     Checking rustc_span v0.0.0 (/checkout/src/librustc_span)
2020-04-14T10:56:07.1386784Z     Checking rustc_errors v0.0.0 (/checkout/src/librustc_errors)
2020-04-14T10:56:08.3965772Z     Checking rustc_feature v0.0.0 (/checkout/src/librustc_feature)
2020-04-14T10:56:08.4047175Z     Checking fmt_macros v0.0.0 (/checkout/src/libfmt_macros)
2020-04-14T10:56:08.5911209Z     Checking rustc_query_system v0.0.0 (/checkout/src/librustc_query_system)
2020-04-14T10:56:09.3091517Z     Checking rustc_hir v0.0.0 (/checkout/src/librustc_hir)
2020-04-14T10:56:09.4253236Z     Checking rustc_session v0.0.0 (/checkout/src/librustc_session)
2020-04-14T10:56:10.9291017Z     Checking rustc_attr v0.0.0 (/checkout/src/librustc_attr)
2020-04-14T10:56:11.4335313Z     Checking rustc_parse v0.0.0 (/checkout/src/librustc_parse)
---
2020-04-14T11:00:15.1822374Z skip untracked path cpu-usage.csv during rustfmt invocations
2020-04-14T11:00:15.1825925Z skip untracked path src/doc/book/ during rustfmt invocations
2020-04-14T11:00:15.1826915Z skip untracked path src/doc/rust-by-example/ during rustfmt invocations
2020-04-14T11:00:15.1830467Z skip untracked path src/llvm-project/ during rustfmt invocations
2020-04-14T11:00:19.5767187Z Diff in /checkout/src/libstd/io/util.rs at line 4:
2020-04-14T11:00:19.5772962Z  use crate::io::{self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Write};
2020-04-14T11:00:19.5783913Z  mod copy_specialization {
2020-04-14T11:00:19.5797423Z -    use crate::mem::MaybeUninit;
2020-04-14T11:00:19.5797423Z -    use crate::mem::MaybeUninit;
2020-04-14T11:00:19.5810626Z      use crate::io::{self, BufRead, ErrorKind, Read, Write};
2020-04-14T11:00:19.5811818Z  
2020-04-14T11:00:19.5811979Z      pub trait Copyable {
2020-04-14T11:00:19.5811979Z      pub trait Copyable {
2020-04-14T11:00:19.5812745Z          fn copy_to<W: ?Sized + Write>(&mut self, writer: &mut W) -> io::Result<u64>;
2020-04-14T11:00:19.5831064Z Running `"/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/rustfmt" "--config-path" "/checkout" "--edition" "2018" "--unstable-features" "--skip-children" "--check" "/checkout/src/libstd/io/util.rs"` failed.
2020-04-14T11:00:19.5832010Z If you're running `tidy`, try again with `--bless` flag. Or, you just want to format code, run `./x.py fmt` instead.
2020-04-14T11:00:19.5839480Z Build completed unsuccessfully in 0:00:40
2020-04-14T11:00:19.5954740Z == clock drift check ==
2020-04-14T11:00:19.5954740Z == clock drift check ==
2020-04-14T11:00:19.5973328Z   local time: Tue Apr 14 11:00:19 UTC 2020
2020-04-14T11:00:19.7045756Z   network time: Tue, 14 Apr 2020 11:00:19 GMT
2020-04-14T11:00:21.1966558Z 
2020-04-14T11:00:21.1966558Z 
2020-04-14T11:00:21.2041353Z ##[error]Bash exited with code '1'.
2020-04-14T11:00:21.2055441Z ##[section]Finishing: Run build
2020-04-14T11:00:21.2098462Z ##[section]Starting: Checkout rust-lang/rust@refs/pull/71091/merge to s
2020-04-14T11:00:21.2103183Z Task         : Get sources
2020-04-14T11:00:21.2103460Z Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
2020-04-14T11:00:21.2103695Z Version      : 1.0.0
2020-04-14T11:00:21.2103863Z Author       : Microsoft
2020-04-14T11:00:21.2103863Z Author       : Microsoft
2020-04-14T11:00:21.2104146Z Help         : [More Information](https://go.microsoft.com/fwlink/?LinkId=798199)
2020-04-14T11:00:21.2104447Z ==============================================================================
2020-04-14T11:00:21.5465527Z Cleaning any cached credential from repository: rust-lang/rust (GitHub)
2020-04-14T11:00:21.5512407Z ##[section]Finishing: Checkout rust-lang/rust@refs/pull/71091/merge to s
2020-04-14T11:00:21.5613824Z Cleaning up task key
2020-04-14T11:00:21.5615108Z Start cleaning up orphan processes.
2020-04-14T11:00:21.5808196Z Terminate orphan process: pid (5799) (python)
2020-04-14T11:00:21.6024433Z ##[section]Finishing: Finalize Job

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @rust-lang/infra. (Feature Requests)

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-7 of your PR failed (pretty log, raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
2020-04-14T15:20:54.0028074Z ========================== Starting Command Output ===========================
2020-04-14T15:20:54.0030685Z [command]/bin/bash --noprofile --norc /home/vsts/work/_temp/ad9c2e5e-abdf-4399-be4c-f7aa00b3a52c.sh
2020-04-14T15:20:54.0031058Z 
2020-04-14T15:20:54.0034576Z ##[section]Finishing: Disable git automatic line ending conversion
2020-04-14T15:20:54.0050833Z ##[section]Starting: Checkout rust-lang/rust@refs/pull/71091/merge to s
2020-04-14T15:20:54.0053919Z Task         : Get sources
2020-04-14T15:20:54.0054176Z Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
2020-04-14T15:20:54.0054446Z Version      : 1.0.0
2020-04-14T15:20:54.0054616Z Author       : Microsoft
---
2020-04-14T15:20:54.9953488Z ##[command]git remote add origin https://github.com/rust-lang/rust
2020-04-14T15:20:54.9959063Z ##[command]git config gc.auto 0
2020-04-14T15:20:54.9962568Z ##[command]git config --get-all http.https://github.com/rust-lang/rust.extraheader
2020-04-14T15:20:54.9965779Z ##[command]git config --get-all http.proxy
2020-04-14T15:20:54.9971476Z ##[command]git -c http.extraheader="AUTHORIZATION: basic ***" fetch --force --tags --prune --progress --no-recurse-submodules --depth=2 origin +refs/heads/*:refs/remotes/origin/* +refs/pull/71091/merge:refs/remotes/pull/71091/merge
---
2020-04-14T15:23:25.8772010Z  ---> f58a2bb1e753
2020-04-14T15:23:25.8774105Z Step 5/8 : ENV RUST_CONFIGURE_ARGS       --build=x86_64-unknown-linux-gnu       --llvm-root=/usr/lib/llvm-7       --enable-llvm-link-shared       --set rust.thin-lto-import-instr-limit=10
2020-04-14T15:23:25.8776055Z  ---> Using cache
2020-04-14T15:23:25.8776485Z  ---> d079cc6b6db8
2020-04-14T15:23:25.8777411Z Step 6/8 : ENV SCRIPT python2.7 ../x.py test --exclude src/tools/tidy &&            python2.7 ../x.py test src/test/mir-opt --pass=build                                   --target=armv5te-unknown-linux-gnueabi &&            python2.7 ../x.py test src/tools/tidy
2020-04-14T15:23:25.8778602Z  ---> 4183ca46ee56
2020-04-14T15:23:25.8778915Z Step 7/8 : ENV NO_DEBUG_ASSERTIONS=1
2020-04-14T15:23:25.8779347Z  ---> Using cache
2020-04-14T15:23:25.8779779Z  ---> 69e7f8a2a2fb
---
2020-04-14T15:23:25.9125430Z Looks like docker image is the same as before, not uploading
2020-04-14T15:23:32.2034624Z [CI_JOB_NAME=x86_64-gnu-llvm-7]
2020-04-14T15:23:32.2281063Z [CI_JOB_NAME=x86_64-gnu-llvm-7]
2020-04-14T15:23:32.2308983Z == clock drift check ==
2020-04-14T15:23:32.2320448Z   local time: Tue Apr 14 15:23:32 UTC 2020
2020-04-14T15:23:32.3741633Z   network time: Tue, 14 Apr 2020 15:23:32 GMT
2020-04-14T15:23:32.3776071Z Starting sccache server...
2020-04-14T15:23:32.4505625Z configure: processing command line
2020-04-14T15:23:32.4506206Z configure: 
2020-04-14T15:23:32.4507407Z configure: rust.dist-src        := False
---
2020-04-14T15:28:01.6547946Z    Compiling rustc_feature v0.0.0 (/checkout/src/librustc_feature)
2020-04-14T15:28:02.9058755Z    Compiling fmt_macros v0.0.0 (/checkout/src/libfmt_macros)
2020-04-14T15:28:04.2482400Z    Compiling rustc_ast_pretty v0.0.0 (/checkout/src/librustc_ast_pretty)
2020-04-14T15:28:04.8070017Z    Compiling rustc_hir v0.0.0 (/checkout/src/librustc_hir)
2020-04-14T15:28:12.9729555Z    Compiling rustc_query_system v0.0.0 (/checkout/src/librustc_query_system)
2020-04-14T15:28:14.5736080Z    Compiling rustc_hir_pretty v0.0.0 (/checkout/src/librustc_hir_pretty)
2020-04-14T15:28:18.3703267Z    Compiling rustc_attr v0.0.0 (/checkout/src/librustc_attr)
2020-04-14T15:28:21.9064102Z    Compiling rustc_parse v0.0.0 (/checkout/src/librustc_parse)
2020-04-14T15:28:30.7622515Z    Compiling rustc_ast_lowering v0.0.0 (/checkout/src/librustc_ast_lowering)
---
2020-04-14T15:44:49.9110306Z    Compiling panic_unwind v0.0.0 (/checkout/src/libpanic_unwind)
2020-04-14T15:44:51.1213287Z error: cannot specialize on trait `io::BufRead`
2020-04-14T15:44:51.1214726Z   --> src/libstd/io/util.rs:40:5
2020-04-14T15:44:51.1215437Z    |
2020-04-14T15:44:51.1216415Z 40 | /     impl<T: BufRead + ?Sized> Copyable for T {
2020-04-14T15:44:51.1217777Z 41 | |         fn copy_to<W: ?Sized + Write>(&mut self, writer: &mut W) -> io::Result<u64> {
2020-04-14T15:44:51.1219028Z 42 | |             let mut written = 0;
2020-04-14T15:44:51.1221051Z ...  |
2020-04-14T15:44:51.1221927Z 62 | |         }
2020-04-14T15:44:51.1222892Z 63 | |     }
2020-04-14T15:44:51.1223711Z    | |_____^
---
2020-04-14T15:44:51.1501978Z expected success, got: exit code: 101
2020-04-14T15:44:51.1514402Z failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test --exclude src/tools/tidy
2020-04-14T15:44:51.1514773Z Build completed unsuccessfully in 0:19:57
2020-04-14T15:44:51.1569519Z == clock drift check ==
2020-04-14T15:44:51.1585847Z   local time: Tue Apr 14 15:44:51 UTC 2020
2020-04-14T15:44:51.3490809Z   network time: Tue, 14 Apr 2020 15:44:51 GMT
2020-04-14T15:44:53.9111973Z 
2020-04-14T15:44:53.9111973Z 
2020-04-14T15:44:53.9170701Z ##[error]Bash exited with code '1'.
2020-04-14T15:44:53.9190292Z ##[section]Finishing: Run build
2020-04-14T15:44:53.9233807Z ##[section]Starting: Checkout rust-lang/rust@refs/pull/71091/merge to s
2020-04-14T15:44:53.9238672Z Task         : Get sources
2020-04-14T15:44:53.9238977Z Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
2020-04-14T15:44:53.9239273Z Version      : 1.0.0
2020-04-14T15:44:53.9239476Z Author       : Microsoft
2020-04-14T15:44:53.9239476Z Author       : Microsoft
2020-04-14T15:44:53.9239797Z Help         : [More Information](https://go.microsoft.com/fwlink/?LinkId=798199)
2020-04-14T15:44:53.9240171Z ==============================================================================
2020-04-14T15:44:54.2308949Z Cleaning any cached credential from repository: rust-lang/rust (GitHub)
2020-04-14T15:44:54.2361322Z ##[section]Finishing: Checkout rust-lang/rust@refs/pull/71091/merge to s
2020-04-14T15:44:54.2442652Z Cleaning up task key
2020-04-14T15:44:54.2443812Z Start cleaning up orphan processes.
2020-04-14T15:44:54.2605155Z Terminate orphan process: pid (3435) (python)
2020-04-14T15:44:54.2744513Z ##[section]Finishing: Finalize Job

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @rust-lang/infra. (Feature Requests)

@main--
Copy link
Contributor Author

main-- commented Apr 14, 2020

???

@Mark-Simulacrum
Copy link
Member

r? @matthewjasper for specialization review; it looks like BufRead is not currently within the grouping.

I think we should try and work on some documentation here :)

@main--
Copy link
Contributor Author

main-- commented Apr 16, 2020

Is this some special ruleset when compiling std? Because this exact same specialization worked fine when I tested it outside of std.

@Mark-Simulacrum
Copy link
Member

Yeah, due to unsoundness bugs with specialization, std is limited to just #![feature(min_specialization)] which is, IIRC, a "known good" subset.

@crlf0710 crlf0710 added the A-specialization Area: Trait impl specialization label Apr 24, 2020
@crlf0710 crlf0710 added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 2, 2020
@Dylan-DPC-zz
Copy link

r? @dtolnay

Copy link
Member

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

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

I am uncomfortable accepting this because it results in behavior differences that are observable outside of std (different method calls on the caller's trait impls) and can only be preserved by continuing to rely on specialization, with this not being in the sound min_specialization subset.

The optimization is good but we should defer this until specialization is in better shape.

@dtolnay dtolnay closed this May 9, 2020
@main--
Copy link
Contributor Author

main-- commented May 10, 2020

Given that this optimization is not doable without specialization, how do you propose to move forward with the underlying issue? Document it and provide an alternative like std::io::copy_bufread? It's a small piece of code, but if the standard library doesn't provide it (and doesn't educate users about the problem with std::io::copy) the result is (in some cases significant) performance degradation for no reason.

@dtolnay
Copy link
Member

dtolnay commented May 10, 2020

Quite a lot of optimizations will be made possible by specialization. It's being worked on. In the meantime a copy_bufread can be provided on crates.io for the use cases where it makes a significant difference; I don't think we need to stabilize something new for that in std in the short term.

@glandium
Copy link
Contributor

glandium commented Jun 4, 2020

How about adding a fn copy<W: Write + ?Sized>(&mut self, writer: &mut W) -> io::Result<u64> to the Read trait?

@the8472
Copy link
Member

the8472 commented Oct 28, 2020

I am uncomfortable accepting this because it results in behavior differences that are observable outside of std (different method calls on the caller's trait impls) and can only be preserved by continuing to rely on specialization, with this not being in the sound min_specialization subset.

If an approach which only requires min_specialization is possible would that be acceptable?

bors added a commit to rust-lang-ci/rust that referenced this pull request Nov 14, 2020
specialize io::copy to use copy_file_range, splice or sendfile

Fixes rust-lang#74426.
Also covers rust-lang#60689 but only as an optimization instead of an official API.

The specialization only covers std-owned structs so it should avoid the problems with rust-lang#71091

Currently linux-only but it should be generalizable to other unix systems that have sendfile/sosplice and similar.

There is a bit of optimization potential around the syscall count. Right now it may end up doing more syscalls than the naive copy loop when doing short (<8KiB) copies between file descriptors.

The test case executes the following:

```
[pid 103776] statx(3, "", AT_STATX_SYNC_AS_STAT|AT_EMPTY_PATH, STATX_ALL, {stx_mask=STATX_ALL|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0644, stx_size=17, ...}) = 0
[pid 103776] write(4, "wxyz", 4)        = 4
[pid 103776] write(4, "iklmn", 5)       = 5
[pid 103776] copy_file_range(3, NULL, 4, NULL, 5, 0) = 5

```

0-1 `stat` calls to identify the source file type. 0 if the type can be inferred from the struct from which the FD was extracted
𝖬 `write` to drain the `BufReader`/`BufWriter` wrappers. only happen when buffers are present. 𝖬 ≾ number of wrappers present. If there is a write buffer it may absorb the read buffer contents first so only result in a single write. Vectored writes would also be an option but that would require more invasive changes to `BufWriter`.
𝖭 `copy_file_range`/`splice`/`sendfile` until file size, EOF or the byte limit from `Take` is reached. This should generally be *much* more efficient than the read-write loop and also have other benefits such as DMA offload or extent sharing.

## Benchmarks

```

OLD

test io::tests::bench_file_to_file_copy         ... bench:      21,002 ns/iter (+/- 750) = 6240 MB/s    [ext4]
test io::tests::bench_file_to_file_copy         ... bench:      35,704 ns/iter (+/- 1,108) = 3671 MB/s  [btrfs]
test io::tests::bench_file_to_socket_copy       ... bench:      57,002 ns/iter (+/- 4,205) = 2299 MB/s
test io::tests::bench_socket_pipe_socket_copy   ... bench:     142,640 ns/iter (+/- 77,851) = 918 MB/s

NEW

test io::tests::bench_file_to_file_copy         ... bench:      14,745 ns/iter (+/- 519) = 8889 MB/s    [ext4]
test io::tests::bench_file_to_file_copy         ... bench:       6,128 ns/iter (+/- 227) = 21389 MB/s   [btrfs]
test io::tests::bench_file_to_socket_copy       ... bench:      13,767 ns/iter (+/- 3,767) = 9520 MB/s
test io::tests::bench_socket_pipe_socket_copy   ... bench:      26,471 ns/iter (+/- 6,412) = 4951 MB/s
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-specialization Area: Trait impl specialization S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

std::io::copy performance may be 20x slower than it could be?
9 participants