[Feature #21264] Replace C extension with pure Ruby implementation for Ruby >= 3.3#155
[Feature #21264] Replace C extension with pure Ruby implementation for Ruby >= 3.3#155jinroq wants to merge 2 commits intoruby:masterfrom
Conversation
C implementation has been rewritten as faithfully as possible in pure Ruby. [Feature #21264] https://bugs.ruby-lang.org/issues/21264
|
Date was originally written in Ruby prior to Ruby 1.9.3. It was rewritten in C to significantly increase performance. When Date was written in Ruby, it's low performance made it a common bottleneck in Ruby applications. I think for this to be considered, you need to provide comprehensive benchmarks showing that performance does not decrease significantly. |
lib/date/constants.rb
Outdated
|
|
||
| MONTHNAMES = [nil, "January", "February", "March", "April", "May", "June", | ||
| "July", "August", "September", "October", "November", "December"] | ||
| .map { |s| s&.encode(Encoding::US_ASCII)&.freeze }.freeze |
There was a problem hiding this comment.
Put # encoding: US-ASCII at the beginning.
|
A simple benchmark to just create objects: require 'benchmark'
require 'date'
N = 10000
Benchmark.bm do |bm|
bm.report("Time") {N.times {Time.now}}
bm.report("Date") {N.times {Date.today}}
endWith $ ruby -I./lib bench.rb
user system total real
Time 0.001656 0.000023 0.001679 ( 0.001675)
Date 0.002735 0.000062 0.002797 ( 0.002827)This PR: $ ruby -I./lib bench.rb
user system total real
Time 0.001018 0.000013 0.001031 ( 0.001031)
Date 0.007624 0.000151 0.007775 ( 0.007776)Interestingly, this PR makes |
|
@nobu you should probably benchmark with A benchmark should include most of the methods in the library. When I was working on |
|
For the mean time, just tried master: This PR: Agree there seems to be a lot of room for optimization. |
I don't believe the line-by-line translation part is 100% accurate, though it may be true for large portions of the library. The primary implementation difference between the current C implementation and the previous (pre Ruby 1.9.3) Ruby implementation was that the previous Ruby implementation always eagerly converted from whatever the input format was to I think we'd be willing to accept a small performance decrease to switch the C implementation with a Ruby implementation. However, a ~3x performance decrease is way too much to consider switching, IMO. As I mentioned earlier, |
https://bugs.ruby-lang.org/issues/21264
Summary
Rewrite the Date and DateTime C extension as pure Ruby, targeting Ruby 3.3+.
Ruby < 3.3 continues to use the existing C extension as before.
lib/date/)ext/date/) compiled viarake-compilerAll 143 tests pass with 162,593 assertions on both paths.
Motivation
Architecture
The version branch (
RUBY_VERSION >= "3.3") is applied at three layers:lib/date.rbrequire_relativepure Ruby filesrequire 'date_core'(C ext)ext/date/extconf.rbcreate_makefile('date_core')Rakefiletask :compileis a no-opRake::ExtensionTaskcompiles C extUSE_PACKmon/mday/hour/min/secinto a single integer for memory efficiency@nth,@jd,@df,@sf,@of,@sg)TIGHT_PARSERDate._parse(disabled by default in C via/* #define TIGHT_PARSER */)TIGHT_PARSERlogic is not implementedPure Ruby file structure
lib/date/core.rblib/date/parse.rbDate._parse,_iso8601,_rfc3339,_rfc2822,_xmlschema,_jisx0301lib/date/datetime.rblib/date/strptime.rbstrptimeparsinglib/date/strftime.rbstrftimeformattinglib/date/zonetab.rblib/date/patterns.rblib/date/constants.rblib/date/time.rbDate#to_time,Time#to_date,Time#to_datetimelib/date/version.rbDate::VERSIONChanges
Rakefile: Branch onRUBY_VERSIONfor compile/test task setup;testdepends oncompilefor Ruby < 3.3date.gemspec: Include bothlib/**/*.rbandext/date/*files; setextensionsext/date/extconf.rb: Generate dummy Makefile on Ruby >= 3.3, build C ext otherwiselib/date.rb: Branch onRUBY_VERSIONfor require pathlib/date/*.rb(new): Pure Ruby implementation (10 files, ~9,500 lines)Sidenote
It has not been refactored because the goal is to replace C with Ruby. If this PR is merged, it will be refactored.