This is an archive of the discontinued LLVM Phabricator instance.

[clang-tidy] performance-inefficient-vector-operation: Support proto repeated field
ClosedPublic

Authored by congliu on Sep 3 2019, 4:41 PM.

Details

Summary

Finds calls that add element to protobuf repeated field in a loop without calling Reserve() before the loop. Calling Reserve() first can avoid unnecessary memory reallocations.

A new option EnableProto is added to guard this feature.

Diff Detail

Event Timeline

congliu created this revision.Sep 3 2019, 4:41 PM
Herald added a project: Restricted Project. · View Herald TranscriptSep 3 2019, 4:41 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript

Please mention new option in Release Notes.

clang-tools-extra/docs/clang-tidy/checks/performance-inefficient-vector-operation.rst
9

See other checks documentation as example of options descriptions.

Eugene.Zelenko added a project: Restricted Project.
lebedev.ri retitled this revision from Support proto repeated field in performence-inefficient-vector-operation to [clang-tidy] performance-inefficient-vector-operation: Support proto repeated field.Sep 4 2019, 2:19 AM

I'm not sure this is the correct approach.
I'd think the check instead should be parametrized, so this patch should become just extending the config.

congliu edited the summary of this revision. (Show Details)Sep 4 2019, 1:15 PM
congliu updated this revision to Diff 218782.Sep 4 2019, 1:33 PM

Updated option descriptions.

congliu marked an inline comment as done.Sep 4 2019, 1:35 PM

I'm not sure this is the correct approach.
I'd think the check instead should be parametrized, so this patch should become just extending the config.

Could you elaborate how the parameterized check will look like? By config did you mean the check options?

congliu updated this revision to Diff 218789.Sep 4 2019, 2:10 PM

Uploaded the correct diff...

hokein added a comment.Sep 6 2019, 6:48 AM

your patch doesn't have a full context, please upload the patch with full context (=U99999) or use Arcanist.

I'd think the check instead should be parametrized, so this patch should become just extending the config.

The AST for protobuf is quite different compared with normal vector, so I don't think there will be an easy and simple way to do it in a config way.

clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp
86 ↗(On Diff #218789)

nit: remove static_cast?

227 ↗(On Diff #218789)

nit: getName().drop_front(sizeof("add_")).

233 ↗(On Diff #218789)

for repeated fields, there should be add_foo, mutable_foo methods in the proto generated code (https://developers.google.com/protocol-buffers/docs/reference/cpp-generated#repeatednumeric).

So I think we can remove this check here.

249 ↗(On Diff #218789)

the heuristic is limited, and will fail the cases like below:

MyProto proto;
set_proto_xxx_size(&proto);
for (int i = 0; i < n; ++i) {
   proto.add_xxx(i);
}

In the vector case, we do a more strict check, maybe we do the same way as well (but it will make the check fail to spot some cases)...

congliu updated this revision to Diff 219180.Sep 6 2019, 2:39 PM
congliu marked 7 inline comments as done.

Addressed Haojian's comments.

  • Do not warn when there is reference to the proto variable between its declaration and the loop body.
  • Exclude const methods.
  • Update tests.
clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp
227 ↗(On Diff #218789)

Used 'sizeof("add_")-1' since "add_" is const char [5].

233 ↗(On Diff #218789)

I intended to rule out the corner cases when a proto field name is "add_xxx". But now I think checking whether there is a "mutable_xxx" method is not a effective way to rule out the corner case. A simpler way is just checking whether add_xxx is const... I have updated the matcher to exclude const methods.

249 ↗(On Diff #218789)

Good point. Let's avoid those false positives.

hokein added inline comments.Sep 10 2019, 1:37 AM
clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp
227 ↗(On Diff #218789)

how about?

llvm::StringRef FieldName =
        ProtoAddFieldCall->getMethodDecl()->getName();
FieldName.consume_front("add_");
std::string MutableFieldName = ...;
233 ↗(On Diff #218789)

I wasn't aware of this corner case, could you add a comment describing the heuristic we use here (around the matcher)?

15 ↗(On Diff #219180)

the include (probably added by clangd) is for google internal style, I believe you are developing at google internal codebase (rather than the opensource LLVM codebase)?

192 ↗(On Diff #219180)

nit: const CXXMemberCallExpr *AppendCall =VectorAppendCall? VectorAppendCall:ProtoAddFieldCall;

195 ↗(On Diff #219180)

In theory, this case should not be happened -- the callback is only invoked when we find a match for the interesting vector/proto cases.

Just use assert(AppendCall) << "no append call expression".

263 ↗(On Diff #219180)

I think the container name doesn't provide much information in the diag message, maybe just use
%0 is called inside a loop; consider pre-allocating the container capacity before the loop?

congliu updated this revision to Diff 219576.Sep 10 2019, 11:25 AM
congliu marked 6 inline comments as done.

Addressed Haojian's comments.

hokein accepted this revision.Sep 11 2019, 1:11 AM

thanks, looks good.

clang-tools-extra/test/clang-tidy/performance-inefficient-vector-operation.cpp
315 ↗(On Diff #219576)

looks like we miss (), the same below.

This revision is now accepted and ready to land.Sep 11 2019, 1:11 AM
congliu updated this revision to Diff 219988.Sep 12 2019, 1:14 PM
congliu marked an inline comment as done.

Addressed Haojian's comment.

hokein accepted this revision.Sep 13 2019, 2:17 AM

feel free to commit the patch.

Could someone commit this for me? I failed to commit this change...

This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptSep 16 2019, 1:52 AM

Could someone commit this for me? I failed to commit this change...

Committed in rL371963, just curious why you failed to commit? if you are using llvm git monorepo, ./llvm/utils/git-svn/git-llvm push should work.