From 3da65874d99d0b7e5fd7c918f8c31d3ebcaef338 Mon Sep 17 00:00:00 2001 From: Neil Conway Date: Fri, 7 Jun 2024 11:25:43 -0400 Subject: [PATCH v4 6/6] Optimize COPY FROM using SIMD CopyReadLineText() scans the COPY input buffer looking for newlines and escape sequences (as well as quotes in CSV mode). We can use SIMD instructions to efficiently skip chunks of text that don't contain any interesting characters. This yields a significant performance improvement for wide rows (many attributes and/or wide attribute values). --- src/backend/commands/copyfromparse.c | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c index 067a33f924..f1f2415bde 100644 --- a/src/backend/commands/copyfromparse.c +++ b/src/backend/commands/copyfromparse.c @@ -73,6 +73,7 @@ #include "nodes/miscnodes.h" #include "pgstat.h" #include "port/pg_bswap.h" +#include "port/simd.h" #include "utils/builtins.h" #include "utils/rel.h" @@ -1180,6 +1181,7 @@ CopyReadLineText(CopyFromState cstate) bool need_data = false; bool hit_eof = false; bool result = false; + Vector8 chunk; /* CSV variables */ bool first_char_in_line = true; @@ -1261,6 +1263,40 @@ CopyReadLineText(CopyFromState cstate) need_data = false; } + /* + * If there is enough data available, use SIMD to check for special + * characters. This allows us to efficiently skip large chunks of + * text, in the common case that newlines and control characters are + * relatively rare. + */ + Assert(input_buf_ptr <= cstate->input_buf_len); + if (cstate->input_buf_len - input_buf_ptr >= sizeof(Vector8)) + { + vector8_load(&chunk, (const uint8 *) &input_buf[input_buf_ptr]); + + if (!(vector8_has(chunk, (unsigned char) '\\') || + vector8_has(chunk, (unsigned char) '\r') || + vector8_has(chunk, (unsigned char) '\n') || + (cstate->opts.csv_mode && vector8_has( + chunk, (unsigned char) escapec)) || + (cstate->opts.csv_mode && vector8_has( + chunk, (unsigned char) quotec)))) + { + input_buf_ptr += sizeof(Vector8); + continue; + } + + /* + * Otherwise, proceed byte-by-byte. Note that on subsequent loop + * iterations, because we will only advance input_buf_ptr by a few + * bytes (usually only one), the SIMD checks above will often be + * repeated on an overlapping range of bytes. + * + * TODO: check whether the bookkeeping required to avoid this is + * worth the cost/complexity. + */ + } + /* OK to fetch a character */ prev_raw_ptr = input_buf_ptr; c = input_buf[input_buf_ptr++]; -- 2.39.3 (Apple Git-146)