Skip to content

Commit 47d7c76

Browse files
authored
yes: improve throughput & simplify code (#12650)
1 parent 80cc829 commit 47d7c76

1 file changed

Lines changed: 18 additions & 27 deletions

File tree

src/uu/yes/src/yes.rs

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
2424
let matches = uucore::clap_localization::handle_clap_result(uu_app(), args)?;
2525

2626
#[allow(clippy::unwrap_used, reason = "clap provides 'y' by default")]
27-
let buffer = args_into_buffer(matches.get_many::<OsString>("STRING").unwrap())?;
28-
29-
match exec(buffer) {
27+
let mut buffer = args_into_buffer(matches.get_many::<OsString>("STRING").unwrap())?;
28+
repeat_content_to_capacity(&mut buffer);
29+
match exec(&buffer) {
3030
Ok(()) => Ok(()),
3131
// On Windows, silently handle broken pipe since there's no SIGPIPE
3232
#[cfg(windows)]
@@ -96,51 +96,42 @@ fn repeat_content_to_capacity(buf: &mut Vec<u8>) {
9696
}
9797

9898
#[cfg(not(any(target_os = "linux", target_os = "android")))]
99-
pub fn exec(mut bytes: Vec<u8>) -> io::Result<()> {
100-
repeat_content_to_capacity(&mut bytes);
101-
let bytes = bytes.as_slice();
99+
pub fn exec(bytes: &[u8]) -> io::Result<()> {
102100
let mut stdout = io::stdout().lock();
103101
loop {
104102
stdout.write_all(bytes)?;
105103
}
106104
}
107105

108106
#[cfg(any(target_os = "linux", target_os = "android"))]
109-
pub fn exec(mut bytes: Vec<u8>) -> io::Result<()> {
107+
pub fn exec(bytes: &[u8]) -> io::Result<()> {
110108
use uucore::io::RawWriter;
111109
use uucore::pipes::{pipe, splice, tee};
112110

113-
let safe_partial_send = rustix::pipe::PIPE_BUF.is_multiple_of(bytes.len());
114-
repeat_content_to_capacity(&mut bytes);
115-
let bytes = bytes.as_slice();
116111
let stdout = rustix::stdio::stdout();
117112
// improve throughput
118113
let _ = rustix::pipe::fcntl_setpipe_size(stdout, MAX_ROOTLESS_PIPE_SIZE);
119114
// don't show any error from fast-path and fallback to write for proper message
115+
// tee() cannot control offset. We can do tee only if original bytes.len() is multiple of PIPE_BUF,
116+
// but it is slower than mixing splice even it reduces syscalls...
120117
if let Ok((p_read, mut p_write)) = pipe::<true>()
121118
&& p_write.write_all(bytes).is_ok()
119+
&& let Ok((broker_read, broker_write)) = pipe::<true>()
122120
{
123-
// tee() cannot control offset. But omit splice if it is possible
124-
if safe_partial_send {
125-
// fails if stdout is not a pipe
126-
while tee(&p_read, &stdout, MAX_ROOTLESS_PIPE_SIZE).is_ok() {}
127-
}
128-
if let Ok((broker_read, broker_write)) = pipe::<true>() {
129-
'splice: while let Ok(mut remain) = tee(&p_read, &broker_write, MAX_ROOTLESS_PIPE_SIZE)
130-
{
131-
debug_assert!(remain == bytes.len(), "splice() should cleanup pipe");
132-
while remain > 0 {
133-
if let Ok(s) = splice(&broker_read, &stdout, remain) {
134-
remain -= s;
135-
} else {
136-
// avoid output breakage with reduced remain even if it would not happen
137-
RawWriter(stdout).write_all(&bytes[bytes.len() - remain..])?;
138-
break 'splice;
139-
}
121+
'splice: while let Ok(mut remain) = tee(&p_read, &broker_write, MAX_ROOTLESS_PIPE_SIZE) {
122+
debug_assert!(remain == bytes.len(), "splice() should cleanup pipe");
123+
while remain > 0 {
124+
if let Ok(s) = splice(&broker_read, &stdout, remain) {
125+
remain -= s;
126+
} else {
127+
// avoid output breakage with reduced remain even if it would not happen
128+
RawWriter(stdout).write_all(&bytes[bytes.len() - remain..])?;
129+
break 'splice;
140130
}
141131
}
142132
}
143133
}
134+
144135
// fallback
145136
let mut stdout = RawWriter(stdout);
146137
loop {

0 commit comments

Comments
 (0)