Avoid INT2NUM overhead when coercing date specific elements for MYSQL_TYPE_TIME + introduce basic infrastructure for measuring GC overhead

This commit is contained in:
Lourens Naudé 2010-08-08 23:02:28 +01:00 committed by Brian Lopez
parent d9153b82fc
commit 2609783aeb
3 changed files with 41 additions and 5 deletions

View File

@ -47,7 +47,7 @@ namespace :bench do
define_bench_task :query_with_mysql_casting
define_bench_task :query_without_mysql_casting
define_bench_task :sequel
define_bench_task :allocations
end
# Load custom tasks
Dir['tasks/*.rake'].sort.each { |f| load f }

33
benchmark/allocations.rb Normal file
View File

@ -0,0 +1,33 @@
# encoding: UTF-8
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
raise Mysql2::Mysql2Error.new("GC allocation benchmarks only supported on Ruby 1.9!") unless RUBY_VERSION =~ /1\.9/
require 'rubygems'
require 'benchmark'
require 'active_record'
ActiveRecord::Base.default_timezone = :local
ActiveRecord::Base.time_zone_aware_attributes = true
class Mysql2Model < ActiveRecord::Base
set_table_name :mysql2_test
end
def bench_allocations(feature, iterations = 10, &blk)
puts "GC overhead for #{feature}"
Mysql2Model.establish_connection(:adapter => 'mysql2', :database => 'test')
GC::Profiler.clear
GC::Profiler.enable
iterations.times{ blk.call }
GC::Profiler.report(STDOUT)
GC::Profiler.disable
end
bench_allocations('coercion') do
Mysql2Model.all(:limit => 1000).each{ |r|
r.attributes.keys.each{ |k|
r.send(k.to_sym)
}
}
end

View File

@ -6,7 +6,7 @@ rb_encoding *binaryEncoding;
VALUE cMysql2Result;
VALUE cBigDecimal, cDate, cDateTime;
VALUE opt_decimal_zero, opt_float_zero;
VALUE opt_decimal_zero, opt_float_zero, opt_time_year, opt_time_month;
extern VALUE mMysql2, cMysql2Client, cMysql2Error;
static VALUE intern_encoding_from_charset;
static ID intern_new, intern_utc, intern_local, intern_encoding_from_charset_code,
@ -96,7 +96,6 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
MYSQL_FIELD * fields = NULL;
unsigned int i = 0;
unsigned long * fieldLengths;
double column_to_double;
void * ptr;
#ifdef HAVE_RUBY_ENCODING_H
rb_encoding *default_internal_enc = rb_default_internal_encoding();
@ -155,7 +154,8 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
}
break;
case MYSQL_TYPE_FLOAT: // FLOAT field
case MYSQL_TYPE_DOUBLE: // DOUBLE or REAL field
case MYSQL_TYPE_DOUBLE: { // DOUBLE or REAL field
double column_to_double;
column_to_double = strtod(row[i], NULL);
if (column_to_double == 0.000000){
val = opt_float_zero;
@ -163,10 +163,11 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
val = rb_float_new(column_to_double);
}
break;
}
case MYSQL_TYPE_TIME: { // TIME field
int hour, min, sec, tokens;
tokens = sscanf(row[i], "%2d:%2d:%2d", &hour, &min, &sec);
val = rb_funcall(rb_cTime, db_timezone, 6, INT2NUM(2000), INT2NUM(1), INT2NUM(1), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
val = rb_funcall(rb_cTime, db_timezone, 6, opt_time_year, opt_time_month, opt_time_month, INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
if (!NIL_P(app_timezone)) {
if (app_timezone == intern_local) {
val = rb_funcall(val, intern_localtime, 0);
@ -435,6 +436,8 @@ void init_mysql2_result() {
opt_decimal_zero = rb_str_new2("0.0");
rb_global_variable(&opt_float_zero);
opt_float_zero = rb_float_new((double)0);
opt_time_year = INT2NUM(2000);
opt_time_month = INT2NUM(1);
#ifdef HAVE_RUBY_ENCODING_H
binaryEncoding = rb_enc_find("binary");