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();
std::sort(names.begin(), names.end());
for (const auto &name : names) {
auto el = name.c_str();
streams.out.append(el);
streams.out.append(L"\n");
for (auto &name : names) {
streams.out.append(name + 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()));
} else {
for (const auto &name : names) {
streams.out.append(name.c_str());
streams.out.append(L"\n");
for (auto &name : names) {
streams.out.append(name + 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;
}
wcstring out;
switch (mode) {
case JOBS_PRINT_NOTHING: {
break;
@ -53,53 +54,57 @@ static void builtin_jobs_print(const job_t *j, int mode, int header, io_streams_
case JOBS_DEFAULT: {
if (header) {
// Print table header before first job.
streams.out.append(_(L"Job\tGroup\t"));
out.append(_(L"Job\tGroup\t"));
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()) {
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"));
streams.out.append(L"\t");
streams.out.append(j->command_wcstr());
streams.out.append(L"\n");
out.append(j->is_stopped() ? _(L"stopped") : _(L"running"));
out.append(L"\t");
out.append(j->command_wcstr());
out.append(L"\n");
streams.out.append(out);
break;
}
case JOBS_PRINT_GROUP: {
if (header) {
// 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;
}
case JOBS_PRINT_PID: {
if (header) {
// 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) {
streams.out.append_format(L"%d\n", p->pid);
append_format(out, L"%d\n", p->pid);
}
streams.out.append(out);
break;
}
case JOBS_PRINT_COMMAND: {
if (header) {
// 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) {
streams.out.append_format(L"%ls\n", p->argv0());
append_format(out, L"%ls\n", p->argv0());
}
streams.out.append(out);
break;
}
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());
retval = STATUS_CMD_ERROR;
} else {
streams.out.append(format_double(v, opts));
streams.out.push_back(L'\n');
streams.out.append(format_double(v, opts) + L"\n");
}
} else {
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) {
streams.out.append_with_separation(str, separation_type_t::explicitly);
} else {
streams.out.append(str);
streams.out.push_back(L'\0');
streams.out.append(str + 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()) {
return STATUS_CMD_ERROR;
}
streams.out.append(pwd);
streams.out.push_back(L'\n');
streams.out.append(pwd + L"\n");
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());
for (const auto &key : names) {
streams.out.append(key);
wcstring out;
out.append(key);
if (!names_only) {
wcstring val;
@ -460,14 +461,15 @@ static int builtin_set_list(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
shorten = true;
val.resize(60);
}
streams.out.append(L" ");
streams.out.append(val);
out.push_back(L' ');
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;