-
Notifications
You must be signed in to change notification settings - Fork 68
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
Adjust the launch bounds to get_json_object to avoid spilling #2015
Adjust the launch bounds to get_json_object to avoid spilling #2015
Conversation
the launch bounds to remove spilling Signed-off-by: Robert (Bobby) Evans <[email protected]>
build |
build |
src/main/cpp/src/json_parser.cuh
Outdated
return char_range(_data + pos, len); | ||
} | ||
|
||
__device__ inline char_range slice_from(cudf::size_type pos) const |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
slice_from is useless.
// save current token start pos, used by coping current token text | ||
char const* current_token_start_pos; | ||
cudf::size_type current_token_start_pos; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both the following variables can be removed.
cudf::size_type current_token_start_pos;
cudf::size_type number_token_len;
If postpone the validatation into write_raw
and copy_current_structure
Then we can remove these two variables.
Current logic is:
Validation a token will go to the end char of the token and save the start pos the the token. If need to copy the current token, have to go back and scan the token again.
Updated logic will be:
Change current token to expected token by only detect the first char of the next token. Postpone the validatation into write_raw
and copy_current_structure
.
e.g.:
{'k' : '123456789'}
When executing next_token
when current pos is pointing to the string '123456789', just scanning 1st char ' decides the next expected token is String. Let curr pos point to the start of '123456789' and set current expected token as STRING. Then when executing write_raw
and copy_current_structure
, do the validation when copying.
After change, the get_json_object
will only scan the whole JSON 1 time without go back.
I have a draft (about 30%) for this, but not sure the improvement gain.
build |
I have upmerged the code relative to the changes in #1924 and addressed the review comments here. I reran the benchmark comparison and got the following.
The numbers are really unchanged from the previous results, except that there are some small movement on the baseline numbers. |
build |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost entirely nits.
src/main/cpp/src/json_parser.cuh
Outdated
__device__ inline bool eof(cudf::size_type pos) { return pos >= _len; } | ||
__device__ inline bool is_null() { return _data == nullptr; } | ||
__device__ inline bool is_empty() { return _len == 0; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 3 could be const.
src/main/cpp/src/json_parser.cuh
Outdated
__device__ inline bool eof() { return _range.eof(_pos); } | ||
__device__ inline bool is_null() { return _range.is_null(); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const here and current_char() and pos()
src/main/cpp/src/json_parser.cuh
Outdated
__device__ inline bool eof(cudf::size_type pos) { return pos >= chars.size(); } | ||
__device__ inline bool eof() { return curr_pos >= chars.size(); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const
src/main/cpp/src/json_parser.cuh
Outdated
char c = str.current_char(); | ||
int v = static_cast<int>(c); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like both of these could be const.
src/main/cpp/src/json_parser.cuh
Outdated
if (copy_destination != nullptr) { *copy_destination++ = str.current_char(); } | ||
} else { | ||
// escape_style::ESCAPED | ||
int escape_chars = escape_char(str.current_char(), copy_destination); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const
build |
@nvdbaranec please take another look |
src/main/cpp/src/get_json_object.cu
Outdated
// We have 1 for the minBlocksPerMultiprocessor in the launch bounds to avoid spilling from | ||
// the kernel itself. By default NVCC uses a heuristic to find a balance between the | ||
// maximum number of registers used by a kernel and the parallelism of the kernel. | ||
// The lots of registers are used the parallelism will suffer. But in our case |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// The lots of registers are used the parallelism will suffer. But in our case | |
// If lots of registers are used the parallelism may suffer. But in our case |
src/main/cpp/src/json_parser.cuh
Outdated
* Note: when setting `allow_single_quotes` or `allow_unescaped_control_chars`, | ||
* then JSON format is not conventional. | ||
* Note: This is not conventional as it allows | ||
* single quotes and unescaped control characters |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* single quotes and unescaped control characters | |
* single quotes and unescaped control characters |
src/main/cpp/src/json_parser.cuh
Outdated
{ | ||
} | ||
|
||
__device__ inline char_range(const cudf::string_view& input) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
__device__ inline char_range(const cudf::string_view& input) | |
__device__ inline char_range(cudf::string_view const& input) |
src/main/cpp/src/json_parser.cuh
Outdated
// a member variable with a static method like this. | ||
__device__ inline static char_range null() { return char_range(nullptr, 0); } | ||
|
||
__device__ inline char_range(const char_range&) = default; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
__device__ inline char_range(const char_range&) = default; | |
__device__ inline char_range(char_range const&) = default; |
src/main/cpp/src/json_parser.cuh
Outdated
|
||
__device__ inline char_range(const char_range&) = default; | ||
__device__ inline char_range(char_range&&) = default; | ||
__device__ inline char_range& operator=(const char_range&) = default; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
__device__ inline char_range& operator=(const char_range&) = default; | |
__device__ inline char_range& operator=(char_range const&) = default; |
src/main/cpp/src/json_parser.cuh
Outdated
const char c = str.current_char(); | ||
const int v = static_cast<int>(c); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const char c = str.current_char(); | |
const int v = static_cast<int>(c); | |
char const c = str.current_char(); | |
int const v = static_cast<int>(c); |
src/main/cpp/src/json_parser.cuh
Outdated
if (copy_destination != nullptr) { *copy_destination++ = str.current_char(); } | ||
} else { | ||
// escape_style::ESCAPED | ||
const int escape_chars = escape_char(str.current_char(), copy_destination); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const int escape_chars = escape_char(str.current_char(), copy_destination); | |
int const escape_chars = escape_char(str.current_char(), copy_destination); |
src/main/cpp/src/json_parser.cuh
Outdated
char c = *str_pos; | ||
switch (*str_pos) { | ||
if (!str.eof()) { | ||
const char c = str.current_char(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const char c = str.current_char(); | |
char const c = str.current_char(); |
src/main/cpp/src/json_parser.cuh
Outdated
cudf::char_utf8 code_point = 0; | ||
for (size_t i = 0; i < 4; i++) { | ||
if (str.eof()) { return false; } | ||
const char c = str.current_char(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const char c = str.current_char(); | |
char const c = str.current_char(); |
src/main/cpp/src/json_parser.cuh
Outdated
// In UTF-8, the maximum number of bytes used to encode a single character | ||
// is 4 | ||
char buff[4]; | ||
const cudf::size_type bytes = from_char_utf8(utf_char, buff); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const cudf::size_type bytes = from_char_utf8(utf_char, buff); | |
cudf::size_type const bytes = from_char_utf8(utf_char, buff); |
src/main/cpp/src/json_parser.cuh
Outdated
if (!eof(curr_pos)) { | ||
char c = *curr_pos; | ||
if (!eof()) { | ||
const char c = chars[curr_pos]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const char c = chars[curr_pos]; | |
char const c = chars[curr_pos]; |
src/main/cpp/src/json_parser.cuh
Outdated
if (!eof(curr_pos)) { | ||
char next_char_after_zero = *curr_pos; | ||
if (!eof()) { | ||
const char next_char_after_zero = chars[curr_pos]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const char next_char_after_zero = chars[curr_pos]; | |
char const next_char_after_zero = chars[curr_pos]; |
src/main/cpp/src/json_parser.cuh
Outdated
char c = *curr_pos; | ||
skip_whitespaces(); | ||
if (!eof()) { | ||
const char c = chars[curr_pos]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const char c = chars[curr_pos]; | |
char const c = chars[curr_pos]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the additional style comments. cudf enforces a very annoying east-const style that we need to follow.
@ttnghia and @nvdbaranec please take another look. I think all of the comments are now addressed. |
build |
I don't see this being enforced in thirdparty/cudf/.clang-format since it does not have if I add this rule the clang-format pre-commit finds and auto-corrects many violations in spark-rapids-jni and cudf |
We found in practice that the get_json_object kernel could be very slow due to register spilling. This asks CUDA to avoid spilling if possible.
Note that this has been upmerged to include changes equivalent to #1924
The comparison of the benchmarks are the following
In my other tests based on NVIDIA/spark-rapids#10729 I saw speedups against the current version of get_json_object of 1.6x to 3.5x
For the legacy version that didn't have any validation I saw improvements between 1.04x and and 1.8x.
I ran the integration tests and they all passed also, so I think this is good to go.