File Coverage

blib/lib/Time/HiRes/Sleep/Until.pm
Criterion Covered Total %
statement 36 36 100.0
branch 5 6 83.3
condition 4 6 66.6
subroutine 11 11 100.0
pod 6 6 100.0
total 62 65 95.3


line stmt bran cond sub pod time code
1             package Time::HiRes::Sleep::Until;
2 1     1   82716 use strict;
  1         3  
  1         29  
3 1     1   5 use warnings;
  1         2  
  1         27  
4 1     1   8 use base qw{Package::New};
  1         2  
  1         499  
5 1     1   253 use Time::HiRes qw{};
  1         2  
  1         14  
6 1     1   453 use Math::Round qw{};
  1         1293  
  1         313  
7              
8             our $VERSION = '0.09';
9              
10             =head1 NAME
11              
12             Time::HiRes::Sleep::Until - Provides common ways to sleep until...
13              
14             =head1 SYNOPSIS
15              
16             use Time::HiRes::Sleep::Until;
17             my $su = Time::HiRes::Sleep::Until->new;
18             my $slept = $su->epoch($epoch); # epoch is a calculated time + $seconds
19             my $slept = $su->mark(20); # sleep until 20 second mark of the clock :00, :20, or :40
20             my $slept = $su->second(45); # sleep until 45 seconds after the minute
21              
22              
23             =head1 DESCRIPTION
24              
25             Sleep Until provides sleep wrappers for sleep functions that I commonly need. These methods are simply wrappers around L and L.
26              
27             We use this package to make measurements at the same time within the minute for integration with RRDtool.
28              
29             =head1 USAGE
30              
31             use strict;
32             use warnings;
33             use DateTime;
34             use Time::HiRes::Sleep::Until;
35             my $su = Time::HiRes::Sleep::Until->new;
36             do {
37             print DateTime->now, "\n"; #make a measurment three times a minute
38             } while ($su->mark(20));
39              
40             Perl One liner
41              
42             perl -MTime::HiRes::Sleep::Until -e 'printf "Slept: %s\n", Time::HiRes::Sleep::Until->new->top'
43              
44             =head1 CONSTRUCTOR
45              
46             =head2 new
47              
48             use Time::HiRes::Sleep::Until;
49             my $su = Time::HiRes::Sleep::Until->new;
50              
51             =head1 METHODS
52              
53             =head2 epoch
54              
55             Sleep until provided epoch in float seconds.
56              
57             while ($CONTINUE) {
58             my $sleep_epoch = $su->time + 60/8;
59             do_work(); #run process that needs to run back to back but not more than 8 times per minute
60             $su->epoch($sleep_epoch); #sleep(7.5 - runtime). if runtime > 7.5 seconds does not sleep
61             }
62              
63             =cut
64              
65             sub epoch {
66 8     8 1 1007146 my $self = shift;
67 8   50     54 my $epoch = shift || 0; #default is 1970-01-01 00:00
68 8         45 my $sleep = $epoch - Time::HiRes::time();
69 8 100       213860320 return $sleep <= 0 ? 0 : Time::HiRes::sleep($sleep);
70             }
71              
72             =head2 mark
73              
74             Sleep until next second mark;
75              
76             my $slept = $su->mark(20); # 20 second mark, i.e. 3 times a minute on the 20s
77             my $slept = $su->mark(10); # 10 second mark, i.e. 6 times a minute on the 10s
78             my $slept = $su->mark(6); # 6 second mark, i.e. 10 times a minute on 0,6,12,...
79              
80             =cut
81              
82             sub mark {
83 2     2 1 3975 my $time = Time::HiRes::time();
84 2         10 my $self = shift;
85 2   50     16 my $mark = shift || 0;
86 2 50       15 die("Error: mark requires parameter to be greater than zero.") unless $mark > 0;
87 2         16 my $epoch = Math::Round::nhimult($mark => $time); #next mark
88 2         73 return $self->epoch($epoch);
89             }
90              
91             =head2 second
92              
93             Sleep until the provided seconds after the minute
94              
95             my $slept = $su->second(0); #sleep until top of minute
96             my $slept = $su->second(30); #sleep until bottom of minute
97              
98             =cut
99              
100             sub second {
101 4     4 1 8006 my $time = Time::HiRes::time();
102 4         14 my $self = shift;
103 4   100     41 my $second = shift || 0; #default is top of the minute
104 4         30 my $min_next = Math::Round::nhimult(60 => $time);
105 4         118 my $min_last = $min_next - 60;
106 4 100       56 return $time < $min_last + $second
107             ? $self->epoch($min_last + $second)
108             : $self->epoch($min_next + $second);
109             }
110              
111             =head2 top
112              
113             Sleep until the top of the minute
114              
115             my $slept = $su->top; #alias for $su->second(0);
116              
117             =cut
118              
119             sub top {
120 2     2 1 4019 my $self = shift;
121 2         11 return $self->second(0);
122             }
123              
124             =head2 time
125              
126             Method to access Time::HiRes time without another import.
127              
128             =cut
129              
130 1     1 1 9212 sub time {return Time::HiRes::time()};
131              
132             =head2 sleep
133              
134             Method to access Time::HiRes sleep without another import.
135              
136             =cut
137              
138             sub sleep {
139 1     1 1 723 my $self = shift;
140 1         500304 return Time::HiRes::sleep(@_);
141             }
142              
143             =head1 LIMITATIONS
144              
145             The mathematics add a small amount of delay for which we do not account. Testing routinely passes with 100th of a second accuracy and typically with millisecond accuracy.
146              
147             =head1 BUGS
148              
149             Please log on GitHub
150              
151             =head1 AUTHOR
152              
153             Michael R. Davis
154              
155             =head1 COPYRIGHT
156              
157             MIT License
158              
159             Copyright (c) 2023 Michael R. Davis
160              
161             =head1 SEE ALSO
162              
163             L, L
164              
165             =cut
166              
167             1;