pax_global_header00006660000000000000000000000064123170135670014517gustar00rootroot0000000000000052 comment=074d94fcbf2b368b0f775d0cc78b8625294dcb9c ruby-hitimes-1.2.1/000077500000000000000000000000001231701356700141415ustar00rootroot00000000000000ruby-hitimes-1.2.1/CONTRIBUTING.md000066400000000000000000000037361231701356700164030ustar00rootroot00000000000000# Hi there! I see you are interested in contributing. That is wonderful. I love contributions. I guarantee that there are bugs in this software. And I guarantee that there is a feature you want that is not in here yet. As such, any and all bugs reports are gratefully accepted, bugfixes even more so. Helping out with bugs is the easiest way to contribute. ## The Quick Version * Have a [GitHub Account][]. * Search the [GitHub Issues][] and see if your issue already present. If so add your comments, :thumbsup:, etc. * Issue not there? Not a problem, open up a [new issue][]. * **Bug reports** please be as detailed as possible. Include: * full ruby engine and version: `ruby -e 'puts RUBY_DESCRIPTION'` * operating system and version * version of hitimes `ruby -rubygems -e "require 'hitimes'; puts Hitimes::VERSION"` * as much detail about the bug as possible so I can replicated it. Feel free to link in a [gist][] * **New Feature** * What the new feature should do. * What benefit the new feature brings to the project. * Fork the [repo][]. * Create a new branch for your issue: `git checkout -b issue/my-issue` * Lovingly craft your contribution: * `rake develop` to get started, or if you prefer bundler `rake develop:using_bunder && bundle`. * `rake test` to run tests * Make sure that `rake test` passes. Its important, I said it twice. * Add yourself to the contributors section below. * Submit your [pull request][]. # Contributors * Jeremy Hinegardner [GitHub Account]: https://github.com/signup/free "GitHub Signup" [GitHub Issues]: https://github.com/copiousfreetime/hitimes/issues "Hitimes Issues" [new issue]: https://github.com/copiousfreetime/hitimes/issues/new "New Hitimes Issue" [gist]: https://gist.github.com/ "New Gist" [repo]: https://github.com/copiousfreetime/hitimes "hitimes Repo" [pull request]: https://help.github.com/articles/using-pull-requests "Using Pull Requests" ruby-hitimes-1.2.1/HISTORY.md000066400000000000000000000045471231701356700156360ustar00rootroot00000000000000# Hitimes Changelog ## Version 1.2.1 2013-03-12 * Update dependencies * Ruby 2.0 fixes * Switch to Markdown, Yeah RDoc 4.0! ## Version 1.2.0 2013-02-09 * Update dependencies * Documentation cleanup * Fix use of deprecated JRuby API in java extension * Fix use of deprecated OSX system calls in C extension * Make hitimes -w clean * Fix ambiguity of calling duration on non-started Interval * Use RbConfig instead of Config (eregon) * Added Hitimes.measure * Switch to using rake-compiler for cross compilation of gems ## Version 1.1.1 2010-09-04 * Remove the unnecessary dependencies that should be development dependencies ## Version 1.1.0 2010-07-28 * Add a pure java extension so hitimes may be used in jruby with the same API ## Version 1.0.5 2010-07-20 * Fix 'circular require considered harmful' warnings in 1.9.x (reported by Roger Pack) * Fix 'method redefined' warnings in 1.9.x (reported by Roger Pack) ## Version 1.0.4 2009-08-01 * Add in support for x86-mingw32 gem * Add version subdirectory for extension on all platforms ## Version 1.0.3 2009-06-28 * Fix bug with time.h on linode (reported by Roger Pack) * Fix potential garbage collection issue with Interval class * Windows gem is now a fat binary to support installing in 1.8 or 1.9 from the same gem ## Version 1.0.1 2009-06-12 * Fix examples * performance tuning, new Hitimes::Metric derived classes are faster than old Timer class ## Version 1.0.0 2009-06-12 * Major version bump with complete refactor of the metric collection API * 3 types of metrics now instead of just 1 Timer * Hitimes::ValueMetric * Hitimes::TimedMetric * Hitimes::TimedValueMetric * The ability to convert all metrics #to_hash * Updated documentation with examples using each metric type ## Version 0.4.1 2009-02-19 * change to ISC License * fix bug in compilation on gentoo ## Version 0.4.0 2008-12-20 * Added new stat 'rate' * Added new stat method to_hash * Added Hitimes::MutexedStats class for threadsafe stats collection - not needed when used in MRI 1.8.x * remove stale dependency on mkrf ## Version 0.3.0 * switched to extconf for building extensions * first release of windows binary gem * reverted back to normal rdoc ## Version 0.2.1 * added Timer#rate method * switched to darkfish rdoc ## Version 0.2.0 * Performance improvements * Added Hitimes::Stats class ## Version 0.1.0 * Initial completion ruby-hitimes-1.2.1/LICENSE000066400000000000000000000014441231701356700151510ustar00rootroot00000000000000ISC LICENSE - http://opensource.org/licenses/isc-license.txt Copyright (c) 2008-2012 Jeremy Hinegardner Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ruby-hitimes-1.2.1/Manifest.txt000066400000000000000000000021371231701356700164530ustar00rootroot00000000000000CONTRIBUTING.md HISTORY.md LICENSE Manifest.txt README.md Rakefile examples/benchmarks.rb examples/stats.rb ext/hitimes/c/extconf.rb ext/hitimes/c/hitimes.c ext/hitimes/c/hitimes_instant_clock_gettime.c ext/hitimes/c/hitimes_instant_osx.c ext/hitimes/c/hitimes_instant_windows.c ext/hitimes/c/hitimes_interval.c ext/hitimes/c/hitimes_interval.h ext/hitimes/c/hitimes_stats.c ext/hitimes/c/hitimes_stats.h ext/hitimes/java/src/hitimes/Hitimes.java ext/hitimes/java/src/hitimes/HitimesInterval.java ext/hitimes/java/src/hitimes/HitimesService.java ext/hitimes/java/src/hitimes/HitimesStats.java lib/hitimes.rb lib/hitimes/metric.rb lib/hitimes/mutexed_stats.rb lib/hitimes/paths.rb lib/hitimes/stats.rb lib/hitimes/timed_metric.rb lib/hitimes/timed_value_metric.rb lib/hitimes/value_metric.rb lib/hitimes/version.rb spec/hitimes_spec.rb spec/interval_spec.rb spec/metric_spec.rb spec/mutex_stats_spec.rb spec/paths_spec.rb spec/spec_helper.rb spec/stats_spec.rb spec/timed_metric_spec.rb spec/timed_value_metric_spec.rb spec/value_metric_spec.rb spec/version_spec.rb tasks/default.rake tasks/extension.rake tasks/this.rb ruby-hitimes-1.2.1/README.md000066400000000000000000000103141231701356700154170ustar00rootroot00000000000000## hitimes * [Homepage](http://github.com/copiousfreetime/hitimes) * [Github project](http://github.com.org/copiousfreetime/hitimes) * email jeremy at copiousfreetime dot org * `git clone url git://github.com/copiousfreetime/hitimes.git` ## INSTALL * `gem install hitimes` ## DESCRIPTION Hitimes is a fast, high resolution timer library for recording performance metrics. It uses the appropriate low method calls for each system to get the highest granularity time increments possible. It currently supports any of the following systems: * any system with the POSIX call `clock_gettime()` * Mac OS X * Windows * JRuby Using Hitimes can be faster than using a series of `Time.new` calls, and it will have a much higher granularity. It is definitely faster than using `Process.times`. ## SYNOPSIS ### Interval Use Hitimes::Interval to calculate only the duration of a block of code ``` ruby duration = Hitimes::Interval.measure do # some operation ... end puts duration ``` ### TimedMetric Use a Hitimes::TimedMetric to calculate statistics about an iterative operation ``` ruby timed_metric = Hitimes::TimedMetric.new('operation on items') ``` Explicitly use `start` and `stop`: ``` ruby collection.each do |item| timed_metric.start # .. do something with item timed_metric.stop end ``` Or use the block. In TimedMetric the return value of +measure+ is the return value of the block ``` ruby collection.each do |item| result_of_do_something = timed_metric.measure { do_something( item ) } end ``` And then look at the stats ``` ruby puts timed_metric.mean puts timed_metric.max puts timed_metric.min puts timed_metric.stddev puts timed_metric.rate ``` ### ValueMetric Use a Hitimes::ValueMetric to calculate statistics about measured samples ``` ruby value_metric = Hitimes::ValueMetric.new( 'size of thing' ) loop do # ... do stuff changing sizes of 'thing' value_metric.measure( thing.size ) # ... do other stuff that may change size of thing end puts value_metric.mean puts value_metric.max puts value_metric.min puts value_metric.stddev puts value_metric.rate ``` ### TimedValueMetric Use a Hitimes::TimedValueMetric to calculate statistics about batches of samples ``` ruby timed_value_metric = Hitimes::TimedValueMetric.new( 'batch times' ) loop do batch = ... # get a batch of things timed_value_metric.start # .. do something with batch timed_value_metric.stop( batch.size ) end puts timed_value_metric.rate puts timed_value_metric.timed_stats.mean puts timed_value_metric.timed_stats.max puts timed_value_metric.timed_stats.min puts timed_value_metric.timed_stats.stddev puts timed_value_metric.value_stats.mean puts timed_value_metric.value_stats.max puts timed_value_metric.value_stats.min puts timed_value_metric.value_stats.stddev ``` ## CHANGES Read the HISTORY.md file. ## BUILDING FOR WINDOWS [rake-compiler](https://github.com/luislavena/rake-compiler) is use for building the windows version. For me, on OSX to cross compile the process is: ``` % gem install rake-compiler # in each rvm instance, 1.8.7, 1.9.3 % rvm use 2.0.0@hitimes % rake-compiler cross-ruby VERSION=2.0.0-p0 # or latest % rvm use 1.9.3@hitimes % rake-compiler cross-ruby VERSION=1.9.3-p374 # or latest % rvm use 1.8.7@hitimes % rake-compiler cross-ruby VERSION=1.8.7-p371 # This only works via 1.8.7 at the current moment % rake cross native gem RUBY_CC_VERSION=1.8.7:1.9.3:2.0.0 ``` ## CREDITS * [Bruce Williams](https://github.com/bruce) for suggesting the idea ## ISC License Copyright (c) 2008-2012 Jeremy Hinegardner Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ruby-hitimes-1.2.1/Rakefile000066400000000000000000000013701231701356700156070ustar00rootroot00000000000000# vim: syntax=ruby load 'tasks/this.rb' This.name = "hitimes" This.author = "Jeremy Hinegardner" This.email = "jeremy@copiousfreetime.org" This.homepage = "http://github.com/copiousfreetime/#{ This.name }" This.ruby_gemspec do |spec| spec.add_development_dependency( 'rake' , '~> 10.0.3') spec.add_development_dependency( 'rspec' , '~> 2.13.0' ) spec.add_development_dependency( 'rdoc' , '~> 4.0' ) spec.add_development_dependency( 'json' , '~> 1.7.7' ) spec.add_development_dependency( 'rake-compiler', '~> 0.8.3' ) spec.extensions.concat This.extension_conf_files end This.java_gemspec( This.ruby_gemspec ) do |spec| spec.extensions.clear end load 'tasks/default.rake' load 'tasks/extension.rake' ruby-hitimes-1.2.1/checksums.yaml.gz000066400000000000000000000004161231701356700174320ustar00rootroot00000000000000=?Qe1R@E" B:;{O keKvr~}.(ٛvT$/-rMkz%%p&fITQ+83u뵋@ZUXfcf4}mb;7,2r_9Ƭ`tU REVu 2c *vN>k\!VC4hgg{67.θCm~#Ns)0Wa }{x PEruby-hitimes-1.2.1/examples/000077500000000000000000000000001231701356700157575ustar00rootroot00000000000000ruby-hitimes-1.2.1/examples/benchmarks.rb000066400000000000000000000054331231701356700204260ustar00rootroot00000000000000require 'benchmark' require 'time' # # this is all here in case this example is run from the examples directory # begin require 'hitimes' rescue LoadError => le ext_path = File.expand_path( File.join( File.dirname( __FILE__ ), "..", "ext" ) ) lib_path = File.expand_path( File.join( File.dirname( __FILE__ ), "..", "lib" ) ) if $:.include?( ext_path ) then raise le end $: << ext_path $: << lib_path retry end #---------------------------------------------------------------------- # test program to look at the performance sampling time durations using # different methods #---------------------------------------------------------------------- include Benchmark # # Normal apprach to Interval usage # def hitimes_duration_i1 i = Hitimes::Interval.new i.start i.stop end # # Use the easy access method to start stop an interval # def hitimes_duration_i2 Hitimes::Interval.now.stop end # # Use a new timer each time # def hitimes_duration_t1 Hitimes::TimedMetric.now('duration_t1').stop end # # reuse the same timer over and over # HT2= Hitimes::TimedMetric.new( 'duration_t2' ) def hitimes_duration_t2 HT2.start HT2.stop end HT3 = Hitimes::TimedMetric.new( 'duration_t3' ) def hitimes_duration_t3 HT3.measure { nil } end # # Check out the speed of the TimedValueMetric too # def hitimes_duration_tv1 Hitimes::TimedValueMetric.now( 'duration_tv1' ).stop( 42 ) end HTV2 = Hitimes::TimedValueMetric.new( 'duration_tv2' ) def hitimes_duration_tv2 HTV2.start HTV2.stop( 42 ) end HTV3 = Hitimes::TimedValueMetric.new( 'duration_tv3' ) def hitimes_duration_tv3 HTV3.measure( 42 ) { nil } end # # use the Struct::Tms values and return the difference in User time between 2 # successive calls # def process_duration t1 = Process.times.utime Process.times.utime - t1 end # # Take 2 times and subtract one from the other # def time_duration t1 = Time.now.to_f Time.now.to_f - t1 end puts "Testing time sampling 100,000 times" bm(30) do |x| x.report("Process") { 100_000.times { process_duration } } x.report("Time") { 100_000.times { time_duration } } x.report("Hitimes::TimedMetric 1") { 100_000.times { hitimes_duration_t1 } } x.report("Hitimes::TimedMetric 2") { 100_000.times { hitimes_duration_t2 } } x.report("Hitimes::TimedMetric 3") { 100_000.times { hitimes_duration_t3 } } x.report("Hitimes::Interval 1") { 100_000.times { hitimes_duration_i1 } } x.report("Hitimes::Interval 2") { 100_000.times { hitimes_duration_i2 } } x.report("Hitimes::TimedValueMetric 1") { 100_000.times { hitimes_duration_tv1 } } x.report("Hitimes::TimedValueMetric 2") { 100_000.times { hitimes_duration_tv2 } } x.report("Hitimes::TimedValueMetric 3") { 100_000.times { hitimes_duration_tv3 } } end ruby-hitimes-1.2.1/examples/stats.rb000066400000000000000000000011211231701356700174350ustar00rootroot00000000000000# # this is all here in case this example is run from the examples directory # begin require 'hitimes' rescue LoadError => le %w[ ext lib ].each do |p| path = File.expand_path( File.join( File.dirname( __FILE__ ), "..", p ) ) if $:.include?( path ) then raise le end $: << path end retry end s = Hitimes::Stats.new dir = ARGV.shift || Dir.pwd Dir.entries( dir ).each do |entry| fs = File.stat( entry ) if fs.file? then s.update( fs.size ) end end Hitimes::Stats::STATS.each do |m| puts "#{m.rjust(6)} : #{s.send( m ) }" end puts s.to_hash.inspect ruby-hitimes-1.2.1/ext/000077500000000000000000000000001231701356700147415ustar00rootroot00000000000000ruby-hitimes-1.2.1/ext/hitimes/000077500000000000000000000000001231701356700164035ustar00rootroot00000000000000ruby-hitimes-1.2.1/ext/hitimes/c/000077500000000000000000000000001231701356700166255ustar00rootroot00000000000000ruby-hitimes-1.2.1/ext/hitimes/c/extconf.rb000066400000000000000000000010641231701356700206210ustar00rootroot00000000000000require 'rbconfig' require 'mkmf' if RbConfig::CONFIG['host_os'] =~ /darwin/ then $CFLAGS += " -DUSE_INSTANT_OSX=1 -Wall" $LDFLAGS += " -framework CoreServices" elsif RbConfig::CONFIG['host_os'] =~ /win32/ or RbConfig::CONFIG['host_os'] =~ /mingw/ then $CFLAGS += " -DUSE_INSTANT_WINDOWS=1" else if have_library("rt", "clock_gettime") then $CFLAGS += " -DUSE_INSTANT_CLOCK_GETTIME=1" end end # put in a different location if on windows so we can have fat binaries subdir = RUBY_VERSION.gsub(/\.\d$/,'') create_makefile("hitimes/#{subdir}/hitimes") ruby-hitimes-1.2.1/ext/hitimes/c/hitimes.c000066400000000000000000000007211231701356700204330ustar00rootroot00000000000000#include #include "hitimes_interval.h" /* Module and Classes */ VALUE mH; /* module Hitimes */ VALUE eH_Error; /* class Hitimes::Error */ /* * Document-class: Hitimes::Error * * General error class for the Hitimes module */ void Init_hitimes( ) { mH = rb_define_module("Hitimes"); eH_Error = rb_define_class_under(mH, "Error", rb_eStandardError); Init_hitimes_interval(); Init_hitimes_stats( ); } ruby-hitimes-1.2.1/ext/hitimes/c/hitimes_instant_clock_gettime.c000066400000000000000000000011421231701356700250620ustar00rootroot00000000000000#ifdef USE_INSTANT_CLOCK_GETTIME #include "hitimes_interval.h" #include #ifndef CLOCK_MONOTONIC # include # ifndef CLOCK_MONOTONIC # ifdef __linux__ # include # endif # endif #endif hitimes_instant_t hitimes_get_current_instant( ) { struct timespec time; int rc; rc = clock_gettime( CLOCK_MONOTONIC, &time); if ( 0 != rc ) { char* e = strerror( rc ); rb_raise(eH_Error, "Unable to retrieve time for CLOCK_MONOTONIC : %s", e ); } return ( ( NANOSECONDS_PER_SECOND * (long)time.tv_sec ) + time.tv_nsec ); } #endif ruby-hitimes-1.2.1/ext/hitimes/c/hitimes_instant_osx.c000066400000000000000000000023561231701356700230720ustar00rootroot00000000000000#ifdef USE_INSTANT_OSX #include "hitimes_interval.h" #include #include /* All this OSX code is adapted from http://developer.apple.com/library/mac/#qa/qa1398/_index.html */ /* * returns the conversion factor, this value is used to convert * the value from hitimes_get_current_instant() into seconds */ long double hitimes_instant_conversion_factor() { static mach_timebase_info_data_t s_timebase_info; static long double conversion_factor; static uint64_t nano_conversion; /** * If this is the first time we've run, get the timebase. * We can use denom == 0 to indicate that s_timebase_info is * uninitialised because it makes no sense to have a zero * denominator is a fraction. */ if ( s_timebase_info.denom == 0 ) { mach_timebase_info(&s_timebase_info); nano_conversion = s_timebase_info.numer / s_timebase_info.denom; conversion_factor = (long double) (nano_conversion) * (1e9l); } return conversion_factor; } /* * returns the mach absolute time, which has no meaning outside of a conversion * factor. */ hitimes_instant_t hitimes_get_current_instant() { return mach_absolute_time(); } #endif ruby-hitimes-1.2.1/ext/hitimes/c/hitimes_instant_windows.c000066400000000000000000000011061231701356700237430ustar00rootroot00000000000000#ifdef USE_INSTANT_WINDOWS #include "hitimes_interval.h" /* * returns the conversion factor, this value is used to convert * the value from hitimes_get_current_instant() into seconds */ long double hitimes_instant_conversion_factor() { LARGE_INTEGER ticks_per_second; QueryPerformanceFrequency( &ticks_per_second ); return (double)ticks_per_second.QuadPart; } /* * returns the number of ticks */ hitimes_instant_t hitimes_get_current_instant() { LARGE_INTEGER tick; QueryPerformanceCounter(&tick); return (hitimes_instant_t)tick.QuadPart; } #endif ruby-hitimes-1.2.1/ext/hitimes/c/hitimes_interval.c000066400000000000000000000237341231701356700223500ustar00rootroot00000000000000/** * Copyright (c) 2008 Jeremy Hinegardner * All rights reserved. See LICENSE and/or COPYING for details. * * vim: shiftwidth=4 */ #include "hitimes_interval.h" /* Modules and Classes -- defined here */ VALUE cH_Interval; /* class Hitimes::Interval */ /** * Allocator and Deallocator for Interval classes */ VALUE hitimes_interval_free(hitimes_interval_t* i) { xfree( i ); return Qnil; } VALUE hitimes_interval_alloc(VALUE klass) { VALUE obj; hitimes_interval_t* i = xmalloc( sizeof( hitimes_interval_t ) ); i->start_instant = 0L; i->stop_instant = 0L; i->duration = -1.0l; obj = Data_Wrap_Struct(klass, NULL, hitimes_interval_free, i); return obj; } /** * call-seq: * Interval.now -> Interval * * Create an interval that has already started */ VALUE hitimes_interval_now( ) { VALUE obj; hitimes_interval_t *i = xmalloc( sizeof( hitimes_interval_t ) ); i->start_instant = hitimes_get_current_instant( ); i->stop_instant = 0L; i->duration = -1.0l; obj = Data_Wrap_Struct(cH_Interval, NULL, hitimes_interval_free, i); return obj; } /** * call-seq: * Interval.measure { } -> Float * * Times the execution of the block returning the number of seconds it took */ VALUE hitimes_interval_measure( ) { hitimes_instant_t before; hitimes_instant_t after; long double duration; if ( !rb_block_given_p() ) { rb_raise(eH_Error, "No block given to Interval.measure" ); } before = hitimes_get_current_instant( ); rb_yield( Qnil ); after = hitimes_get_current_instant( ); duration = ( after - before ) / HITIMES_INSTANT_CONVERSION_FACTOR; return rb_float_new( duration ); } /** * call-seq: * interval.split -> Interval * * Immediately stop the current interval and start a new interval that has a * start_instant equivalent to the stop_interval of self. */ VALUE hitimes_interval_split( VALUE self ) { hitimes_interval_t *first; hitimes_interval_t *second = xmalloc( sizeof( hitimes_interval_t ) ); VALUE obj; Data_Get_Struct( self, hitimes_interval_t, first ); first->stop_instant = hitimes_get_current_instant( ); second->start_instant = first->stop_instant; second->stop_instant = 0L; second->duration = -1.0l; obj = Data_Wrap_Struct(cH_Interval, NULL, hitimes_interval_free, second); return obj; } /** * call-seq: * interval.start -> boolean * * mark the start of the interval. Calling start on an already started * interval has no effect. An interval can only be started once. If the * interval is truely started +true+ is returned otherwise +false+. */ VALUE hitimes_interval_start( VALUE self ) { hitimes_interval_t *i; VALUE rc = Qfalse; Data_Get_Struct( self, hitimes_interval_t, i ); if ( 0L == i->start_instant ) { i->start_instant = hitimes_get_current_instant( ); i->stop_instant = 0L; i->duration = -1.0l; rc = Qtrue; } return rc; } /** * call-seq: * interval.stop -> bool or Float * * mark the stop of the interval. Calling stop on an already stopped interval * has no effect. An interval can only be stopped once. If the interval is * truely stopped then the duration is returned, otherwise +false+. */ VALUE hitimes_interval_stop( VALUE self ) { hitimes_interval_t *i; VALUE rc = Qfalse; Data_Get_Struct( self, hitimes_interval_t, i ); if ( 0L == i->start_instant ) { rb_raise(eH_Error, "Attempt to stop an interval that has not started" ); } if ( 0L == i->stop_instant ) { i->stop_instant = hitimes_get_current_instant( ); i->duration = ( i->stop_instant - i->start_instant ) / HITIMES_INSTANT_CONVERSION_FACTOR; rc = rb_float_new( i->duration ); } return rc; } /** * call-seq: * interval.duration_so_far -> Float or false * * return how the duration so far. This will return the duration from the time * the Interval was started if the interval is running, otherwise it will return * false. */ VALUE hitimes_interval_duration_so_far( VALUE self ) { hitimes_interval_t *i; VALUE rc = Qfalse; Data_Get_Struct( self, hitimes_interval_t, i ); if ( 0L == i->start_instant ) { return rc; } if ( 0L == i->stop_instant ) { long double d; hitimes_instant_t now = hitimes_get_current_instant( ); d = ( now - i->start_instant ) / HITIMES_INSTANT_CONVERSION_FACTOR; rc = rb_float_new( d ); } return rc; } /** * call-seq: * interval.started? -> boolean * * returns whether or not the interval has been started */ VALUE hitimes_interval_started( VALUE self ) { hitimes_interval_t *i; Data_Get_Struct( self, hitimes_interval_t, i ); return ( 0L == i->start_instant ) ? Qfalse : Qtrue; } /** * call-seq: * interval.stopped? -> boolean * * returns whether or not the interval has been stopped */ VALUE hitimes_interval_stopped( VALUE self ) { hitimes_interval_t *i; Data_Get_Struct( self, hitimes_interval_t, i ); return ( 0L == i->stop_instant ) ? Qfalse : Qtrue; } /** * call-seq: * interval.running? -> boolean * * returns whether or not the interval is running or not. This means that it * has started, but not stopped. */ VALUE hitimes_interval_running( VALUE self ) { hitimes_interval_t *i; VALUE rc = Qfalse; Data_Get_Struct( self, hitimes_interval_t, i ); if ( ( 0L != i->start_instant ) && ( 0L == i->stop_instant ) ) { rc = Qtrue; } return rc; } /** * call-seq: * interval.start_instant -> Integer * * The integer representing the start instant of the Interval. This value * is not useful on its own. It is a platform dependent value. */ VALUE hitimes_interval_start_instant( VALUE self ) { hitimes_interval_t *i; Data_Get_Struct( self, hitimes_interval_t, i ); return ULL2NUM( i->start_instant ); } /** * call-seq: * interval.stop_instant -> Integer * * The integer representing the stop instant of the Interval. This value * is not useful on its own. It is a platform dependent value. */ VALUE hitimes_interval_stop_instant( VALUE self ) { hitimes_interval_t *i; Data_Get_Struct( self, hitimes_interval_t, i ); return ULL2NUM( i->stop_instant ); } /** * call-seq: * interval.duration -> Float * interval.to_f -> Float * interval.to_seconds -> Float * interval.length -> Float * * Returns the Float value of the interval, the value is in seconds. If the * interval has not had stop called yet, it will report the number of seconds * in the interval up to the current point in time. * * Raises Error if duration is called on an interval that has not started yet. */ VALUE hitimes_interval_duration ( VALUE self ) { hitimes_interval_t *i; Data_Get_Struct( self, hitimes_interval_t, i ); /* raise an error if the internval is not started */ if ( 0L == i->start_instant ) { rb_raise(eH_Error, "Attempt to report a duration on an interval that has not started" ); } /** * if stop has not yet been called, then return the amount of time so far */ if ( 0L == i->stop_instant ) { long double d; hitimes_instant_t now = hitimes_get_current_instant( ); d = ( now - i->start_instant ) / HITIMES_INSTANT_CONVERSION_FACTOR; return rb_float_new( d ); } /* * stop has been called, calculate the duration and save the result */ if ( i->duration < 0.0 ) { i->duration = ( i->stop_instant - i->start_instant ) / HITIMES_INSTANT_CONVERSION_FACTOR; } return rb_float_new( i->duration ); } /** * Document-class: Hitimes::Interval * * This is the lowest level timing mechanism available. It allows for easy * measuring based upon a block: * * duration = Interval.measure { ... } * * Or measuring something specifically * * interval = Interval.new * interval.start * duration = interval.stop * * Allocating and starting an interval can be done in one method call with * * interval = Interval.now * * Interval is useful when you only need to track a single interval of time, or * if you do not want to track statistics about an operation. * */ void Init_hitimes_interval() { mH = rb_define_module("Hitimes"); cH_Interval = rb_define_class_under( mH, "Interval", rb_cObject ); rb_define_alloc_func( cH_Interval, hitimes_interval_alloc ); rb_define_module_function( cH_Interval, "now", hitimes_interval_now, 0 ); /* in hitimes_interval.c */ rb_define_module_function( cH_Interval, "measure", hitimes_interval_measure, 0 ); /* in hitimes_interval.c */ rb_define_method( cH_Interval, "duration", hitimes_interval_duration, 0 ); /* in hitimes_interval.c */ rb_define_method( cH_Interval, "length", hitimes_interval_duration, 0 ); rb_define_method( cH_Interval, "to_f", hitimes_interval_duration, 0 ); rb_define_method( cH_Interval, "to_seconds", hitimes_interval_duration, 0 ); rb_define_method( cH_Interval, "duration_so_far", hitimes_interval_duration_so_far, 0); /* in hitimes_interval.c */ rb_define_method( cH_Interval, "started?", hitimes_interval_started, 0 ); /* in hitimes_interval.c */ rb_define_method( cH_Interval, "running?", hitimes_interval_running, 0 ); /* in hitimes_interval.c */ rb_define_method( cH_Interval, "stopped?", hitimes_interval_stopped, 0 ); /* in hitimes_interval.c */ rb_define_method( cH_Interval, "start_instant", hitimes_interval_start_instant, 0 ); /* in hitimes_interval.c */ rb_define_method( cH_Interval, "stop_instant", hitimes_interval_stop_instant, 0 ); /* in hitimes_interval.c */ rb_define_method( cH_Interval, "start", hitimes_interval_start, 0); /* in hitimes_interval.c */ rb_define_method( cH_Interval, "stop", hitimes_interval_stop, 0); /* in hitimes_interval.c */ rb_define_method( cH_Interval, "split", hitimes_interval_split, 0); /* in hitimes_interval.c */ } ruby-hitimes-1.2.1/ext/hitimes/c/hitimes_interval.h000066400000000000000000000041761231701356700223540ustar00rootroot00000000000000/** * Copyright (c) 2008 Jeremy Hinegardner * All rights reserved. See LICENSE and/or COPYING for details. * * vim: shiftwidth=4 */ #ifndef __HITIMES_INTERVAL_H__ #define __HITIMES_INTERVAL_H__ #include #define NANOSECONDS_PER_SECOND 1e9l #ifdef USE_INSTANT_CLOCK_GETTIME # define HITIMES_U64INT unsigned long long int # define HITIMES_INSTANT_CONVERSION_FACTOR 1e9l #elif USE_INSTANT_OSX # define HITIMES_U64INT uint64_t # define HITIMES_INSTANT_CONVERSION_FACTOR hitimes_instant_conversion_factor() #elif USE_INSTANT_WINDOWS # define HITIMES_U64INT unsigned __int64 # define HITIMES_INSTANT_CONVERSION_FACTOR hitimes_instant_conversion_factor() #else # error "Unable to build hitimes, no Instance backend available" #endif /* an alias for a 64bit unsigned integer. The various sytem dependenent * files must define hitimes_u64int_t */ typedef HITIMES_U64INT hitimes_instant_t; typedef struct hitimes_interval { hitimes_instant_t start_instant; hitimes_instant_t stop_instant; long double duration; } hitimes_interval_t; /* all the backends must define these methods */ hitimes_instant_t hitimes_get_current_instant( ); long double hitimes_instant_conversion_factor( ); /* init methods */ void Init_hitimes_stats(); void Init_hitimes_interval(); /* Module and Classes -- defined at the top level */ extern VALUE mH; /* module Hitimes */ extern VALUE eH_Error; /* class Hitimes::Error */ extern VALUE cH_Interval; /* class Hitimes::Interval */ /** * Methods for Interval */ VALUE hitimes_interval_free(hitimes_interval_t* i) ; VALUE hitimes_interval_alloc(VALUE klass); VALUE hitimes_interval_now( ); VALUE hitimes_interval_measure( ); VALUE hitimes_interval_split( VALUE self ); VALUE hitimes_interval_start( VALUE self ); VALUE hitimes_interval_stop( VALUE self ); VALUE hitimes_interval_started( VALUE self ); VALUE hitimes_interval_stopped( VALUE self ); VALUE hitimes_interval_running( VALUE self ); VALUE hitimes_interval_start_instant( VALUE self ); VALUE hitimes_interval_stop_instant( VALUE self ); VALUE hitimes_interval_duration ( VALUE self ); #endif ruby-hitimes-1.2.1/ext/hitimes/c/hitimes_stats.c000066400000000000000000000147771231701356700216710ustar00rootroot00000000000000/** * Copyright (c) 2008 Jeremy Hinegardner * All rights reserved. See LICENSE and/or COPYING for details. * * vim: shiftwidth=4 */ #include "hitimes_stats.h" /* classes defined here */ VALUE cH_Stats; /* Hitimes::Stats */ /** * Allocator and Deallocator for Stats classes */ VALUE hitimes_stats_free(hitimes_stats_t* s) { xfree( s ); return Qnil; } VALUE hitimes_stats_alloc(VALUE klass) { VALUE obj; hitimes_stats_t* s = xmalloc( sizeof( hitimes_stats_t ) ); s->min = 0.0; s->max = 0.0; s->count = 0; s->sum = 0.0; s->sumsq = 0.0; obj = Data_Wrap_Struct(klass, NULL, hitimes_stats_free, s); return obj; } /** * call-seq: * stat.update( val ) -> val * * Update the running stats with the new value. * Return the input value. */ VALUE hitimes_stats_update( VALUE self, VALUE v ) { long double new_v; hitimes_stats_t *stats; Data_Get_Struct( self, hitimes_stats_t, stats ); new_v = NUM2DBL( v ); if ( 0 == stats->count ) { stats->min = new_v; stats->max = new_v; } else { stats->min = ( new_v < stats->min) ? ( new_v ) : ( stats->min ); stats->max = ( new_v > stats->max) ? ( new_v ) : ( stats->max ); } stats->count += 1; stats->sum += new_v; stats->sumsq += ( new_v * new_v ); return v; } /** * call-seq: * stat.mean -> Float * * Return the arithmetic mean of the values put into the Stats object. If no * values have passed through the stats object then 0.0 is returned; */ VALUE hitimes_stats_mean( VALUE self ) { hitimes_stats_t *stats; long double mean = 0.0; Data_Get_Struct( self, hitimes_stats_t, stats ); if ( stats->count > 0 ) { mean = stats->sum / stats->count ; } return rb_float_new( mean ); } /** * call-seq: * stat.rate -> Float * * Return the +count+ divided by +sum+. * * In many cases when Stats#update( _value_ ) is called, the _value_ is a unit * of time, typically seconds or microseconds. #rate is a convenience for those * times. In this case, where _value_ is a unit if time, then count divided by * sum is a useful value, i.e. +something per unit of time+. * * In the case where _value_ is a non-time related value, then the value * returned by _rate_ is not really useful. * */ VALUE hitimes_stats_rate( VALUE self ) { hitimes_stats_t *stats; long double rate = 0.0; Data_Get_Struct( self, hitimes_stats_t, stats ); if ( stats->sum > 0.0 ) { rate = stats->count / stats->sum; } return rb_float_new( rate ); } /** * call-seq: * stat.max -> Float * * Return the maximum value that has passed through the Stats object */ VALUE hitimes_stats_max( VALUE self ) { hitimes_stats_t *stats; Data_Get_Struct( self, hitimes_stats_t, stats ); return rb_float_new( stats->max ); } /** * call-seq: * stat.min -> Float * * Return the minimum value that has passed through the Stats object */ VALUE hitimes_stats_min( VALUE self ) { hitimes_stats_t *stats; Data_Get_Struct( self, hitimes_stats_t, stats ); return rb_float_new( stats->min ); } /** * call-seq: * stat.count -> Integer * * Return the number of values that have passed through the Stats object. */ VALUE hitimes_stats_count( VALUE self ) { hitimes_stats_t *stats; Data_Get_Struct( self, hitimes_stats_t, stats ); return LONG2NUM( stats->count ); } /** * call-seq: * stat.sum -> Float * * Return the sum of all the values that have passed through the Stats object. */ VALUE hitimes_stats_sum( VALUE self ) { hitimes_stats_t *stats; Data_Get_Struct( self, hitimes_stats_t, stats ); return rb_float_new( stats->sum ); } /** * call-seq: * stat.sumsq -> Float * * Return the sum of the squars of all the values that passed through the Stats * object. */ VALUE hitimes_stats_sumsq( VALUE self ) { hitimes_stats_t *stats; Data_Get_Struct( self, hitimes_stats_t, stats ); return rb_float_new( stats->sumsq ); } /** * call-seq: * stat.stddev -> Float * * Return the standard deviation of all the values that have passed through the * Stats object. The standard deviation has no meaning unless the count is > 1, * therefore if the current _stat.count_ is < 1 then 0.0 will be returned; */ VALUE hitimes_stats_stddev ( VALUE self ) { hitimes_stats_t *stats; long double stddev = 0.0; Data_Get_Struct( self, hitimes_stats_t, stats ); if ( stats->count > 1 ) { stddev = sqrt( ( stats->sumsq - ( stats->sum * stats->sum / stats->count ) ) / ( stats->count - 1 ) ); } return rb_float_new( stddev ); } /** * Document-class: Hitimes::Stats * * The Stats class encapulsates capturing and reporting statistics. It is * modeled after the RFuzz::Sampler class, but implemented in C. For general use * you allocate a new Stats object, and then update it with new values. The * Stats object will keep track of the _min_, _max_, _count_, _sum_ and _sumsq_ * and when you want you may also retrieve the _mean_, _stddev_ and _rate_. * * this contrived example shows getting a list of all the files in a directory * and running stats on file sizes. * * s = Hitimes::Stats.new * dir = ARGV.shift || Dir.pwd * Dir.entries( dir ).each do |entry| * fs = File.stat( entry ) * if fs.file? then * s.update( fs.size ) * end * end * * %w[ count min max mean sum stddev rate ].each do |m| * puts "#{m.rjust(6)} : #{s.send( m ) }" * end */ void Init_hitimes_stats() { mH = rb_define_module("Hitimes"); cH_Stats = rb_define_class_under( mH, "Stats", rb_cObject ); /* in hitimes_stats.c */ rb_define_alloc_func( cH_Stats, hitimes_stats_alloc ); rb_define_method( cH_Stats, "update", hitimes_stats_update, 1 ); /* in hitimes_stats.c */ rb_define_method( cH_Stats, "count", hitimes_stats_count, 0 ); /* in hitimes_stats.c */ rb_define_method( cH_Stats, "max", hitimes_stats_max, 0 ); /* in hitimes_stats.c */ rb_define_method( cH_Stats, "mean", hitimes_stats_mean, 0 ); /* in hitimes_stats.c */ rb_define_method( cH_Stats, "min", hitimes_stats_min, 0 ); /* in hitimes_stats.c */ rb_define_method( cH_Stats, "rate", hitimes_stats_rate, 0 ); /* in hitimes_stats.c */ rb_define_method( cH_Stats, "sum", hitimes_stats_sum, 0 ); /* in hitimes_stats.c */ rb_define_method( cH_Stats, "sumsq", hitimes_stats_sumsq, 0 ); /* in hitimes_stats.c */ rb_define_method( cH_Stats, "stddev", hitimes_stats_stddev, 0 ); /* in hitimes_stats.c */ } ruby-hitimes-1.2.1/ext/hitimes/c/hitimes_stats.h000066400000000000000000000011011231701356700216470ustar00rootroot00000000000000/** * Copyright (c) 2008 Jeremy Hinegardner * All rights reserved. See LICENSE and/or COPYING for details. * * vim: shiftwidth=4 */ #ifndef __HITIMES_STATS_H__ #define __HITIMES_STATS_H__ #include #include /* classes and modules defined elswhere */ extern VALUE mH; /* Hitimes */ extern VALUE eH_Error; /* Hitimes::Error */ extern VALUE cH_Stats; /* Hitimes::Stats */ typedef struct hitimes_stats { long double min; long double max; long double sum; long double sumsq; long long count; } hitimes_stats_t; #endif ruby-hitimes-1.2.1/ext/hitimes/java/000077500000000000000000000000001231701356700173245ustar00rootroot00000000000000ruby-hitimes-1.2.1/ext/hitimes/java/src/000077500000000000000000000000001231701356700201135ustar00rootroot00000000000000ruby-hitimes-1.2.1/ext/hitimes/java/src/hitimes/000077500000000000000000000000001231701356700215555ustar00rootroot00000000000000ruby-hitimes-1.2.1/ext/hitimes/java/src/hitimes/Hitimes.java000066400000000000000000000033351231701356700240260ustar00rootroot00000000000000package hitimes; import java.lang.Math; import java.lang.System; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyModule; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyException; import org.jruby.RubyModule; import org.jruby.RubyObject; import org.jruby.exceptions.RaiseException; /** * @author Jeremy Hinegardner */ @JRubyModule( name = "Hitimes" ) public class Hitimes { public static RubyClass hitimesIntervalClass; /** * Create the Hitimes module and add it to the Ruby runtime. */ public static RubyModule createHitimes( Ruby runtime ) { RubyModule mHitimes = runtime.defineModule("Hitimes"); RubyClass cStandardError = runtime.getStandardError(); RubyClass cHitimesError = mHitimes.defineClassUnder("Error", cStandardError, cStandardError.getAllocator()); RubyClass cHitimesStats = mHitimes.defineClassUnder("Stats", runtime.getObject(), HitimesStats.ALLOCATOR ); cHitimesStats.defineAnnotatedMethods( HitimesStats.class ); RubyClass cHitimesInterval = mHitimes.defineClassUnder("Interval", runtime.getObject(), HitimesInterval.ALLOCATOR ); Hitimes.hitimesIntervalClass = cHitimesInterval; cHitimesInterval.defineAnnotatedMethods( HitimesInterval.class ); return mHitimes; } static RaiseException newHitimesError( Ruby runtime, String message ) { RubyClass errorClass = runtime.getModule("Hitimes").getClass( "Error" ); return new RaiseException( RubyException.newException( runtime, errorClass, message ), true ); } @JRubyClass( name = "Hitimes::Error", parent = "StandardError" ) public static class Error {}; } ruby-hitimes-1.2.1/ext/hitimes/java/src/hitimes/HitimesInterval.java000066400000000000000000000133411231701356700255310ustar00rootroot00000000000000package hitimes; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyObject; import org.jruby.runtime.Block; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ThreadContext; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; @JRubyClass( name = "Hitimes::Interval" ) public class HitimesInterval extends RubyObject { /* this is a double to force all division by the conversion factor * to cast to doubles */ private static final double INSTANT_CONVERSION_FACTOR = 1000000000d; private static final long INSTANT_NOT_SET = Long.MIN_VALUE; private static final double DURATION_NOT_SET = Double.NaN; public static final ObjectAllocator ALLOCATOR = new ObjectAllocator() { public IRubyObject allocate(Ruby runtime, RubyClass klass) { return new HitimesInterval( runtime, klass ); } }; public HitimesInterval( Ruby runtime, RubyClass klass ) { super( runtime, klass ); } public HitimesInterval( Ruby runtime, RubyClass klass, long start ) { super( runtime, klass ); this.start_instant = start; } private long start_instant = INSTANT_NOT_SET; private long stop_instant = INSTANT_NOT_SET; private double duration = DURATION_NOT_SET; @JRubyMethod( name = "duration", alias = { "length", "to_f", "to_seconds" } ) public IRubyObject duration() { /* * if start has not yet been called, then raise an exception. */ if ( INSTANT_NOT_SET == this.start_instant ) { throw Hitimes.newHitimesError( getRuntime(), "Attempt to report a duration on an interval that has not started"); } /* * if stop has not yet been called, then return the amount of time so far */ if ( INSTANT_NOT_SET == this.stop_instant ) { double d = ( System.nanoTime() - this.start_instant ) / INSTANT_CONVERSION_FACTOR; return getRuntime().newFloat( d ); } /* * if stop has been called, then calculate the duration and return */ if ( DURATION_NOT_SET == this.duration ) { this.duration = (this.stop_instant - this.start_instant) / INSTANT_CONVERSION_FACTOR; } return getRuntime().newFloat( this.duration ); } @JRubyMethod( name = "duration_so_far" ) public IRubyObject duration_so_far() { IRubyObject rc = getRuntime().getFalse(); if ( INSTANT_NOT_SET == this.start_instant ) { return rc; } if ( INSTANT_NOT_SET == this.stop_instant ) { double d = ( System.nanoTime() - this.start_instant ) / INSTANT_CONVERSION_FACTOR; return getRuntime().newFloat( d ); } return rc; } @JRubyMethod( name = "started?" ) public IRubyObject is_started() { if ( INSTANT_NOT_SET == this.start_instant ) { return getRuntime().getFalse(); } return getRuntime().getTrue(); } @JRubyMethod( name = "running?" ) public IRubyObject is_running() { if ( ( INSTANT_NOT_SET != this.start_instant ) && ( INSTANT_NOT_SET == this.stop_instant ) ) { return getRuntime().getTrue(); } return getRuntime().getFalse(); } @JRubyMethod( name = "stopped?" ) public IRubyObject is_stopped() { if ( INSTANT_NOT_SET == this.stop_instant ) { return getRuntime().getFalse(); } return getRuntime().getTrue(); } @JRubyMethod( name = "start_instant" ) public IRubyObject start_instant() { return getRuntime().newFixnum( this.start_instant ); } @JRubyMethod( name = "stop_instant" ) public IRubyObject stop_instant() { return getRuntime().newFixnum( this.stop_instant ); } @JRubyMethod( name = "start" ) public IRubyObject start() { if ( INSTANT_NOT_SET == this.start_instant ) { this.start_instant = System.nanoTime(); return getRuntime().getTrue(); } return getRuntime().getFalse(); } @JRubyMethod( name = "stop" ) public IRubyObject stop() { if ( INSTANT_NOT_SET == this.start_instant ) { throw Hitimes.newHitimesError( getRuntime(), "Attempt to stop an interval that has not started" ); } if ( INSTANT_NOT_SET == this.stop_instant ) { this.stop_instant = System.nanoTime(); this.duration = (this.stop_instant - this.start_instant) / INSTANT_CONVERSION_FACTOR; return getRuntime().newFloat( this.duration ); } return getRuntime().getFalse(); } @JRubyMethod( name = "split" ) public IRubyObject split() { this.stop(); return new HitimesInterval( getRuntime(), Hitimes.hitimesIntervalClass, this.stop_instant ); } @JRubyMethod( name = "now", module = true ) public static IRubyObject now( IRubyObject self ) { return new HitimesInterval( self.getRuntime(), Hitimes.hitimesIntervalClass, System.nanoTime() ); } @JRubyMethod( name = "measure", module = true, frame = true ) public static IRubyObject measure( IRubyObject self, Block block ) { Ruby runtime = self.getRuntime(); if ( block.isGiven() ) { IRubyObject nil = runtime.getNil(); ThreadContext context = runtime.getCurrentContext(); HitimesInterval interval = new HitimesInterval( runtime, Hitimes.hitimesIntervalClass ); interval.start(); block.yield( context, nil ); interval.stop(); return interval.duration(); } else { throw Hitimes.newHitimesError( runtime, "No block given to Interval.measure" ); } } } ruby-hitimes-1.2.1/ext/hitimes/java/src/hitimes/HitimesService.java000066400000000000000000000005111231701356700253400ustar00rootroot00000000000000package hitimes; import java.io.IOException; import org.jruby.Ruby; import org.jruby.runtime.load.BasicLibraryService; public class HitimesService implements BasicLibraryService { public boolean basicLoad( final Ruby runtime ) throws IOException { Hitimes.createHitimes( runtime ); return true; } } ruby-hitimes-1.2.1/ext/hitimes/java/src/hitimes/HitimesStats.java000066400000000000000000000053341231701356700250460ustar00rootroot00000000000000package hitimes; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyObject; import org.jruby.RubyNumeric; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.ObjectAllocator; import org.jruby.anno.JRubyMethod; import org.jruby.anno.JRubyClass; @JRubyClass( name = "Hitimes::Stats" ) public class HitimesStats extends RubyObject { private double min = 0.0; private double max = 0.0; private double sum = 0.0; private double sumsq = 0.0; private long count = 0; public static final ObjectAllocator ALLOCATOR = new ObjectAllocator() { public IRubyObject allocate(Ruby runtime, RubyClass klass) { return new HitimesStats( runtime, klass ); } }; public HitimesStats( Ruby runtime, RubyClass klass ) { super( runtime, klass ); } @JRubyMethod( name = "update", required = 1, argTypes = RubyNumeric.class ) public IRubyObject update( IRubyObject val ) { double v = RubyNumeric.num2dbl( val ); if ( 0 == this.count ) { this.min = this.max = v; } else { this.min = ( v < this.min ) ? v : this.min; this.max = ( v > this.max ) ? v : this.max; } this.count += 1; this.sum += v; this.sumsq += (v * v); return val; } @JRubyMethod( name = "mean" ) public IRubyObject mean() { double mean = 0.0; if ( this.count > 0 ) { mean = this.sum / this.count; } return getRuntime().newFloat( mean ); } @JRubyMethod( name = "rate" ) public IRubyObject rate() { double rate = 0.0; if ( this.sum > 0.0 ) { rate = this.count / this.sum ; } return getRuntime().newFloat( rate ); } @JRubyMethod( name = "stddev" ) public IRubyObject stddev() { double stddev = 0.0; if ( this.count > 1 ) { double sq_sum = this.sum * this.sum; stddev = Math.sqrt( ( this.sumsq - ( sq_sum / this.count ) ) / ( this.count - 1 ) ); } return getRuntime().newFloat( stddev ); } @JRubyMethod( name = "min" ) public IRubyObject min() { return getRuntime().newFloat( this.min ); } @JRubyMethod( name = "max" ) public IRubyObject max() { return getRuntime().newFloat( this.max ); } @JRubyMethod( name = "sum" ) public IRubyObject sum() { return getRuntime().newFloat( this.sum ); } @JRubyMethod( name = "sumsq" ) public IRubyObject sumsq() { return getRuntime().newFloat( this.sumsq ); } @JRubyMethod( name = "count" ) public IRubyObject count() { return getRuntime().newFixnum( this.count ); } } ruby-hitimes-1.2.1/lib/000077500000000000000000000000001231701356700147075ustar00rootroot00000000000000ruby-hitimes-1.2.1/lib/hitimes.rb000066400000000000000000000021431231701356700166760ustar00rootroot00000000000000#-- # Copyright (c) 2008 Jeremy Hinegardner # All rights reserved. See LICENSE and/or COPYING for details. #++ # # The top level module containing the contents of the hitimes library # # use the library with: # # require 'hitimes' # module Hitimes # # Base class of all errors in Hitimes # class Error < ::StandardError; end # Hitimes.measure { } -> Float # # Times the execution of the block, returning the number of seconds it took def self.measure(&block) Hitimes::Interval.measure(&block) end end require 'hitimes/paths' require 'hitimes/version' # Load the binary extension, try loading one for the specific version of ruby # and if that fails, then fall back to one in the top of the library. # this is the method recommended by rake-compiler begin # this will be for windows require "hitimes/#{RUBY_VERSION.sub(/\.\d$/,'')}/hitimes" rescue LoadError # everyone else. require 'hitimes/hitimes' end require 'hitimes/stats' require 'hitimes/mutexed_stats' require 'hitimes/metric' require 'hitimes/value_metric' require 'hitimes/timed_metric' require 'hitimes/timed_value_metric' ruby-hitimes-1.2.1/lib/hitimes/000077500000000000000000000000001231701356700163515ustar00rootroot00000000000000ruby-hitimes-1.2.1/lib/hitimes/metric.rb000066400000000000000000000064761231701356700201760ustar00rootroot00000000000000 #-- # Copyright (c) 2008, 2009 Jeremy Hinegardner # All rights reserved. See LICENSE and/or COPYING for details. #++ module Hitimes # # Metric hold the common meta information for all derived metric classes # # All metrics hold the meta information of: # # * The name of the metric # * The time of day the first measurement is taken # * The time of day the last measurement is taken # * additional data # # Each derived class is assumed to set the sampling_start_time and # sampling_stop_time appropriately. # # Metric itself should generally not be used. Only use the derived classes. # class Metric # the number of seconds as a float since the sampling_start_time attr_reader :sampling_delta # An additional hash of data to associate with the metric attr_reader :additional_data # The 'name' to associate with the metric attr_reader :name # # :call-seq: # Metric.new( 'my_metric' ) -> Metric # Metric.new( 'my_metric', 'foo' => 'bar', 'this' => 42 ) -> Metric # # Create a new ValueMetric giving it a name and additional data. # # +additional_data+ may be anything that follows the +to_hash+ protocol. # +name+ may be anything that follows the +to_s+ protocol. # def initialize( name, additional_data = {} ) @sampling_start_time = nil @sampling_start_interval = nil @sampling_delta = 0 @name = name.to_s @additional_data = additional_data.to_hash end # # :call-seq: # metric.sampling_start_time -> Float or nil # # The time at which the first sample was taken. # This is the number of microseconds since UNIX epoch UTC as a Float # # If the metric has not started measuring then the start time is nil. # def sampling_start_time if @sampling_start_interval then @sampling_start_time ||= self.utc_microseconds() else nil end end # # :call-seq: # metric.sampling_stop_time -> Float or nil # # The time at which the last sample was taken # This is the number of microseconds since UNIX epoch UTC as a Float # # If the metric has not completely measured at least one thing then # stop time is nil. # # Because accessing the actual 'time of day' is an expesive operation, we # only get the time of day at the beginning of the first measurement and we # keep track of the offset from that point in @sampling_delta. # # When sampling_stop_time is called, the actual time of day is caculated. # def sampling_stop_time if @sampling_delta > 0 then (self.sampling_start_time + (@sampling_delta * 1_000_000)) else nil end end # # :call-seq: # metric.to_hash -> Hash # metric.to_hash # # Convert the metric to a Hash. # def to_hash { 'sampling_start_time' => self.sampling_start_time, 'sampling_stop_time' => self.sampling_stop_time, 'additional_data' => self.additional_data, 'name' => self.name } end # # :call-seq: # metric.utc_microseconds -> Float # # The current time in microseconds from the UNIX Epoch in the UTC # def utc_microseconds Time.now.gmtime.to_f * 1_000_000 end end end ruby-hitimes-1.2.1/lib/hitimes/mutexed_stats.rb000066400000000000000000000012261231701356700215700ustar00rootroot00000000000000#-- # Copyright (c) 2008, 2009 Jeremy Hinegardner # All rights reserved. See LICENSE and/or COPYING for details. #++ require 'thread' module Hitimes # # MutexedStats is the start of a threadsafe Stats class. Currently, on MRI # Ruby the Stats object is already threadsafe, so there is no need to use # MutexedStats. # class MutexedStats < Stats def initialize @mutex = Mutex.new end # call-seq: # mutex_stat.update( val ) -> nil # # Update the running stats with the new value in a threadsafe manner. # def update( value ) @mutex.synchronize do super( value ) end end end end ruby-hitimes-1.2.1/lib/hitimes/paths.rb000066400000000000000000000030571231701356700200220ustar00rootroot00000000000000#-- # Copyright (c) 2008 Jeremy Hinegardner # All rights reserved. See LICENSE and/or COPYING for details. #++ # module Hitimes # # Access to various paths inside the project programatically # module Paths # # :call-seq: # Hitimes::Paths.root_dir -> String # # Returns The full expanded path of the parent directory of +lib+ # going up the path from the current file. A trailing File::SEPARATOR # is guaranteed. # def self.root_dir @root_dir ||=( path_parts = ::File.expand_path(__FILE__).split(::File::SEPARATOR) lib_index = path_parts.rindex("lib") @root_dir = path_parts[0...lib_index].join(::File::SEPARATOR) + ::File::SEPARATOR ) end # # :call-seq: # Hitimes::Paths.lib_path( *args ) -> String # # Returns The full expanded path of the +lib+ directory below # _root_dir_. All parameters passed in are joined onto the # result. A trailing File::SEPARATOR is guaranteed if # _args_ are *not* present. # def self.lib_path(*args) self.sub_path("lib", *args) end # # :call-seq: # Hitimes::Paths.sub_path( sub, *args ) -> String # # Returns the full expanded path of the +sub+ directory below _root_dir. All # _arg_ parameters passed in are joined onto the result. A trailing # File::SEPARATOR is guaranteed if _args_ are *not* present. # def self.sub_path(sub,*args) sp = ::File.join(root_dir, sub) + File::SEPARATOR sp = ::File.join(sp, *args) if args end end end ruby-hitimes-1.2.1/lib/hitimes/stats.rb000066400000000000000000000027221231701356700200370ustar00rootroot00000000000000#-- # Copyright (c) 2008, 2009 Jeremy Hinegardner # All rights reserved. See LICENSE and/or COPYING for details. #++ require 'stringio' module Hitimes class Stats # A list of the available stats STATS = %w[ count max mean min rate stddev sum sumsq ] # # call-seq: # stat.to_hash -> Hash # stat.to_hash( %w[ count max mean ]) -> Hash # # return a hash of the stats. By default this returns a hash of all stats # but passing in an array of items will limit the stats returned to only # those in the Array. # # If passed in an empty array or nil to to_hash then STATS is assumed to be # the list of stats to return in the hash. # def to_hash( *args ) h = {} args = [ args ].flatten args = STATS if args.empty? args.each do |meth| h[meth] = self.send( meth ) end return h end # # call-seq: # stat.to_json -> String # stat.to_json( *args ) -> String # # return a json string of the stats. By default this returns a json string # of all the stats. If an array of items is passed in, those that match the # known stats will be all that is included in the json output. # def to_json( *args ) h = to_hash( *args ) a = [] s = StringIO.new s.print "{ " h.each_pair do |k,v| a << "\"#{k}\": #{v}" end s.print a.join(", ") s.print "}" return s.string end end end ruby-hitimes-1.2.1/lib/hitimes/timed_metric.rb000066400000000000000000000111521231701356700213430ustar00rootroot00000000000000#-- # Copyright (c) 2008, 2009 Jeremy Hinegardner # All rights reserved. See LICENSE and/or COPYING for details. #++ require 'forwardable' module Hitimes # # A TimedMetric holds the metrics on how long it takes to do something. For # example, measuring how long a method takes to operate. # # tm = TimedMetric.new( 'my-method' ) # # 200.times do # my_method_result = tm.measure do # my_method( ... ) # end # end # # puts "#{ tm.name } operated at a rate of #{ tm.rate } calls per second" # # Since TimedMetric is a child class of Metric make sure to look at the # Metric API also. # # A TimedMetric measures the execution time of an option with the Interval # class. # # A TimedMetric contains a Stats object, therefore TimedMetric has +count+, +max+, # +mean+, +min+, +rate+, +stddev+, +sum+, +sumsq+ methods that delegate to that Stats # object for convenience. # # class TimedMetric < Metric # holds all the statistics attr_reader :stats class << TimedMetric # # :call-seq: # TimedMetric.now -> TimedMetric # # Return a TimedMetric that has been started # def now( name, additional_data = {} ) t = TimedMetric.new( name, additional_data ) t.start return t end end # # :call-seq: # TimedMetric.new( 'name') -> TimedMetric # TimedMetric.new( 'name', 'other' => 'data') -> TimedMetric # # Create a new TimedMetric giving it a name and additional data. # +additional_data+ may be anything that follows the +to_hash+ protocol # def initialize( name, additional_data = {} ) super( name, additional_data ) @stats = Stats.new @current_interval = Interval.new end # # :call-seq: # timed_metric.running? -> true or false # # return whether or not the timer is currently running. # def running? @current_interval.running? end # # :call-seq: # timed_metric.start -> nil # # Start the current metric, if the current metric is already started, then # this is a noop. # def start if not @current_interval.running? then @current_interval.start @sampling_start_time ||= self.utc_microseconds() @sampling_start_interval ||= Interval.now end nil end # # :call-seq: # timed_metric.stop -> Float or nil # # Stop the current metric. This updates the stats and removes the current # interval. If the timer was stopped then the duration of the last Interval # is returned. If the timer was already stopped then false is returned and # no stats are updated. # def stop if @current_interval.running? then d = @current_interval.stop @stats.update( d ) @current_interval = Interval.new # update the length of time we have been sampling @sampling_delta = @sampling_start_interval.duration_so_far return d end return false end # # :call-seq: # timed_metric.measure { ... } -> Object # # Measure the execution of a block and add those stats to the running stats. # The return value is the return value of the block # def measure( &block ) return_value = nil begin start return_value = yield ensure stop end return return_value end # # :call-seq: # timed_metric.split -> Float # # Split the current TimedMetric. Essentially, mark a split time. This means # stop the current interval and create a new interval, but make sure # that the new interval lines up exactly, timewise, behind the previous # interval. # # If the timer is running, then split returns the duration of the previous # interval, i.e. the split-time. If the timer is not running, nothing # happens and false is returned. # def split if @current_interval.running? then next_interval = @current_interval.split d = @current_interval.duration @stats.update( d ) @current_interval = next_interval return d end return false end # # :call-seq: # metric.to_hash -> Hash # # Convert the metric to a hash # def to_hash h = super Stats::STATS.each do |s| h[s] = self.send( s ) end return h end # forward appropriate calls directly to the stats object extend Forwardable def_delegators :@stats, :count, :max, :mean, :min, :rate, :stddev, :sum, :sumsq alias :duration :sum end end ruby-hitimes-1.2.1/lib/hitimes/timed_value_metric.rb000066400000000000000000000154601231701356700225450ustar00rootroot00000000000000#-- # Copyright (c) 2008, 2009 Jeremy Hinegardner # All rights reserved. See LICENSE and/or COPYING for details. #++ module Hitimes # # A TimedValueMetric holds the metrics on how long it takes to do a batch of something. # something. For measuring how long a method takes to operate on N items. # # tm = TimedValueMetric.new( 'my-batch-method' ) # # 42.times do # tm.start # number_of_items_processed = do_something # tm.stop( number_of_items_processed ) # end # # puts "#{ tm.name } operated at a rate of #{ tm.rate } calls per second" # # TimedValueMetric combines the usefulness of a ValueMetric and a TimedMetric. # The stats are available for both the time it took to do the operation and # the sizes of the batches that were run. # # A TimedValueMetric keeps track of both the time it took to do an operation # and the size of the batch that was operated on. These metrics are kept # separately as +timed_stats+ and +value_stats+ accessors. # class TimedValueMetric < Metric # holds all the Timed statistics attr_reader :timed_stats # holds all the Value statistics attr_reader :value_stats class << TimedValueMetric # # :call-seq: # TimedValueMetric.now( 'name' ) -> TimedValueMetric # # Return a TimedValueMetric that has been started # def now( name, additional_data = {} ) t = TimedValueMetric.new( name, additional_data ) t.start return t end end # # :call-seq: # TimedValueMetric.new( 'name') -> TimedValueMetric # TimedValueMetric.new( 'name', 'other' => 'data') -> TimedValueMetric # # Create a new TimedValueMetric giving it a name and additional data. # +additional_data+ may be anything that follows the +to_hash+ protocol # def initialize( name, additional_data = {} ) super( name, additional_data ) @timed_stats = Stats.new @value_stats = Stats.new @current_interval = Interval.new end # # :call-seq: # timed_value_metric.running? -> true or false # # return whether or not the metric is currently timing something. # def running? @current_interval.running? end # # :call-seq: # timed_value_metric.start -> nil # # Start the current timer, if the current timer is already started, then # this is a noop. # def start if not @current_interval.running? then @current_interval.start @sampling_start_time ||= self.utc_microseconds() @sampling_start_interval ||= Interval.now end nil end # # :call-seq: # timed_value_metric.stop( count ) -> Float or nil # # Stop the current metric. The +count+ parameter must be a # value to update to the _value_ portion of the TimedValueMetric. Generally # this is probably the number of things that were operated upon since # +start+ was invoked. # # This updates both the +value_stats+ and +timed_stats+ stats and removes # the current interval. If the metric is stopped then the duration of the # last Interval is returned. If the metric was already stopped before this # call, then false is returned and no stats are updated. # # def stop( value ) if @current_interval.running? then d = @current_interval.stop @timed_stats.update( d ) @current_interval = Interval.new @value_stats.update( value ) # update the lenght of time we have been sampling @sampling_delta = @sampling_start_interval.duration_so_far return d end return false end # # :call-seq: # timed_value_metric.measure( value ) { ... } -> Object # # Measure the execution of a block and add those stats to the running stats. # The return value is the return value of the block. A value must be passed # into +measure+ to update the +value_stats+ portion of the TimedValueMetric. # def measure( value, &block ) return_value = nil begin start return_value = yield ensure stop( value ) end return return_value end # # :call-seq: # timed_value_metric.split( value ) -> Float # # Split the current metric. Essentially, mark a split time. This means # stop the current interval, with the givein +value+ and create a new # interval, but make sure that the new interval lines up exactly, timewise, # behind the previous interval. # # If the metric is running, then split returns the duration of the previous # interval, i.e. the split-time. If the metric is not running, nothing # happens, no stats are updated, and false is returned. # # def split( value ) if @current_interval.running? then next_interval = @current_interval.split d = @current_interval.duration @timed_stats.update( d ) @value_stats.update( value ) @current_interval = next_interval return d end return false end # # :call-seq: # timed_value_metric.duration -> Float # # The duration of measured time from the metric. # def duration @timed_stats.sum end # # :call-seq: # timed_value_metric.unit_count -> Float # # The sum of all values passed to +stop+ or +skip+ or +measure+ # def unit_count @value_stats.sum end # # :call-seq: # timed_value_metric.rate -> Float # # Rate in the context of the TimedValueMetric is different than the # TimedMetric. In the TimedValueMetric, each measurement of time is # associated with a quantity of things done during that unit of time. So # the +rate+ for a TimedValueMetric is the (sum of all quantities sampled) / # ( sum of all durations measured ) # # For example, say you were measuring, using a TimedValueMetric batch jobs # that had individual units of work. # # tvm = TimedValueMetric.new( 'some-batch' ) # tvm.start # # process a batch of 12 units # duration1 = tvm.stop( 12 ) # # tvm.start # # process a larger batch of 42 units # duration2 = tvm.stop( 42 ) # # At this point the rate of units per second is calculated as ( 12 + 42 ) / ( duration1 + duration2 ) # # some_batch_rate = tvm.rate # returns ( 34 / ( duration1+duration2 ) ) # def rate @value_stats.sum / @timed_stats.sum end # # :call-seq: # metric.to_hash -> Hash # # Convert the metric to a hash # def to_hash h = super h['timed_stats'] = @timed_stats.to_hash h['value_stats'] = @value_stats.to_hash( Stats::STATS - %w[ rate ] ) h['rate'] = self.rate h['unit_count'] = self.unit_count return h end end end ruby-hitimes-1.2.1/lib/hitimes/value_metric.rb000066400000000000000000000037351231701356700213650ustar00rootroot00000000000000#-- # Copyright (c) 2008, 2009 Jeremy Hinegardner # All rights reserved. See LICENSE and/or COPYING for details. #++ require 'forwardable' module Hitimes # # A ValueMetric holds the data from measuring a single value over a period of # time. In most cases this may be a single measurement at a single point in # time. # # A good example of a ValueMetric is measuring the number of items in a queue. # # A ValueMetric contains a Stats object, therefore ValueMetric has +count+, +max+, # +mean+, +min+, +stddev+, +sum+, +sumsq+ methods that delegate to that Stats # object for convenience. # class ValueMetric < Metric # holds all the statistics attr_reader :stats # # :call-seq: # ValueMetric.new( 'my_metric' ) -> ValueMetric # ValueMetric.new( 'my_metric', 'foo' => 'bar', 'this' => 42 ) -> ValueMetric # # Create a new ValueMetric giving it a name and additional data. # +additional_data+ may be anything that follows the +to_hash+ protocol. # def initialize( name, additional_data = {} ) super( name, additional_data ) @stats = Stats.new end # # :call-seq: # metric.measure( value ) -> Float # # Give the +value+ as the measurement to the metric. The value is returned # def measure( value ) @sampling_start_time ||= self.utc_microseconds() @sampling_start_interval ||= Interval.now @stats.update( value ) # update the length of time we have been sampling @sampling_delta = @sampling_start_interval.duration_so_far end # # :call-seq: # metric.to_hash -> Hash # # Convert the metric to a hash # def to_hash h = super (Stats::STATS - %w[ rate ]).each do |s| h[s] = self.send( s ) end return h end # forward appropriate calls directly to the stats object extend Forwardable def_delegators :@stats, :count, :max, :mean, :min, :stddev, :sum, :sumsq end end ruby-hitimes-1.2.1/lib/hitimes/version.rb000066400000000000000000000002271231701356700203640ustar00rootroot00000000000000#-- # Copyright (c) 2008 Jeremy Hinegardner # All rights reserved. See LICENSE and/or COPYING for details #++ module Hitimes VERSION = "1.2.1" end ruby-hitimes-1.2.1/metadata.yml000066400000000000000000000115601231701356700164470ustar00rootroot00000000000000--- !ruby/object:Gem::Specification name: hitimes version: !ruby/object:Gem::Version version: 1.2.1 platform: ruby authors: - Jeremy Hinegardner autorequire: bindir: bin cert_chain: [] date: 2013-03-12 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: 10.0.3 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: 10.0.3 - !ruby/object:Gem::Dependency name: rspec requirement: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: 2.13.0 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: 2.13.0 - !ruby/object:Gem::Dependency name: rdoc requirement: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '4.0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '4.0' - !ruby/object:Gem::Dependency name: json requirement: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: 1.7.7 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: 1.7.7 - !ruby/object:Gem::Dependency name: rake-compiler requirement: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: 0.8.3 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: 0.8.3 description: 'Hitimes is a fast, high resolution timer library for recording performance metrics. It uses the appropriate low method calls for each system to get the highest granularity time increments possible. It currently supports any of the following systems: * any system with the POSIX call `clock_gettime()` * Mac OS X * Windows * JRuby Using Hitimes can be faster than using a series of `Time.new` calls, and it will have a much higher granularity. It is definitely faster than using `Process.times`.' email: jeremy@copiousfreetime.org executables: [] extensions: - ext/hitimes/c/extconf.rb extra_rdoc_files: - CONTRIBUTING.md - HISTORY.md - Manifest.txt - README.md files: - CONTRIBUTING.md - HISTORY.md - LICENSE - Manifest.txt - README.md - Rakefile - examples/benchmarks.rb - examples/stats.rb - ext/hitimes/c/extconf.rb - ext/hitimes/c/hitimes.c - ext/hitimes/c/hitimes_instant_clock_gettime.c - ext/hitimes/c/hitimes_instant_osx.c - ext/hitimes/c/hitimes_instant_windows.c - ext/hitimes/c/hitimes_interval.c - ext/hitimes/c/hitimes_interval.h - ext/hitimes/c/hitimes_stats.c - ext/hitimes/c/hitimes_stats.h - ext/hitimes/java/src/hitimes/Hitimes.java - ext/hitimes/java/src/hitimes/HitimesInterval.java - ext/hitimes/java/src/hitimes/HitimesService.java - ext/hitimes/java/src/hitimes/HitimesStats.java - lib/hitimes.rb - lib/hitimes/metric.rb - lib/hitimes/mutexed_stats.rb - lib/hitimes/paths.rb - lib/hitimes/stats.rb - lib/hitimes/timed_metric.rb - lib/hitimes/timed_value_metric.rb - lib/hitimes/value_metric.rb - lib/hitimes/version.rb - spec/hitimes_spec.rb - spec/interval_spec.rb - spec/metric_spec.rb - spec/mutex_stats_spec.rb - spec/paths_spec.rb - spec/spec_helper.rb - spec/stats_spec.rb - spec/timed_metric_spec.rb - spec/timed_value_metric_spec.rb - spec/value_metric_spec.rb - spec/version_spec.rb - tasks/default.rake - tasks/extension.rake - tasks/this.rb homepage: http://github.com/copiousfreetime/hitimes licenses: [] metadata: {} post_install_message: rdoc_options: - --main - README.md - --markup - tomdoc require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.0.3 signing_key: specification_version: 4 summary: Hitimes is a fast, high resolution timer library for recording performance metrics. It uses the appropriate low method calls for each system to get the highest granularity time increments possible. test_files: - spec/hitimes_spec.rb - spec/interval_spec.rb - spec/metric_spec.rb - spec/mutex_stats_spec.rb - spec/paths_spec.rb - spec/spec_helper.rb - spec/stats_spec.rb - spec/timed_metric_spec.rb - spec/timed_value_metric_spec.rb - spec/value_metric_spec.rb - spec/version_spec.rb ruby-hitimes-1.2.1/spec/000077500000000000000000000000001231701356700150735ustar00rootroot00000000000000ruby-hitimes-1.2.1/spec/hitimes_spec.rb000066400000000000000000000005411231701356700200740ustar00rootroot00000000000000require 'spec_helper' describe Hitimes do it "can time a block of code" do d = Hitimes.measure do sleep 0.2 end d.should be_within(0.02).of(0.2) end it "raises an error if measure is called with no block" do lambda{ Hitimes.measure }.should raise_error( Hitimes::Error, /\ANo block given to Interval.measure\Z/ ) end end ruby-hitimes-1.2.1/spec/interval_spec.rb000066400000000000000000000063231231701356700202620ustar00rootroot00000000000000require "spec_helper" describe Hitimes::Interval do it "raises an error if duration is called on a non-started interval" do i = Hitimes::Interval.new lambda{ i.duration }.should raise_error( Hitimes::Error, /\AAttempt to report a duration on an interval that has not started\Z/ ) end it "raises an error if stop is called on a non-started interval" do i = Hitimes::Interval.new lambda { i.stop }.should raise_error( Hitimes::Error, /\AAttempt to stop an interval that has not started\Z/ ) end it "knows if it has been started" do i = Hitimes::Interval.new i.should_not be_started i.start i.should be_started end it "knows if it has been stopped" do i = Hitimes::Interval.new i.start i.should_not be_stopped i.stop i.should be_stopped end it "knows if it is currently running" do i = Hitimes::Interval.new i.should_not be_running i.start i.should be_running i.stop i.should_not be_running end it "can time a block of code" do d = Hitimes::Interval.measure do sleep 0.2 end d.should be_within(0.02).of(0.2) end it "raises an error if measure is called with no block" do lambda{ Hitimes::Interval.measure }.should raise_error( Hitimes::Error, /\ANo block given to Interval.measure\Z/ ) end it "creates an interval via #now" do i = Hitimes::Interval.now i.should be_started i.should_not be_stopped end it "calling duration multiple times returns successivly grater durations" do i = Hitimes::Interval.new i.start y = i.duration z = i.duration z.should > y end it "calling start multiple times on has no effect after the first call" do i = Hitimes::Interval.new i.start.should be == true x = i.start_instant i.start_instant.should be > 0 i.start.should be == false x.should == i.start_instant end it "returns the duration on the first call to stop" do i = Hitimes::Interval.now d = i.stop d.should be_instance_of( Float ) end it "calling stop multiple times on has no effect after the first call" do i = Hitimes::Interval.new i.start.should be == true i.stop x = i.stop_instant i.stop_instant.should be > 0 i.stop.should be == false x.should == i.stop_instant end it "duration does not change after stop is calledd" do i = Hitimes::Interval.new i.start x = i.stop y = i.duration i.stop.should be == false z = i.duration x.should be == y x.should be == z y.should be == z end it "can return how much time has elapsed from the start without stopping the interval" do i = Hitimes::Interval.new i.start x = i.duration_so_far i.should be_running y = i.duration_so_far i.stop x.should be < y x.should be < i.duration y.should be < i.duration end describe "#split" do it "creates a new Interval object" do i = Hitimes::Interval.new i.start i2 = i.split i.object_id.should_not == i2.object_id end it "with the stop instant equivialent to the previous Interval's start instant" do i = Hitimes::Interval.new i.start i2 = i.split i.stop_instant.should == i2.start_instant end end end ruby-hitimes-1.2.1/spec/metric_spec.rb000066400000000000000000000013721231701356700177200ustar00rootroot00000000000000require "spec_helper" describe Hitimes::Metric do before( :each ) do @metric = Hitimes::Metric.new( "testing" ) end it 'has a name' do @metric.name.should be == "testing" end it "has associated data from initialization" do m = Hitimes::Metric.new( "more-data", 'foo' => 'bar', 'this' => 'that' ) m.additional_data['foo'].should be == 'bar' m.additional_data['this'].should be == 'that' m = Hitimes::Metric.new( "more-data", { 'foo' => 'bar', 'this' => 'that' } ) m.additional_data['foo'].should be == 'bar' m.additional_data['this'].should be == 'that' end it "initially has no sampling times" do @metric.sampling_start_time.should be == nil @metric.sampling_stop_time.should be == nil end end ruby-hitimes-1.2.1/spec/mutex_stats_spec.rb000066400000000000000000000016671231701356700210240ustar00rootroot00000000000000require 'spec_helper' describe Hitimes::MutexedStats do before( :each ) do @threads = 5 @iters = 10_000 @final_value = @threads * @iters end def run_with_scissors( stats, threads, iters ) spool = [] threads.times do |t| spool << Thread.new { iters.times{ stats.update( 1 ) } } end spool.each { |t| t.join } return stats end if (not defined? RUBY_ENGINE) or (RUBY_ENGINE == "ruby") then it "Hitimes::Stats is threadsafe" do stats = run_with_scissors( ::Hitimes::Stats.new, @threads, @iters ) stats.count.should== @final_value end else it "Hitimes::Stats is not threadsafe" do stats = run_with_scissors( ::Hitimes::Stats.new, @threads, @iters ) stats.count.should_not == @final_value end end it "has a threadsafe update" do stats = run_with_scissors( ::Hitimes::MutexedStats.new, @threads, @iters ) stats.count.should == @final_value end end ruby-hitimes-1.2.1/spec/paths_spec.rb000066400000000000000000000006401231701356700175510ustar00rootroot00000000000000require 'spec_helper' describe Hitimes::Paths do it "can access the root dir of the project" do Hitimes::Paths.root_dir.should == File.expand_path( File.join( File.dirname( __FILE__ ), ".." ) ) + ::File::SEPARATOR end it "can access the lib path of the project" do Hitimes::Paths.lib_path.should == File.expand_path( File.join( File.dirname( __FILE__ ), "..", "lib" ) ) + ::File::SEPARATOR end end ruby-hitimes-1.2.1/spec/spec_helper.rb000066400000000000000000000002441231701356700177110ustar00rootroot00000000000000if RUBY_VERSION >= '1.9.2' then require 'simplecov' puts "Using coverage!" SimpleCov.start if ENV['COVERAGE'] end require 'rspec/autorun' require 'hitimes' ruby-hitimes-1.2.1/spec/stats_spec.rb000066400000000000000000000047661231701356700176050ustar00rootroot00000000000000require 'spec_helper' require 'json' describe Hitimes::Stats do before( :each ) do @stats = Hitimes::Stats.new @full_stats = Hitimes::Stats.new [ 1, 2, 3].each { |i| @full_stats.update( i ) } end it "is initialized with 0 values" do @stats.count.should be == 0 @stats.min.should be == 0.0 @stats.max.should be == 0.0 @stats.sum.should be == 0.0 @stats.rate.should be == 0.0 end it "calculates the mean correctly" do @full_stats.mean.should be == 2.0 end it "calculates the rate correctly" do @full_stats.rate.should be == 0.5 end it "tracks the maximum value" do @full_stats.max.should be == 3.0 end it "tracks the minimum value" do @full_stats.min.should be == 1.0 end it "tracks the count" do @full_stats.count.should be == 3 end it "tracks the sum" do @full_stats.sum.should be == 6.0 end it "calculates the standard deviation" do @full_stats.stddev.should be == 1.0 end it "calculates the sum of squares " do @full_stats.sumsq.should be == 14.0 end describe "#to_hash " do it "converts to a Hash" do h = @full_stats.to_hash h.size.should be == ::Hitimes::Stats::STATS.size h.keys.sort.should be == ::Hitimes::Stats::STATS end it "converts to a limited Hash if given arguments" do h = @full_stats.to_hash( "min", "max", "mean" ) h.size.should be == 3 h.keys.sort.should be == %w[ max mean min ] h = @full_stats.to_hash( %w[ count rate ] ) h.size.should be == 2 h.keys.sort.should be == %w[ count rate ] end it "raises NoMethodError if an invalid stat is used" do lambda { @full_stats.to_hash( "wibble" ) }.should raise_error( NoMethodError ) end end describe "#to_json" do it "converts to a json string" do j = @full_stats.to_json h = JSON.parse( j ) h.size.should be == ::Hitimes::Stats::STATS.size h.keys.sort.should be == ::Hitimes::Stats::STATS end it "converts to a limited Hash if given arguments" do j = @full_stats.to_json( "min", "max", "mean" ) h = JSON.parse( j ) h.size.should be == 3 h.keys.sort.should be == %w[ max mean min ] j = @full_stats.to_json( %w[ count rate ] ) h = JSON.parse( j ) h.size.should be == 2 h.keys.sort.should be == %w[ count rate ] end it "raises NoMethodError if an invalid stat is used" do lambda { @full_stats.to_json( "wibble" ) }.should raise_error( NoMethodError ) end end end ruby-hitimes-1.2.1/spec/timed_metric_spec.rb000066400000000000000000000105611231701356700211020ustar00rootroot00000000000000require 'spec_helper' describe Hitimes::TimedMetric do before( :each ) do @tm = Hitimes::TimedMetric.new( 'test-timed-metric' ) end it "knows if it is running or not" do @tm.should_not be_running @tm.start @tm.should be_running @tm.stop @tm.should_not be_running end it "#split returns the last duration and the timer is still running" do @tm.start d = @tm.split @tm.should be_running d.should be > 0 @tm.count.should be == 1 @tm.duration.should be == d end it "#stop returns false if called more than once in a row" do @tm.start @tm.stop.should be > 0 @tm.stop.should be == false end it "does not count a currently running interval as an interval in calculations" do @tm.start @tm.count.should be == 0 @tm.split @tm.count.should be == 1 end it "#split called on a stopped timer does nothing" do @tm.start @tm.stop @tm.split.should be == false end it "calculates the mean of the durations" do 2.times { @tm.start ; sleep 0.05 ; @tm.stop } @tm.mean.should be_within(0.01).of(0.05) end it "calculates the rate of the counts " do 5.times { @tm.start ; sleep 0.05 ; @tm.stop } @tm.rate.should be_within(1.0).of(20.00) end it "calculates the stddev of the durations" do 3.times { |x| @tm.start ; sleep(0.05 * x) ; @tm.stop } @tm.stddev.should be_within(0.002).of( 0.05) end it "returns 0.0 for stddev if there is no data" do @tm.stddev.should be == 0.0 end it "keeps track of the min value" do 2.times { @tm.start ; sleep 0.05 ; @tm.stop } @tm.min.should be_within( 0.002 ).of(0.05) end it "keeps track of the max value" do 2.times { @tm.start ; sleep 0.05 ; @tm.stop } @tm.max.should be_within( 0.002 ).of(0.05) end it "keeps track of the sum value" do 2.times { @tm.start ; sleep 0.05 ; @tm.stop } @tm.sum.should be_within( 0.005 ).of(0.10) end it "keeps track of the sum of squars value" do 3.times { @tm.start ; sleep 0.05 ; @tm.stop } @tm.sumsq.should be_within(0.001).of(0.0075) end it "keeps track of the minimum start time of all the intervals" do f1 = Time.now.gmtime.to_f * 1_000_000 5.times { @tm.start ; sleep 0.05 ; @tm.stop } f2 = Time.now.gmtime.to_f * 1_000_000 @tm.sampling_start_time.should be >= f1 @tm.sampling_start_time.should be < f2 # distance from now to start time should be greater than the distance from # the start to the min start_time (f2 - @tm.sampling_start_time).should > ( @tm.sampling_start_time - f1 ) end it "keeps track of the last stop time of all the intervals" do f1 = Time.now.gmtime.to_f * 1_000_000 sleep 0.01 5.times { @tm.start ; sleep 0.05 ; @tm.stop } sleep 0.01 f2 = Time.now.gmtime.to_f * 1_000_000 @tm.sampling_stop_time.should be > f1 @tm.sampling_stop_time.should be <= f2 # distance from now to max stop time time should be less than the distance # from the start to the max stop time (f2 - @tm.sampling_stop_time).should < ( @tm.sampling_stop_time - f1 ) end it "can create an already running timer" do t = Hitimes::TimedMetric.now( 'already-running' ) t.should be_running end it "can measure a block of code from an instance" do t = Hitimes::TimedMetric.new( 'measure a block' ) 3.times { t.measure { sleep 0.05 } } t.duration.should be_within(0.01).of(0.15) t.count.should be == 3 end it "returns the value of the block when measuring" do t = Hitimes::TimedMetric.new( 'measure a block' ) x = t.measure { sleep 0.05; 42 } t.duration.should be_within(0.002).of(0.05) x.should be == 42 end describe "#to_hash" do it "has name value" do h = @tm.to_hash h['name'].should be == "test-timed-metric" end it "has an empty hash for additional_data" do h = @tm.to_hash h['additional_data'].should be == Hash.new h['additional_data'].size.should be == 0 end it "has the right sum" do 10.times { |x| @tm.measure { sleep 0.01*x } } h = @tm.to_hash h['sum'].should be_within( 0.01).of(0.45) end fields = ::Hitimes::Stats::STATS.dup + %w[ name additional_data sampling_start_time sampling_stop_time ] fields.each do |f| it "should have a value for #{f}" do @tm.measure { sleep 0.001 } h = @tm.to_hash h[f].should_not be_nil end end end end ruby-hitimes-1.2.1/spec/timed_value_metric_spec.rb000066400000000000000000000123671231701356700223040ustar00rootroot00000000000000require 'spec_helper' describe Hitimes::TimedValueMetric do before( :each ) do @tm = Hitimes::TimedValueMetric.new( 'test-timed-value-metric' ) end it "knows if it is running or not" do @tm.should_not be_running @tm.start @tm.should be_running @tm.stop( 1 ) @tm.should_not be_running end it "#split returns the last duration and the timer is still running" do @tm.start d = @tm.split( 1 ) @tm.should be_running d.should be > 0 @tm.value_stats.count.should be == 1 @tm.timed_stats.count.should be == 1 @tm.duration.should be == d end it "#stop returns false if called more than once in a row" do @tm.start @tm.stop( 1 ).should be > 0 @tm.stop( 1 ).should be == false end it "does not count a currently running interval as an interval in calculations" do @tm.start @tm.value_stats.count.should be == 0 @tm.timed_stats.count.should be == 0 @tm.split( 1 ) @tm.value_stats.count.should be == 1 @tm.timed_stats.count.should be == 1 end it "#split called on a stopped timer does nothing" do @tm.start @tm.stop( 1 ) @tm.split( 1 ).should be == false end it "calculates the mean of the durations" do 3.times { |x| @tm.start ; sleep 0.05 ; @tm.stop(x) } @tm.timed_stats.mean.should be_within(0.01).of(0.05) @tm.value_stats.mean.should be == 1.00 end it "calculates the rate of the counts " do 5.times { |x| @tm.start ; sleep 0.05 ; @tm.stop( x ) } @tm.rate.should be_within(1.0).of(40.0) end it "calculates the stddev of the durations" do 3.times { |x| @tm.start ; sleep(0.05 * x) ; @tm.stop(x) } @tm.timed_stats.stddev.should be_within(0.001).of(0.05) @tm.value_stats.stddev.should be == 1.0 end it "returns 0.0 for stddev if there is no data" do @tm.timed_stats.stddev.should be == 0.0 @tm.value_stats.stddev.should be == 0.0 end it "keeps track of the min value" do 3.times { |x| @tm.start ; sleep 0.05 ; @tm.stop( x ) } @tm.timed_stats.min.should be_within( 0.003 ).of(0.05) @tm.value_stats.min.should be == 0 end it "keeps track of the max value" do 3.times { |x| @tm.start ; sleep 0.05 ; @tm.stop( x ) } @tm.timed_stats.max.should be_within(0.003).of( 0.05 ) @tm.value_stats.max.should be == 2 end it "keeps track of the sum value" do 3.times { |x| @tm.start ; sleep 0.05 ; @tm.stop( x ) } @tm.timed_stats.sum.should be_within(0.01).of(0.15) @tm.value_stats.sum.should be == 3 end it "keeps track of the sum of squares value" do 3.times { |x| @tm.start ; sleep 0.05 ; @tm.stop( x ) } @tm.timed_stats.sumsq.should be_within(0.0005).of(0.0075) @tm.value_stats.sumsq.should be == 5 end it "keeps track of the minimum start time of all the intervals" do f1 = Time.now.gmtime.to_f * 1000000 5.times { @tm.start ; sleep 0.05 ; @tm.stop( 1 ) } f2 = Time.now.gmtime.to_f * 1000000 @tm.sampling_start_time.should be >= f1 @tm.sampling_start_time.should be < f2 # distance from now to start time should be greater than the distance from # the start to the min start_time (f2 - @tm.sampling_start_time).should > ( @tm.sampling_start_time - f1 ) end it "keeps track of the last stop time of all the intervals" do f1 = Time.now.gmtime.to_f * 1_000_000 5.times { @tm.start ; sleep 0.05 ; @tm.stop( 1 ) } sleep 0.05 f2 = Time.now.gmtime.to_f * 1_000_000 @tm.sampling_stop_time.should be > f1 @tm.sampling_stop_time.should be <= f2 # distance from now to max stop time time should be less than the distance # from the start to the max stop time (f2 - @tm.sampling_stop_time).should < ( @tm.sampling_stop_time - f1 ) end it "can create an already running timer" do t = Hitimes::TimedValueMetric.now( 'already-running' ) t.should be_running end it "can measure a block of code from an instance" do t = Hitimes::TimedValueMetric.new( 'measure a block' ) 3.times { t.measure( 1 ) { sleep 0.05 } } t.duration.should be_within(0.004).of(0.15) t.timed_stats.count.should be == 3 t.value_stats.count.should be == 3 end it "returns the value of the block when measuring" do t = Hitimes::TimedValueMetric.new( 'measure a block' ) x = t.measure( 42 ) { sleep 0.05; 42 } t.duration.should be_within(0.002).of(0.05) x.should be == 42 end describe "#to_hash" do it "has name value" do h = @tm.to_hash h['name'].should be == "test-timed-value-metric" end it "has an empty has for additional_data" do h = @tm.to_hash h['additional_data'].should be == Hash.new h['additional_data'].size.should be == 0 end it "has a rate" do 5.times { |x| @tm.start ; sleep 0.05 ; @tm.stop( x ) } h = @tm.to_hash h['rate'].should be_within(1.0 ).of(40.0) end it "has a unit_count" do 5.times { |x| @tm.start ; sleep 0.05 ; @tm.stop( x ) } h = @tm.to_hash h['unit_count'].should be == 10 end fields = %w[ name additional_data sampling_start_time sampling_stop_time value_stats timed_stats rate unit_count ] fields.each do |f| it "should have a value for #{f}" do 3.times { |x| @tm.measure(x) { sleep 0.001 } } h = @tm.to_hash h[f].should_not be_nil end end end end ruby-hitimes-1.2.1/spec/value_metric_spec.rb000066400000000000000000000061771231701356700211240ustar00rootroot00000000000000require 'spec_helper' describe Hitimes::ValueMetric do before( :each ) do @metric = Hitimes::ValueMetric.new( "testing" ) 10.times { |x| @metric.measure( x ) } end it 'has a name' do @metric.name.should be == "testing" end it "has associated data from initialization" do m = Hitimes::ValueMetric.new( "more-data", 'foo' => 'bar', 'this' => 'that' ) m.additional_data['foo'].should be == 'bar' m.additional_data['this'].should be == 'that' m = Hitimes::ValueMetric.new( "more-data", { 'foo' => 'bar', 'this' => 'that' } ) m.additional_data['foo'].should be == 'bar' m.additional_data['this'].should be == 'that' end it "calculates the mean of the measurements" do @metric.mean.should be == 4.5 end it "calculates the stddev of the measurements" do @metric.stddev.should > 0.0 end it "returns 0.0 for stddev if there is no data" do m = Hitimes::ValueMetric.new('0-data') m.stddev.should be == 0.0 end it "keeps track of the sum of data" do @metric.sum.should be == 45.0 end it "keeps track of the sum of squars of data" do @metric.sumsq.should be == 285.0 end it "retuns 0.0 for mean if there is no data" do Hitimes::ValueMetric.new('0-data').mean.should be == 0.0 end it "keeps track of the min value" do @metric.min.should be == 0 end it "keeps track of the max value" do @metric.max.should be == 9 end it "keeps track of the first start time of all the measurements" do m = Hitimes::ValueMetric.new( "first-start-time" ) f1 = Time.now.gmtime.to_f * 1_000_000 10.times{ |x| m.measure( x ); sleep 0.1 } f2 = Time.now.gmtime.to_f * 1_000_000 m.sampling_start_time.should be >= f1 m.sampling_start_time.should be < f2 # distance from now to start time should be greater than the distance from # the start to the min start_time (f2 - m.sampling_start_time).should > ( m.sampling_start_time - f1 ) end it "keeps track of the last stop time of all the intervals" do m = Hitimes::ValueMetric.new( "last-stop-time" ) f1 = Time.now.gmtime.to_f * 1_000_000 10.times {|x| m.measure( x ); sleep 0.1 } f2 = Time.now.gmtime.to_f * 1_000_000 m.sampling_stop_time.should be > f1 m.sampling_stop_time.should be <= f2 # distance from now to max stop time time should be less than the distance # from the start to the max stop time (f2 - m.sampling_stop_time).should < ( m.sampling_stop_time - f1 ) end describe "#to_hash" do it "has name value" do h = @metric.to_hash h['name'].should be == "testing" end it "has an empty has for additional_data" do h = @metric.to_hash h['additional_data'].should be == Hash.new h['additional_data'].size.should be == 0 end it "has the right sum" do h = @metric.to_hash h['sum'].should be == 45 end fields = ::Hitimes::Stats::STATS.dup + %w[ name additional_data sampling_start_time sampling_stop_time ] fields = fields - [ 'rate' ] fields.each do |f| it "should have a value for #{f}" do h = @metric.to_hash h[f].should_not be_nil end end end end ruby-hitimes-1.2.1/spec/version_spec.rb000066400000000000000000000002401231701356700201130ustar00rootroot00000000000000require "spec_helper" describe "Hitimes::Version" do it "should be accessable as a constant" do Hitimes::VERSION.should match(/\d+\.\d+\.\d+/) end end ruby-hitimes-1.2.1/tasks/000077500000000000000000000000001231701356700152665ustar00rootroot00000000000000ruby-hitimes-1.2.1/tasks/default.rake000066400000000000000000000205641231701356700175650ustar00rootroot00000000000000# vim: syntax=ruby require 'rake/clean' #------------------------------------------------------------------------------ # If you want to Develop on this project just run 'rake develop' and you'll # have all you need to get going. If you want to use bundler for development, # then run 'rake develop:using_bundler' #------------------------------------------------------------------------------ namespace :develop do # Install all the development and runtime dependencies of this gem using the # gemspec. task :default do require 'rubygems/dependency_installer' installer = Gem::DependencyInstaller.new This.set_coverage_gem puts "Installing gem depedencies needed for development" This.platform_gemspec.dependencies.each do |dep| if dep.matching_specs.empty? then puts "Installing : #{dep}" installer.install dep else puts "Skipping : #{dep} -> already installed #{dep.matching_specs.first.full_name}" end end puts "\n\nNow run 'rake test'" end # Create a Gemfile that just references the gemspec file 'Gemfile' => :gemspec do File.open( "Gemfile", "w+" ) do |f| f.puts 'source :rubygems' f.puts 'gemspec' end end desc "Create a bundler Gemfile" task :using_bundler => 'Gemfile' do puts "Now you can 'bundle'" end # Gemfiles are build artifacts CLOBBER << FileList['Gemfile*'] end desc "Boostrap development" task :develop => "develop:default" #------------------------------------------------------------------------------ # Minitest - standard TestTask #------------------------------------------------------------------------------ begin require 'rake/testtask' Rake::TestTask.new( :test ) do |t| t.ruby_opts = %w[ -w -rubygems ] t.libs = %w[ lib spec ] t.pattern = "spec/**/*_spec.rb" end task :test_requirements task :test => :test_requirements task :default => :test rescue LoadError This.task_warning( 'test' ) end #------------------------------------------------------------------------------ # RDoc - standard rdoc rake task, although we must make sure to use a more # recent version of rdoc since it is the one that has 'tomdoc' markup #------------------------------------------------------------------------------ begin gem 'rdoc' # otherwise we get the wrong task from stdlib require 'rdoc/task' RDoc::Task.new do |t| t.markup = 'tomdoc' t.rdoc_dir = 'doc' t.main = 'README.md' t.title = "#{This.name} #{This.version}" t.rdoc_files.include( FileList['*.{rdoc,md,txt}'], FileList['ext/**/*.c'], FileList['lib/**/*.rb'] ) end rescue LoadError => le This.task_warning( 'rdoc' ) end #------------------------------------------------------------------------------ # Coverage - optional code coverage, rcov for 1.8 and simplecov for 1.9, so # for the moment only rcov is listed. #------------------------------------------------------------------------------ if RUBY_VERSION < "1.9.0" begin require 'rcov/rcovtask' Rcov::RcovTask.new( 'coverage' ) do |t| t.libs << 'spec' t.pattern = 'spec/**/*_spec.rb' t.verbose = true t.rcov_opts << "-x ^/" # remove all the global files t.rcov_opts << "--sort coverage" # so we see the worst files at the top end rescue LoadError This.task_warning( 'rcov' ) end else begin require 'simplecov' desc 'Run tests with code coverage' task :coverage do ENV['COVERAGE'] = 'true' Rake::Task[:test].execute end CLOBBER << FileList["coverage"] rescue LoadError This.task_warning( 'simplecov' ) end end #------------------------------------------------------------------------------ # Manifest - We want an explicit list of thos files that are to be packaged in # the gem. Most of this is from Hoe. #------------------------------------------------------------------------------ namespace 'manifest' do desc "Check the manifest" task :check => :clean do files = FileList["**/*", ".*"].exclude( This.exclude_from_manifest ).to_a.sort files = files.select{ |f| File.file?( f ) } tmp = "Manifest.tmp" File.open( tmp, 'w' ) do |f| f.puts files.join("\n") end begin sh "diff -du Manifest.txt #{tmp}" ensure rm tmp end puts "Manifest looks good" end desc "Generate the manifest" task :generate => :clean do files = %x[ git ls-files ].split("\n").sort files.reject! { |f| f =~ This.exclude_from_manifest } File.open( "Manifest.txt", "w" ) do |f| f.puts files.join("\n") end end end #------------------------------------------------------------------------------ # Fixme - look for fixmes and report them #------------------------------------------------------------------------------ namespace :fixme do task :default => 'manifest:check' do This.manifest.each do |file| next if file == __FILE__ next unless file =~ %r/(txt|rb|md|rdoc|css|html|xml|css)\Z/ puts "FIXME: Rename #{file}" if file =~ /fixme/i IO.readlines( file ).each_with_index do |line, idx| prefix = "FIXME: #{file}:#{idx+1}".ljust(42) puts "#{prefix} => #{line.strip}" if line =~ /fixme/i end end end def fixme_project_root This.project_path( '../fixme' ) end def fixme_project_path( subtree ) fixme_project_root.join( subtree ) end def local_fixme_files This.manifest.select { |p| p =~ %r|^tasks/| } end def outdated_fixme_files local_fixme_files.reject do |local| upstream = fixme_project_path( local ) Digest::SHA256.file( local ) == Digest::SHA256.file( upstream ) end end def fixme_up_to_date? outdated_fixme_files.empty? end desc "See if the fixme tools are outdated" task :outdated => :release_check do if fixme_up_to_date? then puts "Fixme files are up to date." else outdated_fixme_files.each do |f| puts "#{f} is outdated" end end end desc "Update outdated fixme files" task :update => :release_check do if fixme_up_to_date? then puts "Fixme files are already up to date." else puts "Updating fixme files:" outdated_fixme_files.each do |local| upstream = fixme_project_path( local ) puts " * #{local}" FileUtils.cp( upstream, local ) end puts "Use your git commands as appropriate." end end end desc "Look for fixmes and report them" task :fixme => "fixme:default" #------------------------------------------------------------------------------ # Gem Specification #------------------------------------------------------------------------------ # Really this is only here to support those who use bundler desc "Build the #{This.name}.gemspec file" task :gemspec do File.open( This.gemspec_file, "wb+" ) do |f| f.write This.platform_gemspec.to_ruby end end # the gemspec is also a dev artifact and should not be kept around. CLOBBER << This.gemspec_file.to_s # .rbc files from ruby 2.0 CLOBBER << FileList["**/*.rbc"] # The standard gem packaging task, everyone has it. require 'rubygems/package_task' Gem::PackageTask.new( This.platform_gemspec ) do # nothing end #------------------------------------------------------------------------------ # Release - the steps we go through to do a final release, this is pulled from # a compbination of mojombo's rakegem, hoe and hoe-git # # 1) make sure we are on the master branch # 2) make sure there are no uncommitted items # 3) check the manifest and make sure all looks good # 4) build the gem # 5) do an empty commit to have the commit message of the version # 6) tag that commit as the version # 7) push master # 8) push the tag # 7) pus the gem #------------------------------------------------------------------------------ task :release_check do unless `git branch` =~ /^\* master$/ abort "You must be on the master branch to release!" end unless `git status` =~ /^nothing to commit/m abort "Nope, sorry, you have unfinished business" end end desc "Create tag v#{This.version}, build and push #{This.platform_gemspec.full_name} to rubygems.org" task :release => [ :release_check, 'manifest:check', :gem ] do sh "git commit --allow-empty -a -m 'Release #{This.version}'" sh "git tag -a -m 'v#{This.version}' v#{This.version}" sh "git push origin master" sh "git push origin v#{This.version}" sh "gem push pkg/#{This.platform_gemspec.full_name}.gem" end ruby-hitimes-1.2.1/tasks/extension.rake000066400000000000000000000023341231701356700201500ustar00rootroot00000000000000# To be used if the gem has extensions. # If this task set is inclueded then you will need to also have # # spec.add_development_dependency( 'rake-compiler', '~> 0.8.1' ) # # in your top level rakefile begin require 'rake/extensiontask' require 'rake/javaextensiontask' if RUBY_PLATFORM == "java" then Rake::JavaExtensionTask.new( This.name) do |ext| ext.ext_dir = File.join( 'ext', This.name, "java" ) ext.lib_dir = File.join( 'lib', This.name ) ext.gem_spec = This.java_gemspec end else Rake::ExtensionTask.new( This.name ) do |ext| ext.ext_dir = File.join( 'ext', This.name, "c" ) ext.lib_dir = File.join( 'lib', This.name ) ext.gem_spec = This.ruby_gemspec ext.cross_compile = true # enable cross compilation (requires cross compile toolchain) ext.cross_platform = 'i386-mswin32' # forces the Windows platform instead of the default one # configure options only for cross compile end end task :test_requirements => :compile rescue LoadError This.task_warning( 'extension' ) end CLOBBER << FileList["lib/**/*.{jar,so,bundle}"] CLOBBER << FileList["lib/#{This.name}/{1.8,1.9,2.0}/"] ruby-hitimes-1.2.1/tasks/this.rb000066400000000000000000000136371231701356700165740ustar00rootroot00000000000000require 'pathname' # Public: A Class containing all the metadata and utilities needed to manage a # ruby project. class ThisProject # The name of this project attr_accessor :name # The author's name attr_accessor :author # The email address of the author(s) attr_accessor :email # The homepage of this project attr_accessor :homepage # The regex of files to exclude from the manifest attr_accessor :exclude_from_manifest # The hash of Gem::Specifications keyed' by platform attr_accessor :gemspecs # Public: Initialize ThisProject # # Yields self def initialize(&block) @exclude_from_manifest = %r/\.(git|DS_Store)|^(doc|coverage|pkg|tmp)|Gemfile*|\.(gemspec|swp|jar|bundle|so|rvmrc)$|~$/ @gemspecs = Hash.new yield self if block_given? end # Public: return the version of ThisProject # # Search the ruby files in the project looking for the one that has the # version string in it. This does not eval any code in the project, it parses # the source code looking for the string. # # Returns a String version def version [ "lib/#{ name }.rb", "lib/#{ name }/version.rb" ].each do |v| path = project_path( v ) line = path.read[/^\s*VERSION\s*=\s*.*/] if line then return line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1] end end end # Internal: Return a section of an RDoc file with the given section name # # path - the relative path in the project of the file to parse # section_name - the section out of the file from which to parse data # # Retuns the text of the section as an array of paragrphs. def section_of( file, section_name ) re = /^[=#]+ (.*)$/ sectional = project_path( file ) parts = sectional.read.split( re )[1..-1] parts.map! { |p| p.strip } sections = Hash.new Hash[*parts].each do |k,v| sections[k] = v.split("\n\n") end return sections[section_name] end # Internal: print out a warning about the give task def task_warning( task ) warn "WARNING: '#{task}' tasks are not defined. Please run 'rake develop'" end # Internal: Return the full path to the file that is relative to the project # root. # # path - the relative path of the file from the project root # # Returns the Pathname of the file def project_path( *relative_path ) project_root.join( *relative_path ) end # Internal: The absolute path of this file # # Returns the Pathname of this file. def this_file_path Pathname.new( __FILE__ ).expand_path end # Internal: The root directory of this project # # This is defined as being the directory that is in the path of this project # that has the first Rakefile # # Returns the Pathname of the directory def project_root this_file_path.ascend do |p| rakefile = p.join( 'Rakefile' ) return p if rakefile.exist? end end # Internal: Returns the contents of the Manifest.txt file as an array # # Returns an Array of strings def manifest manifest_file = project_path( "Manifest.txt" ) abort "You need a Manifest.txt" unless manifest_file.readable? manifest_file.readlines.map { |l| l.strip } end # Internal: Return the files that define the extensions # # Returns an Array def extension_conf_files manifest.grep( /extconf.rb\Z/ ) end # Internal: Returns the gemspace associated with the current ruby platform def platform_gemspec gemspecs[platform] end def core_gemspec Gem::Specification.new do |spec| spec.name = name spec.version = version spec.author = author spec.email = email spec.homepage = homepage spec.summary = summary spec.description = description spec.files = manifest spec.executables = spec.files.grep(/^bin/) { |f| File.basename(f) } spec.test_files = spec.files.grep(/^spec/) spec.extra_rdoc_files += spec.files.grep(/(txt|rdoc|md)$/) spec.rdoc_options = [ "--main" , 'README.md', "--markup", "tomdoc" ] end end # Internal: Return the gemspec for the ruby platform def ruby_gemspec( core = core_gemspec, &block ) yielding_gemspec( 'ruby', core, &block ) end # Internal: Return the gemspec for the jruby platform def java_gemspec( core = core_gemspec, &block ) yielding_gemspec( 'java', core, &block ) end # Internal: give an initial spec and a key, create a new gemspec based off of # it. # # This will force the new gemspecs 'platform' to be that of the key, since the # only reason you would have multiple gemspecs at this point is to deal with # different platforms. def yielding_gemspec( key, core ) spec = gemspecs[key] ||= core.dup spec.platform = key yield spec if block_given? return spec end # Internal: Set the recovery gem development dependency # # These are dynamically set since they cannot be hard coded as there is # no way to ship them correctly in the gemspec # # Returns nothing. def set_coverage_gem if RUBY_VERSION < "1.9.0" platform_gemspec.add_development_dependency( 'rcov', '~> 1.0.0' ) else platform_gemspec.add_development_dependency( 'simplecov', '~> 0.7.1' ) end end # Internal: Return the platform of ThisProject at the current moment in time. def platform (RUBY_PLATFORM == "java") ? 'java' : Gem::Platform::RUBY end # Internal: Return the DESCRIPTION section of the README.rdoc file def description_section section_of( 'README.md', 'DESCRIPTION') end # Internal: Return the summary text from the README def summary description_section.first end # Internal: Return the full description text from the READEM def description description_section.join(" ").tr("\n", ' ').gsub(/[{}]/,'').gsub(/\[[^\]]+\]/,'') # strip rdoc end # Internal: The path to the gemspec file def gemspec_file project_path( "#{ name }.gemspec" ) end end This = ThisProject.new