▲ 131 points
back
22 comments
Articles like this one, and the recent project on libraries like Helix http://blog.skylight.io/introducing-helix/ make me awfully tempted to rewrite inner loops in certain production Ruby projects in Rust.
How on earth can pathname handling be a performance drag? If I read his stats correctly, then `Pathname#chop_basename` is called 24456 times for one page load. Something is very fishy about that.
Agree, and that's per actual page load. Not at the start of the app. If there's no dynamic searching for paths in the app, I don't understand why there would be even one path operation done after the first request. Templates, extra resources, etc. - you can optimise this down to assembler, but it's always going to take time. What solves this is just caching the results - you don't run the path operations anymore.
Exactly what I was thinking. You look for the last slash and truncate.
This is a naive solution. Try using that on windows.
This actually makes me wonder if it would be worthwhile to look for this and similar issues and remove Windows support from the methods for a custom implementation. It might shave off some more time.
Still, use a pattern to find the last slash or backslash. Should be pretty quick.
Rails is such a huge community, and Sprockets has to be one of the biggest pain points for many years.
My solution after years of agony has been to just throw it all out, and use a diff asset packager underneath rails.
Really happy that people are taking this issue on. Wish I had the time to help out.
Re Sprockets, I found this recent talk at RailsConf about the history, problems, and future of Sprockets maintenance and development to be an interesting read: http://schneems.com/2016/05/31/saving-sprockets.html
Given how much modern js development depends on node and npm, I think using a different asset packager is the most sensible way to go.
FasterPath Rust Implementation Ruby 2.3.1 Implementation Performance Improvement
FasterPath.absolute? Pathname#absolute? 1234.6%
Nothing like getting 3 orders of magnitude performance improvement.Ruby's `Pathname#absolute?` is doing a lot more work[1]. I don't know why, but it is.
If I change it to just check the first character for the file separator, as I understand FasterPath does, then of course it is faster:
Warming up --------------------------------------
original 4.109k i/100ms
faster 110.202k i/100ms
Calculating -------------------------------------
original 42.645k (± 3.7%) i/s - 213.668k in 5.017595s
faster 2.643M (± 4.4%) i/s - 13.224M in 5.013294s
Comparison:
faster: 2643274.6 i/s
original: 42644.5 i/s - 61.98x slower
My implementation: class Pathname
def f_relative?
@path[0] != File::SEPARATOR
end
end
[1] https://github.com/ruby/ruby/blob/68ebbbfebe5b666cf76ab41f1e...A quick look at the tests[1] shows that it handles drive letters. The current implementation is probably not the most efficient though...
[1] https://github.com/ruby/ruby/blob/68ebbbfebe5b666cf76ab41f1e...
That returns a wrong result on Windows paths, and throws an exception on the empty string.
There are a ton of edge cases in path manipulation code.
I'm pretty sure his implementation works on empty strings because `str[0].nil?`. So the comparison is false, giving the right (?) answer.
I'm not at all familiar with programming in Rust or Ruby, but what is the significance of the string "muffins" on this line? https://github.com/danielpclark/faster_path/blob/7033f5a5673...
Edit: changed link to blob version which will not change line numbers on me.
I don't write Rust either, but I might guess that they are trying to unbox a nullable value that can't be null. They need a default string due to Rusts strong types even if it's not used.
A more idiomatic way to write the line is:
r_str.chars().next() == Some(MAIN_SEPARATOR)
It's a string whose first character is guaranteed not to match MAIN_SEPARATOR, so that the expression always returns false when r_str is empty.
Definitely not the clearest way to do that.
Not a clue.
http://www.rubydoc.info/gems/muffins/0.0.6
Maybe?
Hilarious find though.
I haven't worked with Rust myself, but I read that as a failover/rescue, to provide a string for debugging purposes (hence the silliness).
Not the OP. Just found this very interesting.