From d87e4eeb9530896f47a41ba9cf417db021afbeb9 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 19 Nov 2016 16:59:12 +0530 Subject: [PATCH] Speed un reading from child process Do the reading into a pre-allocated buffer to avoid mallocs in the inner loop. --- kitty/boss.py | 16 ++++------------ kitty/data-types.c | 2 ++ kitty/data-types.h | 4 ++++ kitty/parser.c | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 12 deletions(-) diff --git a/kitty/boss.py b/kitty/boss.py index 8ad4b5ec0..5b114d60a 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -21,7 +21,7 @@ from .char_grid import CharGrid from .keys import interpret_text_event, interpret_key_event from .utils import resize_pty, create_pty, sanitize_title from .fast_data_types import ( - BRACKETED_PASTE_START, BRACKETED_PASTE_END, Screen, parse_bytes_dump, parse_bytes + BRACKETED_PASTE_START, BRACKETED_PASTE_END, Screen, read_bytes_dump, read_bytes ) @@ -56,7 +56,7 @@ class Boss(Thread): self.window, self.opts = window, opts self.screen = Screen(self) self.char_grid = CharGrid(self.screen, opts, window_width, window_height) - self.parse_bytes = partial(parse_bytes_dump, print) if args.dump_commands else parse_bytes + self.read_bytes = partial(read_bytes_dump, print) if args.dump_commands else read_bytes self.write_buf = memoryview(b'') glfw.glfwSetCharModsCallback(window, self.on_text_input) glfw.glfwSetKeyCallback(window, self.on_key) @@ -201,16 +201,8 @@ class Boss(Thread): def read_ready(self): if self.shutting_down: return - try: - data = os.read(self.child_fd, 100 * io.DEFAULT_BUFFER_SIZE) - except BlockingIOError: - return - except EnvironmentError: - data = b'' - if data: - self.parse_bytes(self.screen, data) - else: # EOF - self.shutdown() + if self.read_bytes(self.screen, self.child_fd) is False: + self.shutdown() # EOF def write_ready(self): if not self.shutting_down: diff --git a/kitty/data-types.c b/kitty/data-types.c index b7ceb2343..49983ca13 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -13,6 +13,8 @@ static PyMethodDef module_methods[] = { GL_METHODS {"parse_bytes", (PyCFunction)parse_bytes, METH_VARARGS, ""}, {"parse_bytes_dump", (PyCFunction)parse_bytes_dump, METH_VARARGS, ""}, + {"read_bytes", (PyCFunction)read_bytes, METH_VARARGS, ""}, + {"read_bytes_dump", (PyCFunction)read_bytes_dump, METH_VARARGS, ""}, {NULL, NULL, 0, NULL} /* Sentinel */ }; diff --git a/kitty/data-types.h b/kitty/data-types.h index 1ee38b1fd..caeaf0d81 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -231,6 +231,7 @@ typedef struct { } SavepointBuffer; #define PARSER_BUF_SZ 8192 +#define READ_BUF_SZ (1024*1024) typedef struct { PyObject_HEAD @@ -250,6 +251,7 @@ typedef struct { uint8_t parser_buf[PARSER_BUF_SZ]; unsigned int parser_state, parser_text_start, parser_buf_pos; bool parser_has_pending_text; + uint8_t read_buf[READ_BUF_SZ]; } Screen; PyTypeObject Screen_Type; @@ -275,6 +277,8 @@ int init_SpriteMap(PyObject *); int init_ChangeTracker(PyObject *); int init_Screen(PyObject *); PyObject* create_256_color_table(); +PyObject* read_bytes_dump(PyObject UNUSED *, PyObject *); +PyObject* read_bytes(PyObject UNUSED *, PyObject *); PyObject* parse_bytes_dump(PyObject UNUSED *, PyObject *); PyObject* parse_bytes(PyObject UNUSED *, PyObject *); uint16_t* translation_table(char); diff --git a/kitty/parser.c b/kitty/parser.c index 4b9444873..ff63de42b 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -7,6 +7,8 @@ #include #include +#include +#include #include "data-types.h" #include "control-codes.h" @@ -554,3 +556,34 @@ parse_bytes(PyObject UNUSED *self, PyObject *args) { _parse_bytes(screen, pybuf.buf, pybuf.len, dump_callback); Py_RETURN_NONE; } + +PyObject* +#ifdef DUMP_COMMANDS +read_bytes_dump(PyObject UNUSED *self, PyObject *args) { +#else +read_bytes(PyObject UNUSED *self, PyObject *args) { +#endif + PyObject *dump_callback = NULL; + Py_ssize_t len; + Screen *screen; + int fd; +#ifdef DUMP_COMMANDS + if (!PyArg_ParseTuple(args, "OOi", &dump_callback, &screen, &fd)) return NULL; +#else + if (!PyArg_ParseTuple(args, "Oi", &screen, &fd)) return NULL; +#endif + + while(true) { + len = read(fd, screen->read_buf, READ_BUF_SZ); + if (len == -1) { + if (errno == EINTR) continue; + if (errno == EIO) { Py_RETURN_FALSE; } + return PyErr_SetFromErrno(PyExc_OSError); + } + break; + } + _parse_bytes(screen, screen->read_buf, len, dump_callback); + if(len > 0) { Py_RETURN_TRUE; } + Py_RETURN_FALSE; +} +