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

throughput performance issue on lines longer than available columns #1488

Open
christianparpart opened this issue Mar 17, 2024 · 1 comment
Labels
performance Performance issues or improvements VT: Backend Virtual Terminal Backend (libterminal API)

Comments

@christianparpart
Copy link
Member

christianparpart commented Mar 17, 2024

When using termbench to compare some perf numbers, just with Contour alone, we see a dramatic drop of throughput performance when the number of characters being written, before a LF is sent, is more than available columsn per line on the screen.

image
(graph generated by @Yaraslaut - thx for that :))

In this screenshot, the terminals were configured at 100 column page width, and Contour shows a really unhealth drop when the line goes longer than the number of columns available.

Note, this is quite an unusual usecase and would very rarely hit the actual user unless someone wants explicitly exploit such corner cases. So I'd not consider it a high priority, but it would still be nice to address to make the terminal perform more harmonic throughout the work load.

@christianparpart christianparpart added VT: Backend Virtual Terminal Backend (libterminal API) performance Performance issues or improvements labels Mar 17, 2024
@Yaraslaut
Copy link
Member

One of the idea is to rework grid system, and use c++23 chunk_view for resize action, prototype for this :

#include <algorithm>
#include <iostream>
#include <ranges>
#include <sstream>
#include <typeinfo>
#include <variant>
#include <vector>

void print(auto &&chunk) {
  std::cout << '[';
  for (auto inner_iter = chunk.begin(); inner_iter != chunk.end(); ++inner_iter)
    std::cout << *inner_iter;
  std::cout << "] \n";
}

template <class T>
class VectorView : public std::ranges::view_interface<VectorView<T>> {
public:
  using iterator = typename std::vector<T>::const_iterator;
  VectorView() = default;

  VectorView(iterator begin, iterator end) : m_begin(begin), m_end(end) {}

  VectorView(const std::vector<T> &vec)
      : m_begin(vec.cbegin()), m_end(vec.cend()) {}

  auto begin() const { return m_begin; }

  auto end() const { return m_end; }

private:
  iterator m_begin{}, m_end{};
};

template<typename T>
concept line_concept = requires(T line)
{
    { line.size() } -> std::convertible_to<std::size_t>;
};

template <typename vector_view = VectorView<char>,
          typename buffer_view = std::string_view,
          typename line_view = std::variant<vector_view, buffer_view>,
          typename lines_view = std::vector<line_view>>
struct Grid : public std::ranges::view_interface<lines_view> {
  int current_width = 0;
  lines_view _lines;
  lines_view _lines_view_for_display;

  auto begin() const { return _lines_view_for_display.begin(); }
  auto end() const { return _lines_view_for_display.end(); }

  void add_line(line_concept auto&& line) {
    if (line.size() > current_width)
      current_width = line.size();

    _lines.emplace_back(line);
  }

   void print() {
    for (auto &&one_line : _lines_view_for_display) {
      std::visit([](auto &&line) { ::print(line); }, one_line);
    }
  }

  void resize(int w) {
    lines_view newlines;
    auto do_chunking = [&]<class T>(T a, line_view line) {
      for (auto &&chunk : std::get<T>(line) | std::views::chunk(w)) {
        newlines.push_back(T{chunk.begin(), chunk.end()});
      }
    };
    for (auto line : _lines) {
      std::visit([&](auto &&arg) { do_chunking(arg, line); }, line);
    }
    std::swap(newlines, _lines_view_for_display);
  }
};

// helper type for the visitor #4
template <class... Ts> struct overloaded : Ts... {
  using Ts::operator()...;
};
// explicit deduction guide (not needed as of C++20)
template <class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

int main() {

  std::vector<char> letters_vector{'a', 'b', 'c', 'd', 'e', 'f',
                                   'g', 'h', 'i', 'j', 'k'};

  Grid g;
  g.add_line(std::string_view{"ABCDEFGHIJK"});
  g.add_line(letters_vector);

  g.print();
  std::cout << "====================================\n";
  g.resize(8);
  g.print();
  std::cout << "====================================\n";
  g.resize(5);
  g.print();
  std::cout << "====================================\n";
  g.resize(8);
  g.print();

  std::for_each(g.begin(), g.end(), [](auto &&line) {
    std::visit([](auto &&arg) { std::cout << typeid(arg).name() << std::endl; },
               line);
  });

  for (auto &&el : g) {
    std::visit(
        overloaded{[](auto &&line) { std::cout << "Some other\n"; },
                   [](std::string_view line) { std::cout << "string_view\n"; }},
        el);
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
performance Performance issues or improvements VT: Backend Virtual Terminal Backend (libterminal API)
Projects
None yet
Development

No branches or pull requests

2 participants