monotime 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 388a55af121b75e9a9ac06db8674e5a8a4b06ade0431a5cdd961f82426c87ade
4
- data.tar.gz: 7d62a9b673252f01591769d8659c5a36b1026088724a2afc9694b41f633ca053
3
+ metadata.gz: fa145221981b5ff0adb6d1cd3aa77a7e9e9a32942ab9a849a2f83a0d434e245d
4
+ data.tar.gz: c86e6a4ca11e2e9569089574662e96d2cf0ef1b2216ee638832099a5570cd5da
5
5
  SHA512:
6
- metadata.gz: 14c7ede1fc2daa4fef854d3be58392f57849ff07c4f815c3e995f32073e14893fa7ad95f08e074199457517d262fc8c2942316b8039260b1e66e4045409bb6cf
7
- data.tar.gz: b2c907ce1b4f3f92185ba4cb238c3809b465d40be7e34eb1c4a225779a4f6c156ae1d78742ddf24a467d59bfd3437c15be54d4f8bc91a9a9d06fa42ee5e5544a
6
+ metadata.gz: 78a3a8dc8817cc0f99b67d2839d341e01259815c1fefce78ad0d619f2a4c2739414896a98322a2dd620d105b3b1636f6d355d2250deb71920e3a444d970bc0c4
7
+ data.tar.gz: 5408bc28e13df38a04228eedd325371f7136c036c6ab57c0775c7adc401d4e516acae375502bf16d1f5e3945fe2aaf9b60e6e8549d57570a16d4ec59b10a5b99
data/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.8.2] - 2023-09-22
4
+
5
+ ### Added
6
+
7
+ - `Instant.clock_name` is back and now tracks `clock_id` using reflection.
8
+ - Explicit minimum Ruby version in gemspec (2.7.0).
9
+
10
+ ### Changed
11
+
12
+ - Clock auto-selection redux. We choose the first available from:
13
+
14
+ 1. `CLOCK_UPTIME_RAW` on macOS, faster and higher resolution, also used by Rust
15
+ 2. `CLOCK_MONOTONIC`
16
+ 3. `CLOCK_REALTIME`, a non-monotonic fallback that issues a warning on startup
17
+
18
+ - Slight performance bump for `Duration.measure` on Ruby <= 3.1
19
+
20
+ ## [0.8.1] - 2023-09-18
21
+
22
+ ### Changed
23
+
24
+ - After further consideration, return to defaulting to `CLOCK_MONOTONIC` instead
25
+ of the overly-elaborate auto-selection introduced in 0.8.0.
26
+
27
+ ### Removed
28
+
29
+ - `Instant.clock_name`. No I'm not incrementing to 0.9. It's been a few hours,
30
+ you're not using it, shut up.
31
+
3
32
  ## [0.8.0] - 2023-09-17
4
33
 
5
34
  ### Added
@@ -165,8 +194,11 @@
165
194
  [0.6.1]: https://github.com/Freaky/monotime/commits/v0.6.1
166
195
  [0.7.0]: https://github.com/Freaky/monotime/commits/v0.7.0
167
196
  [0.7.1]: https://github.com/Freaky/monotime/commits/v0.7.0
168
- [0.8.0]: https://github.com/Freaky/monotime/commits/v0.7.0
197
+ [0.8.0]: https://github.com/Freaky/monotime/commits/v0.8.0
198
+ [0.8.1]: https://github.com/Freaky/monotime/commits/v0.8.1
199
+ [0.8.2]: https://github.com/Freaky/monotime/commits/v0.8.2
169
200
  [issue #1]: https://github.com/Freaky/monotime/issues/1
201
+ [Ruby #16740]: https://bugs.ruby-lang.org/issues/16740
170
202
  [@celsworth]: https://github.com/celsworth
171
203
  [@petergoldstein]: https://github.com/petergoldstein
172
- [@fig]: https://github.com/fig
204
+ [@fig]: https://github.com/fig
data/README.md CHANGED
@@ -171,11 +171,11 @@ The gem is available as open source under the terms of the [MIT License](https:/
171
171
  ### Core Ruby
172
172
 
173
173
  For a zero-dependency alternative upon which `monotime` is based, see
174
- [`Process.clock_gettime`](https://ruby-doc.org/core-2.6.3/Process.html#method-c-clock_gettime).
174
+ [`Process.clock_gettime`](https://www.rubydoc.info/stdlib/core/Process:clock_gettime).
175
175
 
176
- `Process::CLOCK_MONOTONIC` is a safe default, but other options may offer better
177
- behaviour in face of NTP frequency skew or suspend/resume and should be evaluated
178
- carefully.
176
+ `Process::CLOCK_MONOTONIC` is a safe default, but other options may offer higher
177
+ resolution or alternative behaviour in light of system suspend/resume or NTP
178
+ frequency skew.
179
179
 
180
180
  ### Other Gems
181
181
 
@@ -106,7 +106,9 @@ module Monotime
106
106
  #
107
107
  # @return [Duration]
108
108
  def measure
109
- Instant.now.tap { yield }.elapsed
109
+ start = Instant.now
110
+ yield
111
+ start.elapsed
110
112
  end
111
113
 
112
114
  # Return the result of the yielded block alongside a +Duration+.
@@ -12,38 +12,16 @@ module Monotime
12
12
  include Comparable
13
13
 
14
14
  class << self
15
- attr_writer :clock_id
16
-
17
- # The symbolic name of the automatically-selected +Process.clock_gettime+
18
- # clock id, if available. This will *not* reflect a manually-set +clock_id+.
19
- #
20
- # @return [Symbol, nil]
21
- attr_reader :clock_name
22
-
23
- # The function used to create +Instant+ instances.
24
- #
25
- # This function must return a +Numeric+, monotonic count of nanoseconds
26
- # since a fixed point in the past.
27
- #
28
- # Defaults to `lambda { Process.clock_gettime(clock_id, :nanosecond) }`.
29
- #
30
- # @overload monotonic_function=(function)
31
- # @param function [#call]
32
- attr_accessor :monotonic_function
33
-
34
15
  # @overload clock_id
35
- # The configured or detected +Process.clock_getime+ clock identifier.
36
- #
37
- # Raises +NotImplementedError+ if a suitable monotonic clock source cannot
38
- # be found and one has not been specified manually.
16
+ # The +Process.clock_gettime+ clock id used to create +Instant+ instances
17
+ # by the default monotonic function.
39
18
  #
40
19
  # @return [Numeric]
41
20
  #
42
21
  # @overload clock_id=(id)
43
- # The +Process.clock_gettime+ clock id used to create +Instant+ instances
44
- # by the default monotonic function.
45
22
  #
46
- # Suggested options include but are not limited to:
23
+ # Override the default +Process.clock_gettime+ clock id. Some potential
24
+ # choices include but are not limited to:
47
25
  #
48
26
  # * +Process::CLOCK_MONOTONIC_RAW+
49
27
  # * +Process::CLOCK_UPTIME_RAW+
@@ -53,56 +31,85 @@ module Monotime
53
31
  # * +Process::CLOCK_MONOTONIC_PRECISE+
54
32
  # * +Process::CLOCK_MONOTONIC_FAST+
55
33
  # * +Process::CLOCK_MONOTONIC+
34
+ # * +:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC+
35
+ # * +:TIMES_BASED_CLOCK_MONOTONIC+
56
36
  #
57
- # These are platform-dependant and may vary in resolution, performance,
58
- # and behaviour from NTP frequency skew and system suspend/resume.
37
+ # These are platform-dependant and may vary in resolution, accuracy,
38
+ # performance, and behaviour in light of system suspend/resume and NTP
39
+ # frequency skew. They should be selected carefully based on your specific
40
+ # needs and environment.
59
41
  #
60
42
  # It is possible to set non-monotonic clock sources here. You probably
61
43
  # shouldn't.
62
44
  #
63
- # Defaults to auto-detect.
45
+ # Defaults to auto-selection from whatever is available from:
64
46
  #
65
- # @param id [Numeric]
66
- def clock_id
67
- @clock_id ||= detect_clock_id
68
- end
47
+ # * +CLOCK_UPTIME_RAW+ (if running under macOS)
48
+ # * +CLOCK_MONOTONIC+
49
+ # * +CLOCK_REALTIME+ (non-monotonic fallback, issues a run-time warning)
50
+ #
51
+ # @param id [Numeric, Symbol]
52
+ attr_accessor :clock_id
53
+
54
+ # The function used to create +Instant+ instances.
55
+ #
56
+ # This function must return a +Numeric+, monotonic count of nanoseconds
57
+ # since a fixed point in the past.
58
+ #
59
+ # Defaults to +-> { Process.clock_gettime(clock_id, :nanosecond) }+.
60
+ #
61
+ # @overload monotonic_function=(function)
62
+ # @param function [#call]
63
+ attr_accessor :monotonic_function
69
64
 
70
65
  # Return the claimed resolution of the given clock id or the configured
71
66
  # +clock_id+, as a +Duration+, or +nil+ if invalid.
72
67
  #
73
- # @param clock [Numeric] Optional clock id instead of default.
74
- def clock_getres(clock = @clock_id)
68
+ # Note per Ruby issue #16740, the practical usability of this method is
69
+ # dubious and non-portable.
70
+ #
71
+ # @param clock [Numeric, Symbol] Optional clock id instead of default.
72
+ def clock_getres(clock = clock_id)
75
73
  Duration.from_nanos(Process.clock_getres(clock, :nanosecond))
76
74
  rescue SystemCallError
77
75
  # suppress errors
78
76
  end
79
77
 
80
- private
78
+ # The symbolic name of the currently-selected +clock_id+, if available.
79
+ #
80
+ # @return [Symbol, nil]
81
+ def clock_name
82
+ return clock_id if clock_id.is_a? Symbol
83
+
84
+ Process.constants.find do |c|
85
+ c.to_s.start_with?('CLOCK_') && Process.const_get(c) == clock_id
86
+ end
87
+ end
81
88
 
82
- def detect_clock_id
83
- name, id, =
84
- [
85
- :CLOCK_MONOTONIC_RAW, # Linux, not affected by NTP frequency adjustments
86
- :CLOCK_UPTIME_RAW, # macOS, not affected by NTP frequency adjustments
87
- :CLOCK_UPTIME_PRECISE, # FreeBSD, increments while system is running
88
- :CLOCK_UPTIME, # OpenBSD, increments while system is running
89
- :CLOCK_MONOTONIC_PRECISE, # FreeBSD, precise monotonic clock
90
- :CLOCK_MONOTONIC, # Standard cross-platform monotonic clock
91
- ]
92
- .each_with_index # Used to force a stable sort in min_by
93
- .filter { |name, _| Process.const_defined?(name) }
94
- .map { |name, index| [name, Process.const_get(name), index] }
95
- .filter_map { |clock| clock.insert(2, clock_getres(clock[1])) }
96
- .min_by { |clock| clock[2..] } # find smallest resolution and index
97
- .tap { |clock| raise NotImplementedError, 'No usable clock' unless clock }
89
+ private
98
90
 
99
- @clock_name = name
100
- id
91
+ def select_clock_id
92
+ if RUBY_PLATFORM.include?('darwin') && Process.const_defined?(:CLOCK_UPTIME_RAW)
93
+ # Offers nanosecond resolution and appears to be slightly faster on two
94
+ # different Macs (M1 and x64)
95
+ #
96
+ # There is also :MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC which calls
97
+ # mach_absolute_time() directly, but documentation for that recommends
98
+ # CLOCK_UPTIME_RAW, and the performance difference is minimal.
99
+ Process::CLOCK_UPTIME_RAW
100
+ elsif Process.const_defined?(:CLOCK_MONOTONIC)
101
+ Process::CLOCK_MONOTONIC
102
+ else
103
+ # There is also :TIMES_BASED_CLOCK_MONOTONIC, but having seen it just return
104
+ # 0 instead of an error on a MSVC build this may be the safer option.
105
+ warn 'No monotonic clock source detected, falling back to CLOCK_REALTIME'
106
+ Process::CLOCK_REALTIME
107
+ end
101
108
  end
102
109
  end
103
110
 
104
111
  self.monotonic_function = -> { Process.clock_gettime(clock_id, :nanosecond) }
105
- clock_id # detect our clock_id early
112
+ self.clock_id = select_clock_id
106
113
 
107
114
  # Create a new +Instant+ from an optional nanosecond measurement.
108
115
  #
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Monotime
4
4
  # Version of the `monotime` gem
5
- MONOTIME_VERSION = '0.8.0'
5
+ MONOTIME_VERSION = '0.8.2'
6
6
  end
data/monotime.gemspec CHANGED
@@ -13,6 +13,8 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = "https://github.com/Freaky/monotime"
14
14
  spec.license = "MIT"
15
15
 
16
+ spec.required_ruby_version = '>= 2.7.0'
17
+
16
18
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
19
  # to allow pushing to a single host or delete this section to allow pushing to any host.
18
20
  if spec.respond_to?(:metadata)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: monotime
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Hurst
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-09-17 00:00:00.000000000 Z
11
+ date: 2023-09-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -102,14 +102,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
102
102
  requirements:
103
103
  - - ">="
104
104
  - !ruby/object:Gem::Version
105
- version: '0'
105
+ version: 2.7.0
106
106
  required_rubygems_version: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  requirements: []
112
- rubygems_version: 3.4.19
112
+ rubygems_version: 3.4.18
113
113
  signing_key:
114
114
  specification_version: 4
115
115
  summary: A sensible interface to the monotonic clock