From d63629b370c4e38db527605863f0533666b6f629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 7 Jul 2019 16:32:18 +0200 Subject: [PATCH] performance improvements * action() returns void - this gets rid of checks in vt_from_slave() * split up ACTION_PRINT into ACTION_PRINT (ASCII) and ACTION_UTF8_PRINT ACTION_PRINT is on the hot path, and we want it streamlined. * Remove run-time checkout for unimplemented state transitions, as we shouldn't have any of those left. * Don't re-load current VT state on each iteration in vt_from_slave() --- csi.c | 50 ++++++------- csi.h | 2 +- osc.c | 9 +-- osc.h | 2 +- vt.c | 233 +++++++++++++++++++++++++++++++++------------------------- 5 files changed, 164 insertions(+), 132 deletions(-) diff --git a/csi.c b/csi.c index de7d8a89..60b6af91 100644 --- a/csi.c +++ b/csi.c @@ -91,12 +91,12 @@ sgr_reset(struct terminal *term) term->vt.attrs.background = term->background; } -static bool +static void csi_sgr(struct terminal *term) { if (term->vt.params.idx == 0) { sgr_reset(term); - return true; + return; } for (size_t i = 0; i < term->vt.params.idx; i++) { @@ -162,7 +162,8 @@ csi_sgr(struct terminal *term) i += 4; } else { LOG_ERR("invalid CSI SGR sequence"); - return false; + abort(); + break; } break; } @@ -208,7 +209,8 @@ csi_sgr(struct terminal *term) i += 4; } else { LOG_ERR("invalid CSI SGR sequence"); - return false; + abort(); + break; } break; } @@ -245,11 +247,10 @@ csi_sgr(struct terminal *term) default: LOG_ERR("unimplemented: CSI: SGR: %u", term->vt.params.v[i].value); - return false; + abort(); + break; } } - - return true; } static const char * @@ -279,7 +280,7 @@ csi_as_string(struct terminal *term, uint8_t final) return msg; } -bool +void csi_dispatch(struct terminal *term, uint8_t final) { LOG_DBG("CSI: %s", csi_as_string(term, final)); @@ -287,7 +288,8 @@ csi_dispatch(struct terminal *term, uint8_t final) if (term->vt.intermediates.idx == 0) { switch (final) { case 'c': - return write(term->ptmx, "\033[?6c", 5) == 5; + write(term->ptmx, "\033[?6c", 5); + break; case 'd': { /* VPA - vertical line position absolute */ @@ -297,7 +299,8 @@ csi_dispatch(struct terminal *term, uint8_t final) } case 'm': - return csi_sgr(term); + csi_sgr(term); + break; case 'A': term_cursor_up(term, param_get(term, 0, 1)); @@ -359,7 +362,8 @@ csi_dispatch(struct terminal *term, uint8_t final) default: LOG_ERR("CSI: %s: invalid argument: %d", csi_as_string(term, final), param); - return false; + abort(); + break; } term_erase(term, start, end); @@ -394,7 +398,8 @@ csi_dispatch(struct terminal *term, uint8_t final) default: LOG_ERR("CSI: %s: invalid argument: %d", csi_as_string(term, final), param); - return false; + abort(); + break; } term_erase(term, start, end); @@ -513,7 +518,7 @@ csi_dispatch(struct terminal *term, uint8_t final) * should provide our own terminfo with *only* \e[?1049h * (and \e[?1049l for rmcup) */ - LOG_WARN("ignoring CSI with final 't'"); + LOG_WARN("ignoring CSI: %s", csi_as_string(term, final)); break; case 'n': { @@ -536,13 +541,12 @@ csi_dispatch(struct terminal *term, uint8_t final) default: LOG_ERR("unimplemented: CSI: %s, parameter = %d", csi_as_string(term, final), param); - return false; + abort(); + break; } - - return true; } else { LOG_ERR("CSI: %s: missing parameter", csi_as_string(term, final)); - return false; + abort(); } break; } @@ -561,8 +565,6 @@ csi_dispatch(struct terminal *term, uint8_t final) LOG_ERR("unimplemented: CSI: %s", csi_as_string(term, final)); abort(); } - - return true; } else if (term->vt.intermediates.idx == 1 && @@ -746,8 +748,6 @@ csi_dispatch(struct terminal *term, uint8_t final) LOG_ERR("unimplemented: CSI: %s", csi_as_string(term, final)); abort(); } - - return true; } else if (term->vt.intermediates.idx == 1 && @@ -759,10 +759,12 @@ csi_dispatch(struct terminal *term, uint8_t final) LOG_ERR( "unimplemented: send device attributes with param = %d", param); - return false; + abort(); + break; } - return write(term->ptmx, "\033[?6c", 5) == 5; + write(term->ptmx, "\033[?6c", 5); + break; } default: @@ -775,6 +777,4 @@ csi_dispatch(struct terminal *term, uint8_t final) LOG_ERR("unimplemented: CSI: %s", csi_as_string(term, final)); abort(); } - - return false; } diff --git a/csi.h b/csi.h index adf7b09c..12ae67ec 100644 --- a/csi.h +++ b/csi.h @@ -3,4 +3,4 @@ #include #include "terminal.h" -bool csi_dispatch(struct terminal *term, uint8_t final); +void csi_dispatch(struct terminal *term, uint8_t final); diff --git a/osc.c b/osc.c index 6c523116..efaab15f 100644 --- a/osc.c +++ b/osc.c @@ -7,7 +7,7 @@ #include "log.h" #include "render.h" -bool +void osc_dispatch(struct terminal *term) { int param = 0; @@ -24,7 +24,7 @@ osc_dispatch(struct terminal *term) if (!isdigit(c)) { LOG_ERR("OSC: invalid parameter: %.*s", (int)term->vt.osc.idx, term->vt.osc.data); - return false; + abort(); } param *= 10; @@ -47,8 +47,7 @@ osc_dispatch(struct terminal *term) default: LOG_ERR("unimplemented: OSC: %.*s", (int)term->vt.osc.idx, term->vt.osc.data); - return false; + abort(); + break; } - - return true; } diff --git a/osc.h b/osc.h index 91a01bc4..9b0b8328 100644 --- a/osc.h +++ b/osc.h @@ -3,4 +3,4 @@ #include #include "terminal.h" -bool osc_dispatch(struct terminal *term); +void osc_dispatch(struct terminal *term); diff --git a/vt.c b/vt.c index a3ace1f2..7bab63d1 100644 --- a/vt.c +++ b/vt.c @@ -63,8 +63,10 @@ enum action { ACTION_UTF8_3_ENTRY, ACTION_UTF8_4_ENTRY, ACTION_UTF8_COLLECT, + ACTION_UTF8_PRINT, }; +#if 0 static const char *const state_names[] = { [STATE_SAME] = "no change", [STATE_GROUND] = "ground", @@ -89,7 +91,7 @@ static const char *const state_names[] = { [STATE_UTF8_COLLECT] = "UTF-8", }; - +#endif static const char *const action_names[] __attribute__((unused)) = { [ACTION_NONE] = "no action", [ACTION_IGNORE] = "ignore", @@ -111,6 +113,7 @@ static const char *const action_names[] __attribute__((unused)) = { [ACTION_UTF8_3_ENTRY] = "UTF-8 (3 chars) begin", [ACTION_UTF8_4_ENTRY] = "UTF-8 (4 chars) begin", [ACTION_UTF8_COLLECT] = "UTF-8 collect", + [ACTION_UTF8_PRINT] = "UTF-8 print", }; struct state_transition { @@ -566,7 +569,7 @@ esc_as_string(struct terminal *term, uint8_t final) } -static bool +static void esc_dispatch(struct terminal *term, uint8_t final) { LOG_DBG("ESC: %s", esc_as_string(term, final)); @@ -594,7 +597,8 @@ esc_dispatch(struct terminal *term, uint8_t final) default: LOG_ERR("%s: invalid charset identifier", esc_as_string(term, final)); - return false; + abort(); + break; } break; } @@ -611,7 +615,8 @@ esc_dispatch(struct terminal *term, uint8_t final) default: LOG_ERR("%s: invalid charset identifier", esc_as_string(term, final)); - return false; + abort(); + break; } break; } @@ -633,16 +638,104 @@ esc_dispatch(struct terminal *term, uint8_t final) default: LOG_ERR("unimplemented: ESC: %s", esc_as_string(term, final)); - return false; + abort(); + break; } - - return true; } -static bool -action(struct terminal *term, enum action action, uint8_t c) +static inline void +pre_print(struct terminal *term) { - switch (action) { + if (unlikely(term->print_needs_wrap) && term->auto_margin) { + if (term->cursor.row == term->scroll_region.end - 1) { + term_scroll(term, 1); + term_cursor_to(term, term->cursor.row, 0); + } else + term_cursor_to(term, term->cursor.row + 1, 0); + } +} + +static inline void +post_print(struct terminal *term) +{ + if (term->cursor.col < term->cols - 1) + term_cursor_right(term, 1); + else + term->print_needs_wrap = true; +} + +static inline void +print_insert(struct terminal *term) +{ + if (unlikely(term->insert_mode)) { + assert(false && "untested"); + grid_memmove( + term->grid, term->cursor.linear + 1, term->cursor.linear, + term->cols - term->cursor.col - 1); + term_damage_update( + term, term->cursor.linear + 1, term->cols - term->cursor.col - 1); + } +} + +static void +action_print_utf8(struct terminal *term) +{ + pre_print(term); + + struct cell *cell = &term->grid->cur_line[term->cursor.col]; + term_damage_update(term, term->cursor.linear, 1); + + print_insert(term); + + //LOG_DBG("print: UTF8: %.*s", (int)term->vt.utf8.idx, term->vt.utf8.data); + memcpy(cell->c, term->vt.utf8.data, term->vt.utf8.idx); + cell->c[term->vt.utf8.idx] = '\0'; + term->vt.utf8.idx = 0; + + cell->attrs = term->vt.attrs; + post_print(term); +} + +static void +action_print(struct terminal *term, uint8_t c) +{ + pre_print(term); + + struct cell *cell = &term->grid->cur_line[term->cursor.col]; + term_damage_update(term, term->cursor.linear, 1); + + print_insert(term); + + static const char *const vt100_0[62] = { /* 0x41 - 0x7e */ + "↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */ + 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ + 0, 0, 0, 0, 0, 0, 0, 0, /* P - W */ + 0, 0, 0, 0, 0, 0, 0, " ", /* X - _ */ + "◆", "▒", "␉", "␌", "␍", "␊", "°", "±", /* ` - g */ + "␤", "␋", "┘", "┐", "┌", "└", "┼", "⎺", /* h - o */ + "⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */ + "│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */ + }; + + if (unlikely(term->charset[term->selected_charset] == CHARSET_GRAPHIC) && + c >= 0x41 && c <= 0x7e) + { + strcpy(cell->c, vt100_0[c - 0x41]); + } else { + //LOG_DBG("print: ASCII: %c", c); + cell->c[0] = c; + cell->c[1] = '\0'; + } + + cell->attrs = term->vt.attrs; + + post_print(term); +} + +static void +action(struct terminal *term, enum action _action, uint8_t c) +{ + switch (_action) { case ACTION_NONE: break; @@ -685,10 +778,11 @@ action(struct terminal *term, enum action action, uint8_t c) default: LOG_ERR("execute: unimplemented: %c (0x%02x)", c, c); - return false; + abort(); + break; } - return true; + break; case ACTION_CLEAR: memset(&term->vt.params, 0, sizeof(term->vt.params)); @@ -697,64 +791,13 @@ action(struct terminal *term, enum action action, uint8_t c) term->vt.utf8.idx = 0; break; - case ACTION_PRINT: { - if (unlikely(term->print_needs_wrap) && term->auto_margin) { - if (term->cursor.row == term->scroll_region.end - 1) { - term_scroll(term, 1); - term_cursor_to(term, term->cursor.row, 0); - } else - term_cursor_to(term, term->cursor.row + 1, 0); - } - - struct cell *cell = &term->grid->cur_line[term->cursor.col]; - term_damage_update(term, term->cursor.linear, 1); - - if (unlikely(term->insert_mode)) { - assert(false && "untested"); - grid_memmove( - term->grid, term->cursor.linear + 1, term->cursor.linear, - term->cols - term->cursor.col - 1); - term_damage_update( - term, term->cursor.linear + 1, term->cols - term->cursor.col - 1); - } - - if (term->vt.utf8.idx > 0) { - //LOG_DBG("print: UTF8: %.*s", (int)term->vt.utf8.idx, term->vt.utf8.data); - memcpy(cell->c, term->vt.utf8.data, term->vt.utf8.idx); - cell->c[term->vt.utf8.idx] = '\0'; - term->vt.utf8.idx = 0; - } else { - static const char *const vt100_0[62] = { /* 0x41 - 0x7e */ - "↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */ - 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ - 0, 0, 0, 0, 0, 0, 0, 0, /* P - W */ - 0, 0, 0, 0, 0, 0, 0, " ", /* X - _ */ - "◆", "▒", "␉", "␌", "␍", "␊", "°", "±", /* ` - g */ - "␤", "␋", "┘", "┐", "┌", "└", "┼", "⎺", /* h - o */ - "⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */ - "│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */ - }; - - if (unlikely(term->charset[term->selected_charset] == CHARSET_GRAPHIC) && - c >= 0x41 && c <= 0x7e) - { - strcpy(cell->c, vt100_0[c - 0x41]); - } else { - //LOG_DBG("print: ASCII: %c", c); - cell->c[0] = c; - cell->c[1] = '\0'; - } - } - - cell->attrs = term->vt.attrs; - - if (term->cursor.col < term->cols - 1) - term_cursor_right(term, 1); - else - term->print_needs_wrap = true; - + case ACTION_PRINT: + action_print(term, c); + break; + + case ACTION_UTF8_PRINT: + action_print_utf8(term); break; - } case ACTION_PARAM:{ if (term->vt.params.idx == 0) @@ -785,14 +828,16 @@ action(struct terminal *term, enum action action, uint8_t c) break; LOG_ERR("unimplemented: action ESC dispatch"); - return false; + abort(); + break; case ACTION_ESC_DISPATCH: - return esc_dispatch(term, c); + esc_dispatch(term, c); break; case ACTION_CSI_DISPATCH: - return csi_dispatch(term, c); + csi_dispatch(term, c); + break; case ACTION_OSC_START: term->vt.osc.idx = 0; @@ -806,13 +851,14 @@ action(struct terminal *term, enum action action, uint8_t c) case ACTION_OSC_END: assert(term->vt.osc.idx < sizeof(term->vt.osc.data)); term->vt.osc.data[term->vt.osc.idx] = '\0'; - return osc_dispatch(term); + osc_dispatch(term); + break; case ACTION_HOOK: case ACTION_UNHOOK: case ACTION_PUT: - LOG_ERR("unimplemented: action %s", action_names[action]); - return false; + LOG_ERR("unimplemented: action %s", action_names[_action]); + abort(); case ACTION_UTF8_2_ENTRY: term->vt.utf8.idx = 0; @@ -837,51 +883,38 @@ action(struct terminal *term, enum action action, uint8_t c) case ACTION_UTF8_COLLECT: term->vt.utf8.data[term->vt.utf8.idx++] = c; - if (--term->vt.utf8.left == 0) + if (--term->vt.utf8.left == 0) { term->vt.state = STATE_GROUND; + action_print_utf8(term); + } break; } - - return true; } void vt_from_slave(struct terminal *term, const uint8_t *data, size_t len) { - //int cursor = term->grid.cursor; + //LOG_DBG("input: 0x%02x", data[i]); + enum state current_state = term->vt.state; + for (size_t i = 0; i < len; i++) { - //LOG_DBG("input: 0x%02x", data[i]); - enum state current_state = term->vt.state; if (current_state == STATE_UTF8_COLLECT) { - if (!action(term, ACTION_UTF8_COLLECT, data[i])) - abort(); + action(term, ACTION_UTF8_COLLECT, data[i]); current_state = term->vt.state; - if (current_state == STATE_UTF8_COLLECT) - continue; - - if (!action(term, ACTION_PRINT, 0)) - abort(); - continue; } const struct state_transition *transition = &states[current_state][data[i]]; - if (transition->action == ACTION_NONE && transition->state == STATE_SAME) { - LOG_ERR("unimplemented transition from %s: 0x%02x", - state_names[current_state], data[i]); - abort(); - } + assert(transition->action != ACTION_NONE || transition->state != STATE_SAME); if (transition->state != STATE_SAME) { enum action exit_action = exit_actions[current_state]; - if (exit_action != ACTION_NONE && !action(term, exit_action, data[i])) - abort(); + action(term, exit_action, data[i]); } - if (!action(term, transition->action, data[i])) - abort(); + action(term, transition->action, data[i]); if (transition->state != STATE_SAME) { /* @@ -889,10 +922,10 @@ vt_from_slave(struct terminal *term, const uint8_t *data, size_t len) * state_names[transition->state]); */ term->vt.state = transition->state; + current_state = transition->state; enum action entry_action = entry_actions[transition->state]; - if (entry_action != ACTION_NONE && !action(term, entry_action, data[i])) - abort(); + action(term, entry_action, data[i]); } } }