builtins: Reduce streams.out.append/push_back calls

This basically immediately issues a "write()" if it's to a pipe or the
terminal.

That means we can reduce syscalls and improve performance, even by
doing something like

```c++
streams.out.append(somewcstring + L"\n");
```

instead of

```c++
streams.out.append(somewcstring);
streams.out.push_back(L'\n');
```

Some benchmarks of the

```fish
for i in (string repeat -n 2000 \n)
    $thing
end
```

variety:

1. `set` (printing variables) sped up 1.75x
2. `builtin -n` 1.60x
3. `jobs` 1.25x (with 3 jobs)
4. `functions` 1.20x
5. `math 1 + 1` 1.1x
6. `pwd` 1.1x

Piping yields similar results, there is no real difference when
outputting to a command substitution.
This commit is contained in:
Fabian Boehm 2022-09-21 17:54:55 +02:00
parent c5b5dd7563
commit 7bc4c9674b
7 changed files with 34 additions and 34 deletions

View File

@ -101,11 +101,8 @@ maybe_t<int> builtin_builtin(parser_t &parser, io_streams_t &streams, const wcha
wcstring_list_t names = builtin_get_names(); wcstring_list_t names = builtin_get_names();
std::sort(names.begin(), names.end()); std::sort(names.begin(), names.end());
for (const auto &name : names) { for (auto &name : names) {
auto el = name.c_str(); streams.out.append(name + L"\n");
streams.out.append(el);
streams.out.append(L"\n");
} }
} }

View File

@ -286,9 +286,8 @@ maybe_t<int> builtin_functions(parser_t &parser, io_streams_t &streams, const wc
streams.out.append(reformat_for_screen(buff, termsize_last())); streams.out.append(reformat_for_screen(buff, termsize_last()));
} else { } else {
for (const auto &name : names) { for (auto &name : names) {
streams.out.append(name.c_str()); streams.out.append(name + L"\n");
streams.out.append(L"\n");
} }
} }

View File

@ -46,6 +46,7 @@ static void builtin_jobs_print(const job_t *j, int mode, int header, io_streams_
pgid = *job_pgid; pgid = *job_pgid;
} }
wcstring out;
switch (mode) { switch (mode) {
case JOBS_PRINT_NOTHING: { case JOBS_PRINT_NOTHING: {
break; break;
@ -53,53 +54,57 @@ static void builtin_jobs_print(const job_t *j, int mode, int header, io_streams_
case JOBS_DEFAULT: { case JOBS_DEFAULT: {
if (header) { if (header) {
// Print table header before first job. // Print table header before first job.
streams.out.append(_(L"Job\tGroup\t")); out.append(_(L"Job\tGroup\t"));
if (have_proc_stat()) { if (have_proc_stat()) {
streams.out.append(_(L"CPU\t")); out.append(_(L"CPU\t"));
} }
streams.out.append(_(L"State\tCommand\n")); out.append(_(L"State\tCommand\n"));
} }
streams.out.append_format(L"%d\t%d\t", j->job_id(), pgid); append_format(out, L"%d\t%d\t", j->job_id(), pgid);
if (have_proc_stat()) { if (have_proc_stat()) {
streams.out.append_format(L"%.0f%%\t", 100. * cpu_use(j)); append_format(out, L"%.0f%%\t", 100. * cpu_use(j));
} }
streams.out.append(j->is_stopped() ? _(L"stopped") : _(L"running")); out.append(j->is_stopped() ? _(L"stopped") : _(L"running"));
streams.out.append(L"\t"); out.append(L"\t");
streams.out.append(j->command_wcstr()); out.append(j->command_wcstr());
streams.out.append(L"\n"); out.append(L"\n");
streams.out.append(out);
break; break;
} }
case JOBS_PRINT_GROUP: { case JOBS_PRINT_GROUP: {
if (header) { if (header) {
// Print table header before first job. // Print table header before first job.
streams.out.append(_(L"Group\n")); out.append(_(L"Group\n"));
} }
streams.out.append_format(L"%d\n", pgid); append_format(out, L"%d\n", pgid);
streams.out.append(out);
break; break;
} }
case JOBS_PRINT_PID: { case JOBS_PRINT_PID: {
if (header) { if (header) {
// Print table header before first job. // Print table header before first job.
streams.out.append(_(L"Process\n")); out.append(_(L"Process\n"));
} }
for (const process_ptr_t &p : j->processes) { for (const process_ptr_t &p : j->processes) {
streams.out.append_format(L"%d\n", p->pid); append_format(out, L"%d\n", p->pid);
} }
streams.out.append(out);
break; break;
} }
case JOBS_PRINT_COMMAND: { case JOBS_PRINT_COMMAND: {
if (header) { if (header) {
// Print table header before first job. // Print table header before first job.
streams.out.append(_(L"Command\n")); out.append(_(L"Command\n"));
} }
for (const process_ptr_t &p : j->processes) { for (const process_ptr_t &p : j->processes) {
streams.out.append_format(L"%ls\n", p->argv0()); append_format(out, L"%ls\n", p->argv0());
} }
streams.out.append(out);
break; break;
} }
default: { default: {

View File

@ -252,8 +252,7 @@ static int evaluate_expression(const wchar_t *cmd, const parser_t &parser, io_st
streams.err.append_format(L"'%ls'\n", expression.c_str()); streams.err.append_format(L"'%ls'\n", expression.c_str());
retval = STATUS_CMD_ERROR; retval = STATUS_CMD_ERROR;
} else { } else {
streams.out.append(format_double(v, opts)); streams.out.append(format_double(v, opts) + L"\n");
streams.out.push_back(L'\n');
} }
} else { } else {
streams.err.append_format(L"%ls: Error: %ls\n", cmd, math_describe_error(error)); streams.err.append_format(L"%ls: Error: %ls\n", cmd, math_describe_error(error));

View File

@ -201,8 +201,7 @@ static void path_out(io_streams_t &streams, const options_t &opts, const wcstrin
if (!opts.null_out) { if (!opts.null_out) {
streams.out.append_with_separation(str, separation_type_t::explicitly); streams.out.append_with_separation(str, separation_type_t::explicitly);
} else { } else {
streams.out.append(str); streams.out.append(str + L"\0");
streams.out.push_back(L'\0');
} }
} }
} }

View File

@ -73,7 +73,6 @@ maybe_t<int> builtin_pwd(parser_t &parser, io_streams_t &streams, const wchar_t
if (pwd.empty()) { if (pwd.empty()) {
return STATUS_CMD_ERROR; return STATUS_CMD_ERROR;
} }
streams.out.append(pwd); streams.out.append(pwd + L"\n");
streams.out.push_back(L'\n');
return STATUS_CMD_OK; return STATUS_CMD_OK;
} }

View File

@ -437,7 +437,8 @@ static int builtin_set_list(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
sort(names.begin(), names.end()); sort(names.begin(), names.end());
for (const auto &key : names) { for (const auto &key : names) {
streams.out.append(key); wcstring out;
out.append(key);
if (!names_only) { if (!names_only) {
wcstring val; wcstring val;
@ -460,14 +461,15 @@ static int builtin_set_list(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
shorten = true; shorten = true;
val.resize(60); val.resize(60);
} }
streams.out.append(L" "); out.push_back(L' ');
streams.out.append(val); out.append(val);
if (shorten) streams.out.push_back(get_ellipsis_char()); if (shorten) out.push_back(get_ellipsis_char());
} }
} }
streams.out.append(L"\n"); out.push_back(L'\n');
streams.out.append(out);
} }
return STATUS_CMD_OK; return STATUS_CMD_OK;