hitimes 0.3.0-x86-mswin32-60
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.
- data/HISTORY +21 -0
- data/LICENSE +19 -0
- data/README +79 -0
- data/Rakefile +63 -0
- data/examples/benchmarks.rb +86 -0
- data/examples/stats.rb +29 -0
- data/ext/extconf.rb +15 -0
- data/ext/hitimes_ext.c +20 -0
- data/ext/hitimes_instant_clock_gettime.c +20 -0
- data/ext/hitimes_instant_osx.c +16 -0
- data/ext/hitimes_instant_windows.c +27 -0
- data/ext/hitimes_interval.c +340 -0
- data/ext/hitimes_interval.h +73 -0
- data/ext/hitimes_stats.c +241 -0
- data/ext/hitimes_stats.h +30 -0
- data/ext/rbconfig-mingw.rb +178 -0
- data/ext/rbconfig.rb +178 -0
- data/gemspec.rb +55 -0
- data/lib/hitimes.rb +21 -0
- data/lib/hitimes/paths.rb +54 -0
- data/lib/hitimes/timer.rb +223 -0
- data/lib/hitimes/version.rb +42 -0
- data/lib/hitimes_ext.so +0 -0
- data/spec/interval_spec.rb +115 -0
- data/spec/paths_spec.rb +14 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/stats_spec.rb +48 -0
- data/spec/timer_spec.rb +105 -0
- data/spec/version_spec.rb +27 -0
- data/tasks/announce.rake +39 -0
- data/tasks/config.rb +107 -0
- data/tasks/distribution.rake +53 -0
- data/tasks/documentation.rake +33 -0
- data/tasks/extension.rake +64 -0
- data/tasks/rspec.rake +31 -0
- data/tasks/rubyforge.rake +52 -0
- data/tasks/utils.rb +80 -0
- metadata +134 -0
data/HISTORY
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
= Changelog
|
2
|
+
|
3
|
+
== Version 0.3.0
|
4
|
+
|
5
|
+
* switched to extconf for building extensions
|
6
|
+
* first release of windows binary gem
|
7
|
+
* reverted back to normal rdoc
|
8
|
+
|
9
|
+
== Version 0.2.1
|
10
|
+
|
11
|
+
* added Timer#rate method
|
12
|
+
* switched to darkfish rdoc
|
13
|
+
|
14
|
+
== Version 0.2.0
|
15
|
+
|
16
|
+
* Performance improvements
|
17
|
+
* Added Stats class
|
18
|
+
|
19
|
+
== Version 0.1.0
|
20
|
+
|
21
|
+
* Initial completion
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2008 Jeremy Hinegardner
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
== hitimes
|
2
|
+
|
3
|
+
* Homepage[http://copiousfreetime.rubyforge.org/hitimes]
|
4
|
+
* {Rubyforge project}[http://rubyforge.org/projects/copiousfreetime/]
|
5
|
+
* email jeremy at copiousfreetime dot org
|
6
|
+
* git clone url git://github.com/copiousfreetime/hitimes.git
|
7
|
+
|
8
|
+
== INSTALL
|
9
|
+
|
10
|
+
* gem install hitimes
|
11
|
+
|
12
|
+
== DESCRIPTION
|
13
|
+
|
14
|
+
Hitimes is a fast, high resolution timer library for recording performance
|
15
|
+
metrics. It uses the appropriate C method calls for each system to get the
|
16
|
+
highest granularity time increments possible.
|
17
|
+
|
18
|
+
It currently supports any system with the POSIX call clock_gettime() and OSX.
|
19
|
+
Windows is in the works.
|
20
|
+
|
21
|
+
Using Hitimes can be faster than using a series of Time.new calls, and it will
|
22
|
+
have a much higher granularity. It is definitely faster than using
|
23
|
+
Process.times.
|
24
|
+
|
25
|
+
== SYNOPSIS
|
26
|
+
|
27
|
+
Use Hitimes::Interval to calculate only the duration of a block of code
|
28
|
+
|
29
|
+
duration = Hitimes::Interval.measure do
|
30
|
+
# some operation ...
|
31
|
+
end
|
32
|
+
|
33
|
+
puts duration
|
34
|
+
|
35
|
+
Use a Hitimes::Timer to calculate statistics about an iterative operation
|
36
|
+
|
37
|
+
timer = Hitimes::Timer.new
|
38
|
+
collection.each do |item|
|
39
|
+
timer.start
|
40
|
+
# .. do something with item
|
41
|
+
timer.stop
|
42
|
+
end
|
43
|
+
|
44
|
+
puts timer.mean
|
45
|
+
puts timer.median
|
46
|
+
puts timer.max
|
47
|
+
puts timer.min
|
48
|
+
puts timer.stddev
|
49
|
+
|
50
|
+
|
51
|
+
== CHANGES
|
52
|
+
|
53
|
+
Read the HISTORY file.
|
54
|
+
|
55
|
+
== CREDITS
|
56
|
+
|
57
|
+
* Bruce Williams for suggesting the idea
|
58
|
+
|
59
|
+
== MIT LICENSE
|
60
|
+
|
61
|
+
Copyright (c) 2008 Jeremy Hinegardner
|
62
|
+
|
63
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
64
|
+
this software and associated documentation files (the "Software"), to deal in
|
65
|
+
the Software without restriction, including without limitation the rights to
|
66
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
67
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
68
|
+
so, subject to the following conditions:
|
69
|
+
|
70
|
+
The above copyright notice and this permission notice shall be included in all
|
71
|
+
copies or substantial portions of the Software.
|
72
|
+
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
74
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
75
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
76
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
77
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
78
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
79
|
+
SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
|
6
|
+
#-------------------------------------------------------------------------------
|
7
|
+
# make sure our project's top level directory and the lib directory are added to
|
8
|
+
# the ruby search path.
|
9
|
+
#-------------------------------------------------------------------------------
|
10
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__),"ext"))
|
11
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__),"lib"))
|
12
|
+
$: << File.expand_path(File.dirname(__FILE__))
|
13
|
+
|
14
|
+
|
15
|
+
#-------------------------------------------------------------------------------
|
16
|
+
# load the global project configuration and add in the top level clean and
|
17
|
+
# clobber tasks so that other tasks can utilize those constants if necessary
|
18
|
+
# This loads up the defaults for the whole project configuration
|
19
|
+
#-------------------------------------------------------------------------------
|
20
|
+
require 'rubygems'
|
21
|
+
require 'tasks/config.rb'
|
22
|
+
require 'rake/clean'
|
23
|
+
|
24
|
+
#-------------------------------------------------------------------------------
|
25
|
+
# Main configuration for the project, these overwrite the items that are in
|
26
|
+
# tasks/config.rb
|
27
|
+
#-------------------------------------------------------------------------------
|
28
|
+
require 'hitimes/version'
|
29
|
+
require 'hitimes/paths'
|
30
|
+
|
31
|
+
Configuration.for("project") {
|
32
|
+
name "hitimes"
|
33
|
+
version Hitimes::VERSION
|
34
|
+
author "Jeremy Hinegardner"
|
35
|
+
email "jeremy@copiousfreetime.org"
|
36
|
+
homepage "http://copiousfreetime.rubyforge.org/hitimes/"
|
37
|
+
}
|
38
|
+
|
39
|
+
#-------------------------------------------------------------------------------
|
40
|
+
# load up all the project tasks and setup the default task to be the
|
41
|
+
# test:default task.
|
42
|
+
#-------------------------------------------------------------------------------
|
43
|
+
Configuration.for("packaging").files.tasks.each do |tasklib|
|
44
|
+
import tasklib
|
45
|
+
end
|
46
|
+
task :default => 'test:default'
|
47
|
+
|
48
|
+
#-------------------------------------------------------------------------------
|
49
|
+
# Finalize the loading of all pending imports and update the top level clobber
|
50
|
+
# task to depend on all possible sub-level tasks that have a name like
|
51
|
+
# ':clobber' in other namespaces. This allows us to say:
|
52
|
+
#
|
53
|
+
# rake clobber
|
54
|
+
#
|
55
|
+
# and it will get everything.
|
56
|
+
#-------------------------------------------------------------------------------
|
57
|
+
Rake.application.load_imports
|
58
|
+
Rake.application.tasks.each do |t|
|
59
|
+
if t.name =~ /:clobber/ then
|
60
|
+
task :clobber => [t.name]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
#
|
5
|
+
# this is all here in case this example is run from the examples directory
|
6
|
+
#
|
7
|
+
begin
|
8
|
+
require 'hitimes'
|
9
|
+
rescue LoadError => le
|
10
|
+
ext_path = File.expand_path( File.join( File.dirname( __FILE__ ), "..", "ext" ) )
|
11
|
+
lib_path = File.expand_path( File.join( File.dirname( __FILE__ ), "..", "lib" ) )
|
12
|
+
if $:.include?( ext_path ) then
|
13
|
+
raise le
|
14
|
+
end
|
15
|
+
$: << ext_path
|
16
|
+
$: << lib_path
|
17
|
+
retry
|
18
|
+
end
|
19
|
+
|
20
|
+
#----------------------------------------------------------------------
|
21
|
+
# test program to look at the performance sampling time durations using
|
22
|
+
# different methods
|
23
|
+
#----------------------------------------------------------------------
|
24
|
+
|
25
|
+
include Benchmark
|
26
|
+
|
27
|
+
#
|
28
|
+
# Normal apprach to Interval usage
|
29
|
+
#
|
30
|
+
def hitimes_duration_i1
|
31
|
+
i = Hitimes::Interval.new
|
32
|
+
i.start
|
33
|
+
i.stop
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Use the easy access method to start stop an interval
|
38
|
+
#
|
39
|
+
def hitimes_duration_i2
|
40
|
+
Hitimes::Interval.now.stop
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Use a new timer each time
|
45
|
+
#
|
46
|
+
def hitimes_duration_t1
|
47
|
+
Hitimes::Timer.now.stop
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# reuse the same timer over and over
|
52
|
+
#
|
53
|
+
HT = Hitimes::Timer.new
|
54
|
+
def hitimes_duration_t2
|
55
|
+
HT.start
|
56
|
+
HT.stop
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# use the Struct::Tms values and return the difference in User time between 2
|
61
|
+
# successive calls
|
62
|
+
#
|
63
|
+
def process_duration
|
64
|
+
t1 = Process.times.utime
|
65
|
+
Process.times.utime - t1
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Take 2 times and subtract one from the other
|
70
|
+
#
|
71
|
+
def time_duration
|
72
|
+
t1 = Time.now.to_f
|
73
|
+
Time.now.to_f - t1
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
puts "Testing time sampling 100,000 times"
|
78
|
+
|
79
|
+
bm(20) do |x|
|
80
|
+
x.report("Process") { 100_000.times { process_duration } }
|
81
|
+
x.report("Time") { 100_000.times { time_duration } }
|
82
|
+
x.report("Hitimes::Timer 1") { 100_000.times { hitimes_duration_t1 } }
|
83
|
+
x.report("Hitimes::Timer 2") { 100_000.times { hitimes_duration_t2 } }
|
84
|
+
x.report("Hitimes::Interval 1") { 100_000.times { hitimes_duration_i1 } }
|
85
|
+
x.report("Hitimes::Interval 2") { 100_000.times { hitimes_duration_i2 } }
|
86
|
+
end
|
data/examples/stats.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#
|
2
|
+
# this is all here in case this example is run from the examples directory
|
3
|
+
#
|
4
|
+
begin
|
5
|
+
require 'hitimes'
|
6
|
+
rescue LoadError => le
|
7
|
+
%w[ ext lib ].each do |p|
|
8
|
+
path = File.expand_path( File.join( File.dirname( __FILE__ ), "..", p ) )
|
9
|
+
if $:.include?( path ) then
|
10
|
+
raise le
|
11
|
+
end
|
12
|
+
$: << path
|
13
|
+
end
|
14
|
+
retry
|
15
|
+
end
|
16
|
+
|
17
|
+
s = Hitimes::Stats.new
|
18
|
+
dir = ARGV.shift || Dir.pwd
|
19
|
+
Dir.entries( dir ).each do |entry|
|
20
|
+
fs = File.stat( entry )
|
21
|
+
if fs.file? then
|
22
|
+
s.update( fs.size )
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
%w[ count min max mean sum stddev ].each do |m|
|
27
|
+
puts "#{m.rjust(6)} : #{s.send( m ) }"
|
28
|
+
end
|
29
|
+
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'mkmf'
|
3
|
+
|
4
|
+
if Config::CONFIG['host_os'] =~ /darwin/ then
|
5
|
+
$CFLAGS += " -DUSE_INSTANT_OSX=1"
|
6
|
+
$LDFLAGS += " -framework CoreServices"
|
7
|
+
elsif Config::CONFIG['host_os'] =~ /win32/ or Config::CONFIG['host_os'] =~ /mingw/ then
|
8
|
+
$CFLAGS += " -DUSE_INSTANT_WINDOWS=1"
|
9
|
+
else
|
10
|
+
if have_library("rt", "clock_gettime") then
|
11
|
+
$CFLAGS += " -DUSE_INSTANT_CLOCK_GETTIME=1"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
create_makefile('hitimes_ext')
|
data/ext/hitimes_ext.c
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
|
3
|
+
/* Module and Classes */
|
4
|
+
VALUE mH; /* module Hitimes */
|
5
|
+
VALUE eH_Error; /* class Hitimes::Error */
|
6
|
+
|
7
|
+
/*
|
8
|
+
* Document-class: Hitimes::Error
|
9
|
+
*
|
10
|
+
* General error class for the Hitimes module
|
11
|
+
*/
|
12
|
+
void Init_hitimes_ext( )
|
13
|
+
{
|
14
|
+
mH = rb_define_module("Hitimes");
|
15
|
+
|
16
|
+
eH_Error = rb_define_class_under(mH, "Error", rb_eStandardError);
|
17
|
+
|
18
|
+
Init_hitimes_interval();
|
19
|
+
Init_hitimes_stats( );
|
20
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#ifdef USE_INSTANT_CLOCK_GETTIME
|
2
|
+
|
3
|
+
#include "hitimes_interval.h"
|
4
|
+
|
5
|
+
#include <sys/time.h>
|
6
|
+
|
7
|
+
hitimes_instant_t hitimes_get_current_instant( )
|
8
|
+
{
|
9
|
+
struct timespec time;
|
10
|
+
int rc;
|
11
|
+
|
12
|
+
rc = clock_gettime( CLOCK_MONOTONIC, &time);
|
13
|
+
if ( 0 != rc ) {
|
14
|
+
char* e = strerror( rc );
|
15
|
+
rb_raise(eH_Error, "Unable to retrieve time for CLOCK_MONOTONIC : %s", e );
|
16
|
+
}
|
17
|
+
|
18
|
+
return ( ( NANOSECONDS_PER_SECOND * (long)time.tv_sec ) + time.tv_nsec );
|
19
|
+
}
|
20
|
+
#endif
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#ifdef USE_INSTANT_OSX
|
2
|
+
|
3
|
+
#include "hitimes_interval.h"
|
4
|
+
#include <CoreServices/CoreServices.h>
|
5
|
+
|
6
|
+
/*
|
7
|
+
* returns the number of nanoseconds since the machine was booted
|
8
|
+
*/
|
9
|
+
hitimes_instant_t hitimes_get_current_instant( )
|
10
|
+
{
|
11
|
+
Nanoseconds nano = AbsoluteToNanoseconds( UpTime() );
|
12
|
+
|
13
|
+
return *( hitimes_instant_t *)&nano;
|
14
|
+
}
|
15
|
+
|
16
|
+
#endif
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#ifdef USE_INSTANT_WINDOWS
|
2
|
+
|
3
|
+
#include "hitimes_interval.h"
|
4
|
+
|
5
|
+
|
6
|
+
/*
|
7
|
+
* returns the conversion factor, this value is used to convert
|
8
|
+
* the value from hitimes_get_current_instant() into seconds
|
9
|
+
*/
|
10
|
+
double hitimes_instant_conversion_factor()
|
11
|
+
{
|
12
|
+
LARGE_INTEGER ticks_per_second;
|
13
|
+
QueryPerformanceFrequency( &ticks_per_second );
|
14
|
+
return (double)ticks_per_second.QuadPart;
|
15
|
+
}
|
16
|
+
|
17
|
+
/*
|
18
|
+
* returns the number of ticks
|
19
|
+
*/
|
20
|
+
hitimes_instant_t hitimes_get_current_instant()
|
21
|
+
{
|
22
|
+
LARGE_INTEGER tick;
|
23
|
+
QueryPerformanceCounter(&tick);
|
24
|
+
return (hitimes_instant_t)tick.QuadPart;
|
25
|
+
}
|
26
|
+
|
27
|
+
#endif
|
@@ -0,0 +1,340 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) 2008 Jeremy Hinegardner
|
3
|
+
* All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
*
|
5
|
+
* vim: shiftwidth=4
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include "hitimes_interval.h"
|
9
|
+
|
10
|
+
/* Modules and Classes -- defined here */
|
11
|
+
VALUE cH_Interval; /* class Hitimes::Interval */
|
12
|
+
|
13
|
+
/**
|
14
|
+
* Allocator and Deallocator for Interval classes
|
15
|
+
*/
|
16
|
+
|
17
|
+
VALUE hitimes_interval_free(hitimes_interval_t* i)
|
18
|
+
{
|
19
|
+
if ( Qnil != i->duration ) {
|
20
|
+
rb_gc_unregister_address( &(i->duration) );
|
21
|
+
i->duration = Qnil;
|
22
|
+
}
|
23
|
+
xfree( i );
|
24
|
+
return Qnil;
|
25
|
+
}
|
26
|
+
|
27
|
+
VALUE hitimes_interval_alloc(VALUE klass)
|
28
|
+
{
|
29
|
+
VALUE obj;
|
30
|
+
hitimes_interval_t* i = xmalloc( sizeof( hitimes_interval_t ) );
|
31
|
+
|
32
|
+
i->start_instant = 0L;
|
33
|
+
i->stop_instant = 0L;
|
34
|
+
i->duration = Qnil;
|
35
|
+
|
36
|
+
obj = Data_Wrap_Struct(klass, NULL, hitimes_interval_free, i);
|
37
|
+
return obj;
|
38
|
+
}
|
39
|
+
|
40
|
+
/**
|
41
|
+
* call-seq:
|
42
|
+
* Interval.now -> Interval
|
43
|
+
*
|
44
|
+
* Create an interval that has already started
|
45
|
+
*/
|
46
|
+
VALUE hitimes_interval_now( VALUE self )
|
47
|
+
{
|
48
|
+
VALUE obj;
|
49
|
+
hitimes_interval_t *i = xmalloc( sizeof( hitimes_interval_t ) );
|
50
|
+
|
51
|
+
i->start_instant = hitimes_get_current_instant( );
|
52
|
+
i->stop_instant = 0L;
|
53
|
+
i->duration = Qnil;
|
54
|
+
|
55
|
+
obj = Data_Wrap_Struct(cH_Interval, NULL, hitimes_interval_free, i);
|
56
|
+
|
57
|
+
return obj;
|
58
|
+
}
|
59
|
+
|
60
|
+
/**
|
61
|
+
* call-seq:
|
62
|
+
* Interval.measure { } -> Float
|
63
|
+
*
|
64
|
+
* Times the execution of the block returning the number of seconds it took
|
65
|
+
*/
|
66
|
+
VALUE hitimes_interval_measure( VALUE self )
|
67
|
+
{
|
68
|
+
hitimes_instant_t before;
|
69
|
+
hitimes_instant_t after;
|
70
|
+
double duration;
|
71
|
+
|
72
|
+
if ( !rb_block_given_p() ) {
|
73
|
+
rb_raise(eH_Error, "No block given to Interval.measure" );
|
74
|
+
}
|
75
|
+
|
76
|
+
before = hitimes_get_current_instant( );
|
77
|
+
rb_yield( Qnil );
|
78
|
+
after = hitimes_get_current_instant( );
|
79
|
+
|
80
|
+
duration = ( after - before ) / HITIMES_INSTANT_CONVERSION_FACTOR;
|
81
|
+
return rb_float_new( duration );
|
82
|
+
}
|
83
|
+
|
84
|
+
/**
|
85
|
+
* call-seq:
|
86
|
+
* interval.split -> Interval
|
87
|
+
*
|
88
|
+
* Immediately stop the current interval and start a new interval that has a
|
89
|
+
* start_instant equivalent to the stop_interval of self.
|
90
|
+
*/
|
91
|
+
VALUE hitimes_interval_split( VALUE self )
|
92
|
+
{
|
93
|
+
hitimes_interval_t *first;
|
94
|
+
hitimes_interval_t *second = xmalloc( sizeof( hitimes_interval_t ) );
|
95
|
+
VALUE obj;
|
96
|
+
|
97
|
+
Data_Get_Struct( self, hitimes_interval_t, first );
|
98
|
+
first->stop_instant = hitimes_get_current_instant( );
|
99
|
+
|
100
|
+
second->start_instant = first->stop_instant;
|
101
|
+
second->stop_instant = 0L;
|
102
|
+
second->duration = Qnil;
|
103
|
+
|
104
|
+
obj = Data_Wrap_Struct(cH_Interval, NULL, hitimes_interval_free, second);
|
105
|
+
|
106
|
+
return obj;
|
107
|
+
}
|
108
|
+
|
109
|
+
|
110
|
+
/**
|
111
|
+
* call-seq:
|
112
|
+
* interval.start -> boolean
|
113
|
+
*
|
114
|
+
* mark the start of the interval. Calling start on an already started
|
115
|
+
* interval has no effect. An interval can only be started once. If the
|
116
|
+
* interval is truely started +true+ is returned otherwise +false+.
|
117
|
+
*/
|
118
|
+
VALUE hitimes_interval_start( VALUE self )
|
119
|
+
{
|
120
|
+
hitimes_interval_t *i;
|
121
|
+
VALUE rc = Qfalse;
|
122
|
+
|
123
|
+
Data_Get_Struct( self, hitimes_interval_t, i );
|
124
|
+
if ( 0L == i->start_instant ) {
|
125
|
+
i->start_instant = hitimes_get_current_instant( );
|
126
|
+
i->stop_instant = 0L;
|
127
|
+
i->duration = Qnil;
|
128
|
+
|
129
|
+
rc = Qtrue;
|
130
|
+
}
|
131
|
+
|
132
|
+
return rc;
|
133
|
+
}
|
134
|
+
|
135
|
+
|
136
|
+
/**
|
137
|
+
* call-seq:
|
138
|
+
* interval.stop -> bool or Float
|
139
|
+
*
|
140
|
+
* mark the stop of the interval. Calling stop on an already stopped interval
|
141
|
+
* has no effect. An interval can only be stopped once. If the interval is
|
142
|
+
* truely stopped then the duration is returned, otherwise +false+.
|
143
|
+
*/
|
144
|
+
VALUE hitimes_interval_stop( VALUE self )
|
145
|
+
{
|
146
|
+
hitimes_interval_t *i;
|
147
|
+
VALUE rc = Qfalse;
|
148
|
+
|
149
|
+
Data_Get_Struct( self, hitimes_interval_t, i );
|
150
|
+
if ( 0L == i->start_instant ) {
|
151
|
+
rb_raise(eH_Error, "Attempt to stop an interval that has not started.\n" );
|
152
|
+
}
|
153
|
+
|
154
|
+
if ( 0L == i->stop_instant ) {
|
155
|
+
double d;
|
156
|
+
|
157
|
+
i->stop_instant = hitimes_get_current_instant( );
|
158
|
+
d = ( i->stop_instant - i->start_instant ) / HITIMES_INSTANT_CONVERSION_FACTOR;
|
159
|
+
i->duration = rb_float_new( d );
|
160
|
+
rb_gc_register_address( &(i->duration) );
|
161
|
+
rc = i->duration;
|
162
|
+
}
|
163
|
+
|
164
|
+
return rc;
|
165
|
+
}
|
166
|
+
|
167
|
+
/**
|
168
|
+
* call-seq:
|
169
|
+
* interval.started? -> boolean
|
170
|
+
*
|
171
|
+
* returns whether or not the interval has been started
|
172
|
+
*/
|
173
|
+
VALUE hitimes_interval_started( VALUE self )
|
174
|
+
{
|
175
|
+
hitimes_interval_t *i;
|
176
|
+
|
177
|
+
Data_Get_Struct( self, hitimes_interval_t, i );
|
178
|
+
|
179
|
+
return ( 0L == i->start_instant ) ? Qfalse : Qtrue;
|
180
|
+
}
|
181
|
+
|
182
|
+
|
183
|
+
/**
|
184
|
+
* call-seq:
|
185
|
+
* interval.stopped? -> boolean
|
186
|
+
*
|
187
|
+
* returns whether or not the interval has been stopped
|
188
|
+
*/
|
189
|
+
VALUE hitimes_interval_stopped( VALUE self )
|
190
|
+
{
|
191
|
+
hitimes_interval_t *i;
|
192
|
+
|
193
|
+
Data_Get_Struct( self, hitimes_interval_t, i );
|
194
|
+
|
195
|
+
return ( 0L == i->stop_instant ) ? Qfalse : Qtrue;
|
196
|
+
}
|
197
|
+
|
198
|
+
/**
|
199
|
+
* call-seq:
|
200
|
+
* interval.running? -> boolean
|
201
|
+
*
|
202
|
+
* returns whether or not the interval is running or not. This means that it
|
203
|
+
* has started, but not stopped.
|
204
|
+
*/
|
205
|
+
VALUE hitimes_interval_running( VALUE self )
|
206
|
+
{
|
207
|
+
hitimes_interval_t *i;
|
208
|
+
VALUE rc = Qfalse;
|
209
|
+
|
210
|
+
Data_Get_Struct( self, hitimes_interval_t, i );
|
211
|
+
if ( ( 0L != i->start_instant ) && ( 0L == i->stop_instant ) ) {
|
212
|
+
rc = Qtrue;
|
213
|
+
}
|
214
|
+
|
215
|
+
return rc;
|
216
|
+
}
|
217
|
+
|
218
|
+
|
219
|
+
/**
|
220
|
+
* call-seq:
|
221
|
+
* interval.start_instant -> Integer
|
222
|
+
*
|
223
|
+
* The integer representing the start instant of the Interval. This value
|
224
|
+
* is not useful on its own. It is a platform dependent value.
|
225
|
+
*/
|
226
|
+
VALUE hitimes_interval_start_instant( VALUE self )
|
227
|
+
{
|
228
|
+
hitimes_interval_t *i;
|
229
|
+
|
230
|
+
Data_Get_Struct( self, hitimes_interval_t, i );
|
231
|
+
|
232
|
+
return ULL2NUM( i->start_instant );
|
233
|
+
}
|
234
|
+
|
235
|
+
|
236
|
+
/**
|
237
|
+
* call-seq:
|
238
|
+
* interval.stop_instant -> Integer
|
239
|
+
*
|
240
|
+
* The integer representing the stop instant of the Interval. This value
|
241
|
+
* is not useful on its own. It is a platform dependent value.
|
242
|
+
*/
|
243
|
+
VALUE hitimes_interval_stop_instant( VALUE self )
|
244
|
+
{
|
245
|
+
hitimes_interval_t *i;
|
246
|
+
|
247
|
+
Data_Get_Struct( self, hitimes_interval_t, i );
|
248
|
+
|
249
|
+
return ULL2NUM( i->stop_instant );
|
250
|
+
}
|
251
|
+
|
252
|
+
|
253
|
+
|
254
|
+
/**
|
255
|
+
* call-seq:
|
256
|
+
* interval.duration -> Float
|
257
|
+
*
|
258
|
+
* Returns the Float value of the interval, the value is in seconds. If the
|
259
|
+
* interval has not had stop called yet, it will report the number of seconds
|
260
|
+
* in the interval up to the current point in time.
|
261
|
+
*/
|
262
|
+
VALUE hitimes_interval_duration ( VALUE self )
|
263
|
+
{
|
264
|
+
hitimes_interval_t *i;
|
265
|
+
double d;
|
266
|
+
|
267
|
+
Data_Get_Struct( self, hitimes_interval_t, i );
|
268
|
+
|
269
|
+
/**
|
270
|
+
* if stop has not yet been called, then return the amount of time so far
|
271
|
+
*/
|
272
|
+
if ( 0L == i->stop_instant ) {
|
273
|
+
hitimes_instant_t now = hitimes_get_current_instant( );
|
274
|
+
d = ( now - i->start_instant ) / HITIMES_INSTANT_CONVERSION_FACTOR;
|
275
|
+
return rb_float_new( d );
|
276
|
+
}
|
277
|
+
|
278
|
+
|
279
|
+
/*
|
280
|
+
* stop has been called, calculate the duration and save the result
|
281
|
+
*/
|
282
|
+
if ( Qnil == i->duration ) {
|
283
|
+
d = ( i->stop_instant - i->start_instant ) / HITIMES_INSTANT_CONVERSION_FACTOR;
|
284
|
+
i->duration = rb_float_new( d );
|
285
|
+
rb_gc_register_address( &(i->duration) );
|
286
|
+
}
|
287
|
+
|
288
|
+
return i->duration;
|
289
|
+
}
|
290
|
+
|
291
|
+
|
292
|
+
/**
|
293
|
+
* Document-class: Hitimes::Interval
|
294
|
+
*
|
295
|
+
* This is the lowest level timing mechanism available. It allows for easy
|
296
|
+
* measuring based upon a block:
|
297
|
+
*
|
298
|
+
* duration = Interval.measure { ... }
|
299
|
+
*
|
300
|
+
* Or measuring something specifically
|
301
|
+
*
|
302
|
+
* interval = Interval.new
|
303
|
+
* interval.start
|
304
|
+
* duration = interval.stop
|
305
|
+
*
|
306
|
+
* Allocating and starting an interval can be done in one method call with
|
307
|
+
*
|
308
|
+
* interval = Interval.now
|
309
|
+
*
|
310
|
+
* Interval is useful when you only need to track a single interval of time, or
|
311
|
+
* if you do not want to track statistics about an operation.
|
312
|
+
*
|
313
|
+
*/
|
314
|
+
void Init_hitimes_interval()
|
315
|
+
{
|
316
|
+
mH = rb_define_module("Hitimes");
|
317
|
+
|
318
|
+
cH_Interval = rb_define_class_under( mH, "Interval", rb_cObject );
|
319
|
+
rb_define_alloc_func( cH_Interval, hitimes_interval_alloc );
|
320
|
+
|
321
|
+
rb_define_module_function( cH_Interval, "now", hitimes_interval_now, 0 ); /* in hitimes_interval.c */
|
322
|
+
rb_define_module_function( cH_Interval, "measure", hitimes_interval_measure, 0 ); /* in hitimes_interval.c */
|
323
|
+
|
324
|
+
rb_define_method( cH_Interval, "to_f", hitimes_interval_duration, 0 ); /* in hitimes_interval.c */
|
325
|
+
rb_define_method( cH_Interval, "to_seconds", hitimes_interval_duration, 0 ); /* in hitimes_interval.c */
|
326
|
+
rb_define_method( cH_Interval, "duration", hitimes_interval_duration, 0 ); /* in hitimes_interval.c */
|
327
|
+
rb_define_method( cH_Interval, "length", hitimes_interval_duration, 0 ); /* in hitimes_interval.c */
|
328
|
+
|
329
|
+
rb_define_method( cH_Interval, "started?", hitimes_interval_started, 0 ); /* in hitimes_interval.c */
|
330
|
+
rb_define_method( cH_Interval, "running?", hitimes_interval_running, 0 ); /* in hitimes_interval.c */
|
331
|
+
rb_define_method( cH_Interval, "stopped?", hitimes_interval_stopped, 0 ); /* in hitimes_interval.c */
|
332
|
+
|
333
|
+
rb_define_method( cH_Interval, "start_instant", hitimes_interval_start_instant, 0 ); /* in hitimes_interval.c */
|
334
|
+
rb_define_method( cH_Interval, "stop_instant", hitimes_interval_stop_instant, 0 ); /* in hitimes_interval.c */
|
335
|
+
|
336
|
+
rb_define_method( cH_Interval, "start", hitimes_interval_start, 0); /* in hitimes_interval.c */
|
337
|
+
rb_define_method( cH_Interval, "stop", hitimes_interval_stop, 0); /* in hitimes_interval.c */
|
338
|
+
rb_define_method( cH_Interval, "split", hitimes_interval_split, 0); /* in hitimes_interval.c */
|
339
|
+
|
340
|
+
}
|