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

Use string view for interface labels and descriptions #1210

Merged
merged 6 commits into from
Apr 30, 2024

Conversation

sethrj
Copy link
Member

@sethrj sethrj commented Apr 28, 2024

This prevents repeated allocation/deallocation during the stepping loop as noticed by @esseivaju in #1172.

@sethrj sethrj added core Software engineering infrastructure minor Minor internal changes or fixes performance Changes for performance optimization labels Apr 28, 2024
@sethrj sethrj requested a review from esseivaju April 28, 2024 13:24
Copy link
Contributor

@esseivaju esseivaju left a comment

Choose a reason for hiding this comment

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

Nice! Just a few comments.

@@ -262,8 +262,7 @@ auto LocalTransporter::GetActionTime() const -> MapStrReal
CELER_ASSERT(action_ptrs.size() == time.size());
for (auto i : range(action_ptrs.size()))
{
auto&& label = action_ptrs[i]->label();
result[label] = time[i];
result[std::string{action_ptrs[i]->label()}] = time[i];
Copy link
Contributor

Choose a reason for hiding this comment

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

We can change MapStrReal in LocalTransporter and TimerOutput to std::unordered_map<std::string_view, real_type>

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think we can do it for TimerOutput because that might exceed the lifetime of the core params... I figured it was safer to do a few one-time string copies than to risk it...

Copy link
Contributor

Choose a reason for hiding this comment

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

So far we only use string literals that have static storage, but sure in general it's less error-prone for the map to own the key. It just doesn't look nice having to instantiate a string to look up the map when the string_view has the information needed. Gotta wait for C++20 support to fix that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Do you mean C++26? (which changes operator[])?
Or should we use unordered_map::find which is already (in C++14) templated on the parameter type?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think you did mean C++20 as described here: https://www.cppstories.com/2021/heterogeneous-access-cpp20/. I.e. the templated function/operator is not enough, one also has to customize the hash comparisons.

Copy link
Member Author

Choose a reason for hiding this comment

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

Bummer, I saw that and hoped it would be automatic for the string/view case

src/celeritas/global/ActionRegistry.cc Show resolved Hide resolved
src/corecel/io/OutputRegistry.cc Show resolved Hide resolved
src/corecel/sys/ScopedProfiling.cuda.cc Show resolved Hide resolved
@@ -72,16 +72,16 @@ auto StepperTestBase::check_setup() -> SetupCheckResult

for (auto process_id : range(ProcessId{p.num_processes()}))
{
result.processes.push_back(p.process(process_id)->label());
result.processes.push_back(std::string{p.process(process_id)->label()});
Copy link
Contributor

@esseivaju esseivaju Apr 28, 2024

Choose a reason for hiding this comment

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

I think emplace_back looks better here (or vector of string_view)

@@ -64,9 +64,9 @@ TEST_F(PhysicsParamsTest, accessors)
std::vector<std::string> process_names;
for (auto process_id : range(ProcessId{p.num_processes()}))
{
process_names.push_back(p.process(process_id)->label());
process_names.push_back(std::string{p.process(process_id)->label()});
Copy link
Contributor

Choose a reason for hiding this comment

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

emplace_back here as well

Copy link
Contributor

@esseivaju esseivaju left a comment

Choose a reason for hiding this comment

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

I reran the profiler for the one-slot scenario, we went from 93 million calls to free to 170k so it's pretty good.

@@ -165,8 +174,7 @@ void Transporter<M>::accum_action_times(MapStrDouble* result) const
CELER_ASSERT(action_ptrs.size() == times.size());
for (auto i : range(action_ptrs.size()))
{
auto&& label = action_ptrs[i]->label();
(*result)[label] += times[i];
(*result)[std::string{action_ptrs[i]->label()}] += times[i];
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't that increase (keep the same) the number of allocation?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, but it should only happen once per stream per run — and usually it's going directly into a JSON object which has lots of allocations and can't accept string_view anyway.

@@ -262,8 +262,7 @@ auto LocalTransporter::GetActionTime() const -> MapStrReal
CELER_ASSERT(action_ptrs.size() == time.size());
for (auto i : range(action_ptrs.size()))
{
auto&& label = action_ptrs[i]->label();
result[label] = time[i];
result[std::string{action_ptrs[i]->label()}] = time[i];
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you mean C++26? (which changes operator[])?
Or should we use unordered_map::find which is already (in C++14) templated on the parameter type?

src/corecel/io/OutputRegistry.cc Show resolved Hide resolved
@@ -262,8 +262,7 @@ auto LocalTransporter::GetActionTime() const -> MapStrReal
CELER_ASSERT(action_ptrs.size() == time.size());
for (auto i : range(action_ptrs.size()))
{
auto&& label = action_ptrs[i]->label();
result[label] = time[i];
result[std::string{action_ptrs[i]->label()}] = time[i];
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you did mean C++20 as described here: https://www.cppstories.com/2021/heterogeneous-access-cpp20/. I.e. the templated function/operator is not enough, one also has to customize the hash comparisons.

@sethrj
Copy link
Member Author

sethrj commented Apr 30, 2024

Sorry, just noticed I didn't hit "send" on this comment yesterday...


@esseivaju I think it's much too dangerous to keep long-term string views. Even this is going to lead to an invalid read:

my_string_vec.emplace_back(label);
my_string_view_map.insert({my_string_vec.back(), value});

because once the vector changes capacity, the string views in the map are invalidated.

I think string views are meant primarily for interfaces and not for long-term storage.

@sethrj sethrj merged commit 2767efe into celeritas-project:develop Apr 30, 2024
28 checks passed
@sethrj sethrj deleted the string-view-labels branch May 1, 2024 00:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Software engineering infrastructure minor Minor internal changes or fixes performance Changes for performance optimization
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants