-
Notifications
You must be signed in to change notification settings - Fork 64
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
Get json object comments address #1924
Get json object comments address #1924
Conversation
Signed-off-by: Haoyang Li <haoyangl@nvidia.com>
Signed-off-by: Haoyang Li <haoyangl@nvidia.com>
Signed-off-by: Haoyang Li <haoyangl@nvidia.com>
Signed-off-by: Haoyang Li <haoyangl@nvidia.com>
Will apply performance improvement changes from #1930 after it merged in 24.04 |
build |
Signed-off-by: Haoyang Li <haoyangl@nvidia.com>
Signed-off-by: Haoyang Li <haoyangl@nvidia.com>
Signed-off-by: Haoyang Li <haoyangl@nvidia.com>
Signed-off-by: Haoyang Li <haoyangl@nvidia.com>
…scape_writing. Signed-off-by: Haoyang Li <haoyangl@nvidia.com>
curr_token = json_token::ERROR; | ||
} | ||
// previous token is not INIT, means already get a token; stack is | ||
// empty; Successfully parsed. Note: ignore the tailing sub-string |
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.
Add a comment like:
/**
* Allow tail useless sub-string in JSON, e.g.:
* The following invalid JSON is allowed: {'k' : 'v'}_extra_tail_sub_string
*/
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.
done
src/main/cpp/src/json_parser.cuh
Outdated
@@ -567,6 +508,116 @@ class json_parser { | |||
} | |||
} | |||
|
|||
__device__ inline std::pair<int, int> try_parse_quoted_string_size(char const* str_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.
Add comments for this function.
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.
Rename to: writeString?
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.
done.
src/main/cpp/src/json_parser.cuh
Outdated
// Records string/field name token utf8 bytes size after unescaped | ||
// e.g.: For JSON 4 chars string "\\n", after unescaped, get 1 char '\n' | ||
// used by checking the max string length | ||
int string_token_utf8_bytes = 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.
Rename to: unescped_string_utf8_bytes?
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.
done
src/main/cpp/src/json_parser.cuh
Outdated
// e.g.: 4 chars string "\\n", string_token_utf8_bytes is 1, | ||
// when `write_escaped_text`, will write out 4 chars: " \ n ", | ||
// then this diff will be 4 - 1 = 3 | ||
int bytes_diff_for_escape_writing = 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.
Rename to: escped_string_utf8_bytes?
Refactor to record actual bytes instead of diff? will make code more readable.
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.
done
@@ -660,8 +377,7 @@ __device__ inline thrust::tuple<bool, int> path_match_subscript_index_subscript_ | |||
__device__ bool evaluate_path(json_parser& p, | |||
json_generator& root_g, | |||
write_style root_style, | |||
path_instruction const* root_path_ptr, | |||
int root_path_size) | |||
cudf::device_span<path_instruction const> root_path) |
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.
Note sure if using device_span will cause perf regression, because the size
in device_span
is 64 bits integer which is using more memory compared to 32 bits 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.
no perf regression seen from microbenchmark
src/main/cpp/src/get_json_object.cu
Outdated
{ | ||
auto tid = cudf::detail::grid_1d::global_thread_id(); | ||
auto const stride = cudf::detail::grid_1d::grid_stride(); | ||
|
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.
No need to sync.
__ballot_sync
is used to sync to generate a 32 bits mask within 32 threads(in a warp).
This get_json_object_size_kernel
does not touch any mask, so need to do sync.
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.
done.
src/main/cpp/src/get_json_object.cu
Outdated
d_sizes[tid] = 0; | ||
} | ||
|
||
tid += stride; |
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.
no need, refer to previous comment.
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.
done
src/main/cpp/src/get_json_object.cu
Outdated
@@ -1179,7 +921,7 @@ __device__ thrust::pair<bool, size_t> get_json_object_single( | |||
json_generator generator((out_buf == nullptr || out_buf_size == 0) ? nullptr : out_buf); | |||
|
|||
bool const success = evaluate_path( | |||
j_parser, generator, write_style::raw_style, path_commands_ptr, path_commands_size); | |||
j_parser, generator, write_style::RAW, {path_commands.data(), path_commands.size()}); | |||
|
|||
if (nullptr == out_buf && !success) { |
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.
Remove nullptr == out_buf
?
On first phase the out_buf is null, on second phase it's not 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.
done.
@@ -624,14 +675,20 @@ class json_parser { | |||
char const* to_match_str_pos, | |||
char const* const to_match_str_end, | |||
char* copy_destination, | |||
write_style w_style) | |||
escape_style w_style) | |||
{ |
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.
Extract a match_unescaped_string
from this function? Since try_parse_quoted_string
is doing 2 things.
match_unescaped_string
matches a valid string and is used by match_current_field_name
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.
done
Co-authored-by: Chong Gao <gaochong.gc@qq.com>
Signed-off-by: Haoyang Li <haoyangl@nvidia.com>
micro benchmark for current code: before:
after:
It's about 12% speedup, will run some e2e test and do a per commit break down next. |
Signed-off-by: Haoyang Li <haoyangl@nvidia.com>
BTW, please remove |
src/main/cpp/src/get_json_object.cu
Outdated
{ | ||
auto match = path_match_element(path_ptr, path_size, path_instruction_type::INDEX); | ||
auto match = | ||
path_match_elements(path, path_instruction_type::SUBSCRIPT, path_instruction_type::INDEX); |
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.
path_instruction_type::SUBSCRIPT
is removed after this PR: #1987
src/main/cpp/src/get_json_object.cu
Outdated
@@ -1042,4 +1097,4 @@ std::unique_ptr<cudf::column> get_json_object( | |||
return detail::get_json_object(input, instructions, stream, mr); | |||
} | |||
|
|||
} // namespace spark_rapids_jni | |||
} // namespace spark_rapids_jni |
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.
Add an empty line in the file end.
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.
done.
if (copy_destination != nullptr) copy_destination += escape_chars; | ||
escped_string_utf8_bytes += (escape_chars - 1); | ||
} | ||
|
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.
// check match if enabled
const char* match_str_pos = nullptr;
if (!try_match_char(match_str_pos, nullptr, *str_pos)) {
return std::make_pair(unescped_string_utf8_bytes, escped_string_utf8_bytes);
}
Please check this block. try_match_char(nullptr, nullptr, *str_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.
This is to solve cannot bind non-const lvalue reference of type 'const char*&' to a value of type 'std::nullptr_t'
src/main/cpp/src/json_parser.cuh
Outdated
@@ -998,7 +985,8 @@ class json_parser { | |||
__device__ bool try_skip_unicode(char const*& str_pos, | |||
char const*& to_match_str_pos, | |||
char const* const to_match_str_end, | |||
char*& copy_dest) | |||
char*& copy_dest, | |||
int& unescped_string_utf8_bytes) |
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.
Please pass in escped_string_utf8_bytes
and update.
I found an existing bug which is not introduced in this PR.
Spark behaviors:
// use unescaping logic
get_json_object("['\\u4e2d\\u56FD']", "$") : ["中国"]
// use escaping logic
get_json_object("'\\u4e2d\\u56FD'", "$") : 中国
For the above 2 cases, both need to update the utf8_bytes for both ESCAPE
and UNESCAPE
mode.
Please update test case getJsonObjectTest_Escape
String JSON6 = "['\\u4e2d\\u56FD\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\b']";
String expectedStr6 = "中国\\\"'\\\\/\\b\\f\\n\\r\\t\\b";
And please update the PR description to describe this bug.
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.
Nice catch! done.
Signed-off-by: Haoyang Li <haoyangl@nvidia.com>
build |
build |
@thirtiseven can you tell me how you built and ran the benchmarks? I get compile errors when I try to turn it on using the docker container.
|
@revans2 I think set My commands:
run benchmark
|
Because |
@thirtiseven When posting benchmark number, please use the output of the nvbench compare script so we can see the diff easier:
|
@ttnghia have you had a chance to review this? |
I'll try to review it soon today. |
Sorry I was sick in the last several days. Now reviewing... |
src/main/cpp/src/get_json_object.cu
Outdated
char const* input, | ||
cudf::size_type input_len, |
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.
How about device_span<char const>
? json_parser
constructor can also be modified to take in device_span
.
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.
Oh wait, why do we have this overload of get_json_object_size_single
? Just one version (line 874) is not enough? I don't see any reason why we need to have this new overload.
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.
Yes it won't gain performance, reverted.
src/main/cpp/src/get_json_object.cu
Outdated
template <int block_size> | ||
__launch_bounds__(block_size) CUDF_KERNEL | ||
void get_json_object_size_kernel(cudf::column_device_view col, |
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.
Similar to the other overload, it is not necessary to have this kernel-I don't think we will gain performance by doing this. We can just use the existing kernel like before, but rewrite it a bit to minimize overhead when computing the output size. A few if
instruction overhead in the kernel should not cause any performance difference since the kernel is limited by memory bandwidth, not compute capability
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.
done.
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.
To be clear the difference is about spilling and the number of registers. This is what I found when working on #2015
By splitting them it reduced the number of registers for the one that does not write out data. You are correct that it has essentially no impact to the performance.
Signed-off-by: Haoyang Li <haoyangl@nvidia.com>
Compare results:
|
build |
Closes #1906
Fixed #2021
This PR addresses some follow up comments for getJsonObject new kernel. After addressing it shows about 12% speedup in microbenchmark, but not seen speedup in e2e tests, almost all performance improvement comes from Move 2 variablesstring_token_utf8_bytes, bytes_diff_for_e…
Also fixed a bug:
Spark behaviors:
For the above 2 cases, both need to update the utf8_bytes for both
ESCAPE
andUNESCAPE
mode.