Skip to content
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

fix VertexHolder::getDefaultProp performance issue. #2249

Merged

Conversation

xuguruogu
Copy link
Collaborator

@xuguruogu xuguruogu commented Jul 25, 2020

VertexHolder::getDefaultProp has huge performace problem, if get some prop not exist.

before:
image

after:
image

@xuguruogu
Copy link
Collaborator Author

Anyway VertexHolder::get also has performance problem, due to call malloc for every vertex prop fetch.

}
auto reader = RowReader::getRowReader(std::get<1>(iter2->second), std::get<0>(iter2->second));
auto res = RowReader::getPropByName(reader.get(), prop);

@xuguruogu
Copy link
Collaborator Author

rewrite VertexHolder maybe required.

if (it2 != it->second.cend()) {
return RowReader::getDefaultProp(std::get<0>(it2->second).get(), prop);
}
OptVariantType GoExecutor::VertexHolder::getDefaultProp(
Copy link
Contributor

@dangleptr dangleptr Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, we don't need "getDefaultProp" and "getDefaultPropType" inside VertexHolder,

You could use RowReader::getDefaultProp directly.

FYI. You could pass schemaManager into VertexHolder directly.

@dangleptr
Copy link
Contributor

Thanks for your contribution. It is really a stupid mistake.

@dangleptr
Copy link
Contributor

dangleptr commented Jul 27, 2020

Anyway VertexHolder::get also has performance problem, due to call malloc for every vertex prop fetch.

}
auto reader = RowReader::getRowReader(std::get<1>(iter2->second), std::get<0>(iter2->second));
auto res = RowReader::getPropByName(reader.get(), prop);

I found the problem too. Not only in graphd, but also inside storaged. We have fixed the issue inside 2.0
If you want to fix it in 1.0, what you need to do is to implement reset method inside RowReader, for each edge/tag,
just reset the value and schema. Use only one RowReader for the whole request.

@dangleptr
Copy link
Contributor

Totally the PR looks good to me. Do you have any plan to fix the RowReader problem in this pr? @xuguruogu

@xuguruogu
Copy link
Collaborator Author

i prefer to fix rowreader later

@xuguruogu
Copy link
Collaborator Author

Totally the PR looks good to me. Do you have any plan to fix the RowReader problem in this pr? @xuguruogu

wait for a while. Writing codes.

@xuguruogu
Copy link
Collaborator Author

Anyway VertexHolder::get also has performance problem, due to call malloc for every vertex prop fetch.

}
auto reader = RowReader::getRowReader(std::get<1>(iter2->second), std::get<0>(iter2->second));
auto res = RowReader::getPropByName(reader.get(), prop);

I found the problem too. Not only in graphd, but also inside storaged. We have fixed the issue inside 2.0
If you want to fix it in 1.0, what you need to do is to implement reset method inside RowReader, for each edge/tag,
just reset the value and schema. Use only one RowReader for the whole request.

expose RowReader with the interface of std::unique_ptr may be a better choice. Without changing large amount of code, all functions using RowReader can benefit from malloc free codes.

@@ -87,7 +87,7 @@ std::string AddEdgesProcessor::addEdges(int64_t version, PartitionID partId,
});
for (auto& e : newEdges) {
std::string val;
std::unique_ptr<RowReader> nReader;
RowReader nReader = RowReader::getEmptyRowReader();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'd better use pointer of RowReader this place. Because there are lots of check null for rowReader in the code.

Copy link
Collaborator Author

@xuguruogu xuguruogu Jul 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bool operator==(nullptr_t) const noexcept {
return !data_.data();
}
bool operator==(const RowReader& x) const noexcept {
return data_ == x.data_;
}
bool operator!=(nullptr_t) const noexcept {
return (bool)data_.data();
}
bool operator!=(const RowReader& x) const noexcept {
return data_ != x.data_;
}

Solve it with CPP magic. This can really help to improve performance, the total batch computing costs reduces from 13min to 5min, for about 2.6X improvement.

Access data set from the stack is much faster than from heap, for CPU hardware cache optimization.

@@ -88,7 +87,7 @@ kvstore::ResultCode QueryBoundProcessor::processEdgeSampling(const PartitionID p
using Sample = std::tuple<
EdgeType, /* type */
std::string, /* key */
std::unique_ptr<RowReader>, /* val */
RowReader, /* val */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RowReader size is large. Pointer is a better choice.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sense

@xuguruogu xuguruogu force-pushed the fix-VertexHolder-getDefaultProp branch from e5cefb2 to bf264be Compare July 29, 2020 09:04
Copy link
Contributor

@dangleptr dangleptr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work!! The pr looks good to me.

Besides the RowReader, there is another point we have optimized in 2.0. You could take it as your reference.

That is MetaClient::getEdgeSchemaFromCache
For each row, inside the RowReader, it will call this method to get the related schema.

It is costly, because there are two hashMap inside it.
So in 2.0, we copy the related edge schema before scanning each edgeType. And use a vector to store the multi versions schema for the edgeType.

So two hash lookup will be replaced by one random array access.

return *get();
}

void reset() noexcept {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems we dont need reset any more. But never mind, leave it here.

dangleptr
dangleptr previously approved these changes Jul 29, 2020
@dangleptr dangleptr requested a review from critical27 July 29, 2020 09:32
@dangleptr dangleptr added the ready-for-testing PR: ready for the CI test label Jul 29, 2020
currEdgeSchema, props));
std::make_tuple(
edgeType, k.str(),
std::make_unique<RowReader>(std::move(reader)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HaHa. Very tricky one~

@dangleptr
Copy link
Contributor

Please check the code style.

Copy link
Contributor

@critical27 critical27 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Impressive!

@xuguruogu xuguruogu force-pushed the fix-VertexHolder-getDefaultProp branch from 8ef5730 to ce66684 Compare July 29, 2020 11:17
Copy link
Contributor

@critical27 critical27 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job!

@dangleptr dangleptr merged commit c95e85e into vesoft-inc:master Jul 30, 2020
@xuguruogu xuguruogu deleted the fix-VertexHolder-getDefaultProp branch July 31, 2020 03:08
@xuguruogu
Copy link
Collaborator Author

Awesome work!! The pr looks good to me.

Besides the RowReader, there is another point we have optimized in 2.0. You could take it as your reference.

That is MetaClient::getEdgeSchemaFromCache
For each row, inside the RowReader, it will call this method to get the related schema.

It is costly, because there are two hashMap inside it.
So in 2.0, we copy the related edge schema before scanning each edgeType. And use a vector to store the multi versions schema for the edgeType.

So two hash lookup will be replaced by one random array access.

emm... It may not give the expected performance improvement. I am familiar with commonly used optimization method. Maybe we can talk about it later in a specified scenario.

@dangleptr
Copy link
Contributor

emm... It may not give the expected performance improvement. I am familiar with commonly used optimization method. Maybe we can talk about it later in a specified scenario.

For RowReader, it has about 1.3x improvement.

critical27 pushed a commit to critical27/nebula that referenced this pull request Aug 4, 2020
* fix VertexHolder::getDefaultProp performance issue.

* rewrite row reader to avoid malloc

Co-authored-by: trippli <trippli@tencent.com>
Co-authored-by: dangleptr <37216992+dangleptr@users.noreply.github.com>
tong-hao pushed a commit to tong-hao/nebula that referenced this pull request Jun 1, 2021
* fix VertexHolder::getDefaultProp performance issue.

* rewrite row reader to avoid malloc

Co-authored-by: trippli <trippli@tencent.com>
Co-authored-by: dangleptr <37216992+dangleptr@users.noreply.github.com>
yixinglu pushed a commit to yixinglu/nebula that referenced this pull request Jan 31, 2023
* add allpath test

* add shortest path test case

* add subgraph test case

* add go test case

* add go test case

Co-authored-by: jimingquan <mingquan.ji@vesoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ready-for-testing PR: ready for the CI test
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants