-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
THRIFT-5337 Go set fields write improvement #2307
Conversation
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.
I haven't gone through all the changes yet, but wanted to give you some early feedback.
@@ -152,6 +152,10 @@ class t_go_generator : public t_generator { | |||
const string& tstruct_name, | |||
bool is_result = false, | |||
bool uses_countsetfields = false); | |||
void generate_go_struct_deepequal(std::ostream& out, |
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.
Can we rename all *deepequal*
into *equals*
? I don't think it's accurate to call them "deepequal".
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.
Thanks for review, equals sounds better.
|
||
string field_name; | ||
string publicize_field_name; | ||
int32_t field_id = -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.
this is unused and it will cause certain compilers to fail:
src/thrift/generate/t_go_generator.cc:1879:11: error: unused variable ‘field_id’ [-Werror=unused-variable]
1879 | int32_t field_id = -1;
| ^~~~~~~~
cc1plus: all warnings being treated as errors
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.
removed latest commit
if (is_pointer_field(*f_iter) | ||
&& (ttype->is_base_type() || ttype->is_enum() || ttype->is_container())) { | ||
tgt = "(*" + tgt + ")"; | ||
src = "(*" + src + ")"; |
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.
- wrong indentation
- This generates code like this for optional fields:
if (*p.FieldN) != (*other.FieldN) { return false }
this will cause panic when the field is not set.
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.
Thanks, I add a pointer check to avoid panic last commit
87a7a4b
to
e0c8418
Compare
Looks reasonable at a first glance, will do a proper review later. I wonder if there are any cases covered by |
@dcelasun The process of |
eaa91ae
to
83c8d4a
Compare
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.
I like where this is going, but left some small comments.
Also I believe with this change there's no other way the reflect
import is used, so we can totally remove it from compiled code now.
I believe currently there's some bug in your implementation. The result is different from
namespace go test
enum Enum {
One = 1,
Two = 2,
}
struct Struct {
1: optional string Str,
2: optional i32 I32,
3: optional set<Enum> Enums,
}
package thriftsetbench
import (
"reflect"
"testing"
"github.com/apache/thrift/lib/go/thrift"
"github.com/fishy/thriftsetbench/gen-go/test"
)
func BenchmarkEqual(b *testing.B) {
equalGetter := func() (*test.Struct, *test.Struct) {
s1 := &test.Struct{
Str: thrift.StringPtr("foobar"),
Enums: []test.Enum{
test.Enum_One,
test.Enum_Two,
},
}
s2 := &test.Struct{
Str: thrift.StringPtr("foobar"),
Enums: []test.Enum{
test.Enum_One,
test.Enum_Two,
},
}
return s1, s2
}
nonEqualGetter := func() (*test.Struct, *test.Struct) {
s1 := &test.Struct{
Str: thrift.StringPtr("foobar"),
Enums: []test.Enum{
test.Enum_One,
},
}
s2 := &test.Struct{
Str: thrift.StringPtr("foobar"),
Enums: []test.Enum{
test.Enum_Two,
},
}
return s1, s2
}
for label, getter := range map[string]func() (*test.Struct, *test.Struct){
"equal": equalGetter,
"nonequal": nonEqualGetter,
} {
b.Run(label, func(b *testing.B) {
s1, s2 := getter()
reflectResult := reflect.DeepEqual(s1, s2)
equalsResult := s1.Equals(s2)
if reflectResult != equalsResult {
b.Errorf("Reflect result: %v, Equals result: %v", reflectResult, equalsResult)
}
b.Run("reflect", func(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
reflect.DeepEqual(s1, s2)
}
})
})
b.Run("equals", func(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
s1.Equals(s2)
}
})
})
})
}
} result:
We likely would need to have some thorough test for the |
83c8d4a
to
71a62db
Compare
@fishy It's a bug in |
@BytedanceRPC there's another go compiler change merged, so can you rebase your PR on latest master branch? Also please add some tests for the |
71a62db
to
c843abb
Compare
@fishy rebased PR on latest master branch, and added |
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.
Overall lgtm, but there are a few things can be improved in the test code.
Also you can remove
system_packages.push_back("reflect"); |
"var _ = reflect.DeepEqual\n" |
reflect.DeepEqual
, the reflect package is not used any more in compiled go code.
bool is_args_or_result) { | ||
if (is_args_or_result) { | ||
return; | ||
} |
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.
nit: I think we should do this check on the call site instead, and currently there's only one caller of it (Line 1497), so there should be:
if !is_result && !is_args {
generate_go_struct_equals(out, tstruct, tstruct_name);
}
Semantically this function is called "generate_*", but when one of its arg is passed in true it doesn't generate anything, which feels wrong to me.
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 reasonable, thanks for suggestion.
* Compares any type | ||
*/ | ||
void t_go_generator::generate_go_equals(std::ostream& out, | ||
t_type* ori_type, |
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.
nit: this indentation looks weird. usually you either align with (
, or use fixed 2/4/6 spaces. this is neither.
I don't believe clang-format is used to generate this indentation either, at least it's not enforced by travis. when I run clang-format -i --style=file compiler/cpp/src/thrift/generate/t_go_generator.cc
it made a ton of changes in this file.
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.
not sure is the std::
making indentation looks weird. Indentations looks proper after I remove std::
and apply clang-format
.
To avoid unnecessary change, I only apply the output of clang-format on my changes in compiler/cpp/src/thrift/generate/t_go_generator.cc
.
lib/go/test/tests/equals_test.go
Outdated
func TestEquals(t *testing.T) { | ||
basicTgt, basicSrc := genBasicFoo(), genBasicFoo() | ||
if !basicTgt.Equals(basicSrc) { | ||
t.Fatal("BasicEqualsFoo.Equals() test failed") |
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 test failures should be t.Error
instead of t.Fatal
. Fatal stops the test from running, so if someone made a mistake in the future and failed multiple cases inside this test, they will only see the first failure in the output.
Fatal should only be used when the following tests are depending on this one (e.g. used for nil checks).
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.
Thanks for suggestion
b1c928f
to
a194c06
Compare
t_type* ttype, | ||
string tgt, | ||
string src) { | ||
(void)ttype; |
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.
what does this line do?
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.
try to keep generate_go_equals*
with the same arguments, but ttype
not really used here.
a194c06
to
a5c8540
Compare
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.
Thanks. Looks good. I'll merge it once the tests pass.
10008fb
to
f2d353d
Compare
Can you squash your PR to a single commit, with proper commit message (what you used in the PR title and description)? |
f2d353d
to
281b1d1
Compare
281b1d1
to
002e757
Compare
002e757
to
9e1eb86
Compare
There is a duplicate elements check for set in writeFields* function, and it compares elements using reflect.DeepEqual which is expensive. It's much faster that generates a *Equals* function for set elements and call it in duplicate elements check, especially for nested struct element.
9e1eb86
to
a571cdf
Compare
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.
Travis should finish in 20min or so and I'll merge it after that.
Also add missing copyright header for files added in apache#2307.
Client: go Also add missing copyright header for files added in apache#2307.
Client: go Also add missing copyright header for files added in apache#2307.
Client: go Also add missing copyright header for files added in apache#2307.
Client: go Also add missing copyright header for files added in apache#2307.
Client: go Also add missing copyright header for files added in apache#2307.
Client: go Also add missing copyright header for files added in apache#2307.
Client: go Also add missing copyright header for files added in apache#2307.
Client: go Also add missing copyright header for files added in apache#2307.
Client: go Also add missing copyright header for files added in apache#2307.
Client: go Also add missing copyright header for files added in #2307.
Client: go Also add missing copyright header for files added in #2307.
There is a duplicate elements check for set in
writeFields*
function, and it compares elements usingreflect.DeepEqual
which is expensive.It's much faster that generates a "DeepEqual" function for set elements and apply it in duplicate elements check, especially for nested struct element.
[skip ci]
anywhere in the commit message to free up build resources.