monotime 0.8.0 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
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