-
Notifications
You must be signed in to change notification settings - Fork 362
Performance and safety improvements #429
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
Performance and safety improvements #429
Conversation
ef76547 to
69591ea
Compare
d3a418b to
b5906e2
Compare
|
Rebased and tested with GCC/Debian/testing, Windows Visual Studio Community 2022 and AppleClang/MacOS. Potential reservations: changes the API subtly, not sure about consequences for other projects which use this. |
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. Removing std::regex is refreshing. :)
| }; // class backend_interface | ||
|
|
||
| /// Captures (backend) version information. | ||
| struct Version { |
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 needs MATPLOT_EXPORTS if it's part of the API.
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.
It would also be good to maintain the snake_case convention. version or maybe gnuplot::version since there's no other backend.
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'll make it snake case, sorry.
I could also move Version to gnuplot, I just thought the class is more general than just gnuplot.
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. Outside gnuplot is also OK. I was thinking about the name-grabbing, but that's also OK. We won't need matplot::version for anything else.
| terminal_type = run_and_get_output("gnuplot -e \"show terminal\" 2>&1"); | ||
| terminal_type = std::regex_replace(terminal_type, | ||
| std::regex("[^]*terminal type is ([^ ]+)[^]*"), "$1"); | ||
| terminal_type = word_after(terminal_type, "terminal type is "); |
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.
Heh... Great! :)
source/matplot/backend/gnuplot.cpp
Outdated
| if (!version) { // unknown version | ||
| const auto version_str = run_and_get_output("gnuplot --version 2>&1"); | ||
| const auto major = word_after(version_str, "gnuplot"); | ||
| const auto minor = word_after(major, "."); |
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 pattern is a little confusing when the function is called repeatedly. Let's say the output is "... gnuplot 5.2 patchlevel 6". Wouldn't major just be "5"? If so, then there's no word after "." because major doesn't include everything after 5. That is, major is "5" and not "5.2 patchlevel 6". On the other hand, if major does contain "5.2 patchlevel 6", then the function name and return value are a little misleading.
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.
Right, the name major is misleading, I have renamed it to major_minor and added example in comments -- I think it's clearer when an example is upfront.
source/matplot/backend/gnuplot.h
Outdated
| static std::string default_terminal_type(); | ||
| static bool terminal_is_available(std::string_view); | ||
| static std::tuple<int, int, int> gnuplot_version(); | ||
| static Version gnuplot_version(); |
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.
So converting the output to a tuple wouldn't break the API? A Version is a better decision than a tuple, but it's hard to tell how many people are counting on this API.
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.
Right, I have reverted Version to std::tuple as I did not know that one can compare them in such elegant way. I used to kill it if the code is not about generic programming (Scott Meyers book).
I learned something today, thanks!
| } | ||
| auto set_or_unset_axis = [this](class axis_type &ax, | ||
| std::string axis_name, | ||
| const std::string &axis_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.
If that was your concern about breaking the API, both std::string axis_name and std::string const& axis_name are OK. In the implementation the std::string axis_name can be moved and the std::string const& axis_name can be copied. As far as the user is concerned, that doesn't functionally break the API. Only std::string &axis_name would be a problem.
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 concerns here: that is just a lambda expression - internal stuff.
And yes, it'll bind to the same calls as previously, we just need to make sure that the lambda expression itself does not modify the parameters, but that is checked by the compiler.
| } | ||
| constexpr bool operator!=(const Version &other) const { return !(*this == other); } | ||
| constexpr bool operator<(const Version &other) const { | ||
| if (major < other.major) |
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.
Is it the same as std::tie(major, minor, patch) < std::tie(other.major, other.minor, other.patch)?
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. Looking at the rest of the code and considering tuple defines operator<, I do prefer Version over tuple here if we were coming up with the original API now, but I don't think breaking it now brings a lot of value compared to the potential hassle of people opening issues because the API changed.
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 gone, sorry my bad.
| axes_type::fplot(std::vector<function_line::function_type> equations, | ||
| std::array<double, 2> x_range, | ||
| std::vector<std::string> line_specs) { | ||
| axes_type::fplot(const std::vector<function_line::function_type> &equations, |
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.
Same here. All these API changes are OK.
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.
It's OK if the thing is recompiled, but I am not sure at ABI level, and I do not know if anyone cares.
|
I have removed my |
| const bool has_wall_option = | ||
| std::get<0>(v) > 5 || (std::get<0>(v) == 5 && std::get<1>(v) >= 5); |
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 was my trigger :-)
|
I noticed you made a change to take an argument by reference, but I've noticed that the first arguments to a lot of these functions, the first set of axes is always taken by copy, and I'm wondering why it's not taken by const reference. |
@Please-just-dont Could you please be more specific? Which code lines exactly? |
|
How's this PR going? I don't remember if anything is blocking it since the last review. It's a somewhat unrelated issue, but my intuition is that this would break CI (not because it's bad, but simply because big changes often break it), while at the same time, ci.yml must be broken because it hasn't been maintained in a while. |
|
@alandefreitas I think this PR is ready for merge, unless there are more comments/requests. I see that |
|
I just realized that my build directory is of 21G in size, so that's a big effort just to compile and testing is complicated by the wait (ctest does not allow interaction). Let me know if there is anything more I can do to test at my end, before dispatching this massive test on CI. |
|
Yes. Everything you mention is OK. I just mean regular CI is not running. Our tests aren't that great but at least we got to see if everything was compiling before. Anyway, this should be OK. Let's not block it because of an unrelated issue. |
std::regexwithstd:string_viewscanning (thousands of times faster)std::tuplewith dedicatedVersionclass with named membersbackend_interfacefor safetyconst &infplotand moreclang_tidysuggests making lots ofconstmethods and more...