Permalink
Browse files

Added internal coverage tool.

  • Loading branch information...
1 parent c43b01d commit 9aa8465e2e97f3f3c65b7c062274dac15e907cdb @brixen brixen committed Sep 4, 2012
View
1 .gitignore
@@ -32,7 +32,6 @@ TAGS
\#*
autom4te.cache
code-cache
-coverage
/config.rb
cscope.files
cscope.out
View
1 lib/tooling/coverage.rb
@@ -0,0 +1 @@
+require 'tooling/coverage/coverage'
View
38 lib/tooling/coverage/coverage.rb
@@ -0,0 +1,38 @@
+module Rubinius
+ class Coverage
+ def self.loaded(flag)
+ @loaded = flag
+ end
+
+ def self.loaded?
+ @loaded == true
+ end
+
+ def self.load
+ return if loaded?
+
+ Tooling.load File.expand_path("../ext/coverage", __FILE__)
+ loaded true
+
+ self
+ end
+
+ attr_reader :results
+
+ def initialize
+ self.class.load
+ end
+
+ def start
+ Rubinius::Tooling.enable
+
+ self
+ end
+
+ def stop
+ @results = Rubinius::Tooling.disable
+
+ self
+ end
+ end
+end
View
156 lib/tooling/coverage/ext/coverage.cpp
@@ -0,0 +1,156 @@
+#include <rbxti.hpp>
+#include <rbxti/atomic.hpp>
+#include <rbx_config.h>
+
+#include <iostream>
+#include <tr1/unordered_map>
+
+#ifndef RBX_HAVE_TR1_HASH
+namespace std {
+ namespace tr1 {
+ template <>
+ struct hash<r_mint> {
+ size_t operator()(const r_mint id) const {
+ return id;
+ }
+ };
+ }
+}
+#endif
+using namespace rbxti;
+
+namespace coverage {
+
+ typedef std::tr1::unordered_map<int, int> InstructionCoverageMap;
+ typedef std::tr1::unordered_map<r_mint, InstructionCoverageMap*> CoverageMap;
+
+ class Coverage {
+ CoverageMap coverage_map_;
+ rbxti::SpinLock lock_;
+
+ public:
+ Coverage() { }
+ ~Coverage();
+
+ void lock() {
+ lock_.lock();
+ }
+
+ void unlock() {
+ lock_.unlock();
+ }
+
+ void add(Env* env, r_mint id, int ip);
+ robject results(Env* env);
+ };
+
+ Coverage::~Coverage() {
+ for(CoverageMap::iterator i = coverage_map_.begin();
+ i != coverage_map_.end();
+ i++) {
+ delete i->second;
+ }
+ }
+
+ void Coverage::add(Env* env, r_mint id, int ip) {
+ lock();
+
+ InstructionCoverageMap *map;
+ CoverageMap::iterator i = coverage_map_.find(id);
+
+ if(i == coverage_map_.end()) {
+ map = new InstructionCoverageMap;
+ coverage_map_[id] = map;
+ } else {
+ map = i->second;
+ }
+
+ InstructionCoverageMap::iterator j = map->find(ip);
+
+ if(j == map->end()) {
+ (*map)[ip] = 1;
+ } else {
+ (*map)[ip] += 1;
+ }
+
+ unlock();
+ }
+
+ static void ccode_iterator(Env* env, rcompiled_code code, void* data) {
+ rtable map = (rtable)data;
+ r_mint id = env->method_id(code);
+
+ bool found = false;
+ robject obj = env->table_fetch(map, env->integer_new(id), &found);
+ if(!found) return;
+
+ rtable attr = env->cast_to_rtable(obj);
+ if(!attr) return;
+
+ env->table_store(attr, env->symbol("code"), code);
+ }
+
+ robject Coverage::results(Env* env) {
+ rtable coverage_map = env->table_new();
+
+ for(CoverageMap::iterator i = coverage_map_.begin();
+ i != coverage_map_.end();
+ i++) {
+ InstructionCoverageMap* map = i->second;
+ rtable method_map = env->table_new();
+
+ for(InstructionCoverageMap::iterator j = map->begin();
+ j != map->end();
+ j++) {
+ env->table_store(method_map,
+ env->integer_new(j->first),
+ env->integer_new(j->second));
+ }
+
+ rtable attr = env->table_new();
+ env->table_store(attr, env->symbol("counts"), method_map);
+
+ env->table_store(coverage_map, env->integer_new(i->first), attr);
+ }
+
+ env->find_all_compiled_code(ccode_iterator, (void*)coverage_map);
+
+ return coverage_map;
+ }
+
+ namespace {
+ void coverage_enable(Env* env) {
+ Coverage* coverage = new Coverage;
+ env->set_global_tool_data(coverage);
+ }
+
+ robject coverage_results(Env* env) {
+ Coverage* coverage = reinterpret_cast<Coverage*>(env->global_tool_data());
+
+ env->set_tool_at_ip(NULL);
+ env->set_global_tool_data(NULL);
+
+ robject results = coverage->results(env);
+ delete coverage;
+
+ return results;
+ }
+
+ void coverage_at_ip(Env* env, rmachine_code mcode, int ip) {
+ Coverage* coverage = reinterpret_cast<Coverage*>(env->global_tool_data());
+
+ if(!coverage) return;
+
+ coverage->add(env, env->machine_code_id(mcode), ip);
+ }
+ }
+
+ extern "C" int Tool_Init(Env* env) {
+ env->set_tool_enable(coverage_enable);
+ env->set_tool_results(coverage_results);
+
+ env->set_tool_at_ip(coverage_at_ip);
+
+ return 1;
+ }
+}
View
3 lib/tooling/coverage/ext/extconf.rb
@@ -0,0 +1,3 @@
+require 'mkmf'
+
+create_makefile 'coverage'
View
3 rakelib/extensions.rake
@@ -220,3 +220,6 @@ compile_ext "sdbm", :deps => ["Makefile"],
compile_ext "profiler", :dir => "#{libprefixdir}/tooling/profiler",
:deps => ["Makefile"]
+
+compile_ext "coverage", :dir => "#{libprefixdir}/tooling/coverage/ext",
+ :deps => ["Makefile"]
View
8 vm/builtin/system.cpp
@@ -1082,10 +1082,18 @@ namespace rubinius {
bool disable = CBOOL(o_disable);
+ // TODO: this should be inside tooling
+ bool tooling_interpreter = state->shared().tool_broker()->tooling_interpreter_p();
+
while(obj) {
if(CompiledCode* code = try_as<CompiledCode>(obj)) {
if(MachineCode* mcode = code->machine_code()) {
mcode->deoptimize(state, code, 0, disable);
+ if(tooling_interpreter) {
+ mcode->run = MachineCode::tooling_interpreter;
+ } else {
+ mcode->run = MachineCode::interpreter;
+ }
}
total++;
}
View
6 vm/capi/18/include/rbxti.hpp
@@ -54,6 +54,8 @@ namespace rbxti {
typedef void (*at_ip_func)(Env* env, rmachine_code code, int ip);
+ typedef void (*compiled_code_iterator)(Env* env, rcompiled_code code, void* data);
+
class Env {
public:
EnvPrivate* private_;
@@ -106,6 +108,10 @@ namespace rbxti {
r_mint method_line(rcompiled_code code);
r_mint method_id(rcompiled_code code);
+ void find_all_compiled_code(compiled_code_iterator func, void* data);
+
+ r_mint machine_code_id(rmachine_code code);
+
rtable table_new();
robject table_fetch(rtable tbl, robject key, bool* fetched);
void table_store(rtable tbl, robject key, robject val);
View
6 vm/capi/19/include/rbxti.hpp
@@ -54,6 +54,8 @@ namespace rbxti {
typedef void (*at_ip_func)(Env* env, rmachine_code code, int ip);
+ typedef void (*compiled_code_iterator)(Env* env, rcompiled_code code, void* data);
+
class Env {
public:
EnvPrivate* private_;
@@ -106,6 +108,10 @@ namespace rbxti {
r_mint method_line(rcompiled_code code);
r_mint method_id(rcompiled_code code);
+ void find_all_compiled_code(compiled_code_iterator func, void* data);
+
+ r_mint machine_code_id(rmachine_code code);
+
rtable table_new();
robject table_fetch(rtable tbl, robject key, bool* fetched);
void table_store(rtable tbl, robject key, robject val);
View
4 vm/instructions.cpp
@@ -661,9 +661,7 @@ Object* MachineCode::tooling_interpreter(STATE,
#undef DISPATCH
#define DISPATCH \
- if(unlikely(state->vm()->tooling())) { \
- state->shared().tool_broker()->at_ip(state, mcode, call_frame->ip()); \
- } \
+ state->shared().tool_broker()->at_ip(state, mcode, call_frame->ip()); \
goto *insn_locations[stream[call_frame->inc_ip()]];
#undef next_int
View
4 vm/instruments/rbxti-internal.hpp
@@ -32,6 +32,10 @@ namespace rbxti {
return (rubinius::CompiledCode*)code;
}
+ static inline rubinius::MachineCode* i(rmachine_code code) {
+ return (rubinius::MachineCode*)code;
+ }
+
static inline rubinius::String* i(rstring s) {
return (rubinius::String*)s;
}
View
26 vm/instruments/rbxti.cpp
@@ -16,6 +16,8 @@
#include "builtin/class.hpp"
#include "instruments/tooling.hpp"
+#include "gc/walker.hpp"
+
#include "object_utils.hpp"
using namespace rubinius;
@@ -230,6 +232,30 @@ namespace rbxti {
return 0;
}
+ void Env::find_all_compiled_code(compiled_code_iterator func, void* data) {
+ ObjectWalker walker(private_->state()->memory());
+ GCData gc_data(private_->state()->vm());
+
+ walker.seed(gc_data);
+
+ Env* env = private_->state()->vm()->tooling_env();
+ Object* obj = walker.next();
+
+ while(obj) {
+ if(CompiledCode* code = try_as<CompiledCode>(obj)) {
+ func(env, rbxti::o(code), data);
+ }
+
+ obj = walker.next();
+ }
+ }
+
+ r_mint Env::machine_code_id(rmachine_code code) {
+ MachineCode* mcode = i(code);
+
+ return (mcode->method_id() << 1) | 1;
+ }
+
rtable Env::table_new() {
return o(LookupTable::create(private_->state()));
}
View
4 vm/instruments/tooling.hpp
@@ -54,6 +54,10 @@ namespace tooling {
global_tool_data_ = d;
}
+ bool tooling_interpreter_p() {
+ return at_ip_func_ != NULL;
+ }
+
public:
void* enter_method(STATE, Executable* exec, Module* mod, Arguments& args, CompiledCode* code);
void leave_method(STATE, void* tag);
View
7 vm/machine_code.cpp
@@ -54,7 +54,6 @@ namespace rubinius {
*/
MachineCode::MachineCode(STATE, CompiledCode* meth)
: parent_(NULL)
- , run(MachineCode::interpreter)
, type(NULL)
, uncommon_count(0)
, number_of_caches_(0)
@@ -65,6 +64,12 @@ namespace rubinius {
, debugging(false)
, flags(0)
{
+ if(state->shared().tool_broker()->tooling_interpreter_p()) {
+ run = MachineCode::tooling_interpreter;
+ } else {
+ run = MachineCode::interpreter;
+ }
+
total = meth->iseq()->opcodes()->num_fields();
opcodes = new opcode[total];

0 comments on commit 9aa8465

Please sign in to comment.