Skip to content

Instantly share code, notes, and snippets.

@frsyuki
Last active June 2, 2018 08:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frsyuki/1dc489476dd569a12b28e325214f5d30 to your computer and use it in GitHub Desktop.
Save frsyuki/1dc489476dd569a12b28e325214f5d30 to your computer and use it in GitHub Desktop.
require 'mkmf'
have_header("ruby/st.h")
have_header("st.h")
$CFLAGS << %[ -Wall -O3 -g]
$CFLAGS << " " << `pkg-config --cflags luajit`.strip
$LDFLAGS << " " << `pkg-config --libs-only-L --libs-only-l luajit`.strip
create_makefile('message_query/message_query')
#include "ruby.h"
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "luajit.h"
struct query_t;
typedef struct query_t query_t;
struct query_t {
lua_State *lua;
VALUE filter_code;
VALUE map_code;
VALUE reduce_code;
};
#define QUERY_T(from, name) \
query_t* name; \
Data_Get_Struct(from, query_t, name); \
if(name == NULL) { \
rb_raise(rb_eArgError, "NULL found for " # name " when shouldn't be."); \
}
static void Query_free(query_t* q)
{
if(q == NULL) {
return;
}
xfree(q);
}
static void Query_init(query_t* q)
{
q->lua = luaL_newstate();
if (q->lua == NULL) {
rb_raise(rb_eRuntimeError, "Failed to allocate a new Lua state."); \
}
luaL_openlibs(q->lua);
}
static void Query_mark(query_t* q)
{
}
VALUE Query_initialize(VALUE self, VALUE path)
{
QUERY_T(self, q);
Check_Type(path, T_STRING);
//char* path_str = malloc(RSTRING_LEN(path) + 1);
//memcpy(path_str, RSTRING_PTR(path), RSTRING_LEN(path));
//path_str[RSTRING_LEN(path)] = '\0';
//int ret = luaL_loadfile(q->lua, path_str);
//free(path_str);
int ret = luaL_loadfile(q->lua, RSTRING_PTR(path));
if (ret != LUA_OK) {
rb_raise(rb_eRuntimeError, "Failed to compile Lua script."); \
}
return self;
}
VALUE Query_alloc(VALUE klass)
{
query_t* q = ZALLOC_N(query_t, 1);
Query_init(q);
VALUE self = Data_Wrap_Struct(klass, Query_mark, Query_free, q);
return self;
}
static VALUE Query_apply(VALUE self, VALUE data)
{
QUERY_T(self, q);
Check_Type(data, T_STRING);
lua_pushlstring(q->lua, RSTRING_PTR(data), RSTRING_LEN(data));
lua_setglobal(q->lua, "data");
int ret = lua_pcall(q->lua, 0, 1, 0);
if (ret != LUA_OK) {
rb_raise(rb_eRuntimeError, "Failed to evaluate Lua script."); \
}
size_t len;
const char* ptr = lua_tolstring(q->lua, -1, &len);
return rb_str_new(ptr, len);
}
void Init_message_query(void)
{
VALUE cQuery = rb_define_class("MessageQuery", rb_cObject);
cQuery = rb_define_class_under(cQuery, "Query", rb_cObject);
rb_define_alloc_func(cQuery, Query_alloc);
rb_define_method(cQuery, "initialize", Query_initialize, 1);
rb_define_method(cQuery, "apply", Query_apply, 1);
}
source 'https://rubygems.org/'
gemspec
Gem::Specification.new do |s|
s.name = "message_query"
s.version = "0.1.0"
s.summary = "MessagePack Query"
s.description = %q{MessagePack Query}
s.authors = ["Sadayuki Furuhashi"]
s.email = ["frsyuki@gmail.com"]
s.license = "Apache 2.0"
s.homepage = "http://msgpack.org/"
s.has_rdoc = false
s.require_paths = ["lib"]
s.files = `git ls-files`.split("\n")
s.extensions = ["ext/message_query/extconf.rb"]
s.test_files = `git ls-files -- {test,spec}/*`.split("\n")
s.add_development_dependency 'bundler', ['~> 1.0']
s.add_development_dependency 'rake'
s.add_development_dependency 'rake-compiler', ['~> 1.0']
s.add_development_dependency 'rspec', ['~> 3.3']
s.add_development_dependency 'json'
end
# $ ruby -Ilib -Iext ex.rb data.msgpack
# Rehearsal -------------------------------------------------------
# MessageQuery LuaJIT 1.190000 0.000000 1.190000 ( 1.189161)
# Ruby 2.5.1 1.360000 0.000000 1.360000 ( 1.365458)
# ---------------------------------------------- total: 2.550000sec
#
# user system total real
# MessageQuery LuaJIT 1.200000 0.000000 1.200000 ( 1.217826)
# Ruby 2.5.1 1.390000 0.000000 1.390000 ( 1.393994)
# {:lua=>837500, :ruby=>837500}
require 'message_query'
require 'msgpack'
require 'benchmark'
data = File.read(ARGV[0])
filter_lua = %{not(string.sub(v[6], 1, 20) == "Mozilla/5.0 (Windows")}
map_lua = %{1}
reduce_lua = %{s = s + v}
mq = MessageQuery.new(filter_lua, map_lua, reduce_lua)
r = {}
Benchmark.bmbm do |x|
x.report("MessageQuery LuaJIT") do
r[:lua] = mq.apply(data, 0)
end
x.report("Ruby #{RUBY_VERSION}") do
state = 0
MessagePack::Unpacker.new.feed_each(data) do |v|
if v[5][0, 20] != "Mozilla/5.0 (Windows"
state += 1
end
end
r[:ruby] = state
end
end
p r
require 'bundler'
Bundler::GemHelper.install_tasks
spec = eval File.read("message_query.gemspec")
require 'rake/extensiontask'
Rake::ExtensionTask.new('message_query', spec) do |ext|
ext.ext_dir = 'ext/message_query'
ext.cross_compile = true
ext.lib_dir = File.join(*['lib', 'message_query', ENV['FAT_DIR']].compact)
# cross_platform names are of MRI's platform name
ext.cross_platform = ['x86-mingw32', 'x64-mingw32']
end
CLEAN.include('lib/message_query/message_query.*')
task :default => [:build]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment