add a statistics command to compiler

just to see how many objects make up a binary
This commit is contained in:
Torsten Rüger 2019-09-05 13:25:40 +03:00
parent 91995dc1b3
commit 7d92ee9e6a
4 changed files with 59 additions and 15 deletions

View File

@ -3,11 +3,17 @@ require_relative "binary_writer"
module Risc
# From code, the next step down is Vool, then Mom (in two steps)
#
# The next step transforms to the register machine layer, which is quite close to what actually
# executes. The step after transforms to Arm, which creates executables.
# A RiscCollection is the last virtual stop on the way to binary.
# It creates a Linker to go to binary. The name linker came in analogy to
# "normal" (ie c world) lingo, because there too the linker is all about
# positioning code and data.
#
# Here we also do the assembling, which (at least in arm) creates this mess
# of dependencies. As a simple example imagine a branch, a load and the label
# to which we jump. The brnahc needs the address, but the load may be 4 or 8
# instructions, and thus the label address is only known after the load.
# Exrapolate times 10, that's why this works with listeners and a sort
# of self organizing aproach (see class Position).
class Linker
include Util::Logging

View File

@ -7,7 +7,7 @@ module Risc
# into one stream or binary text object. This is then written to an ELF text section.
#
# A word about positions: The c world has a thing called position independent code, and
# baically we follw that idea. Code (ie jumps and constant loads) are all relative.
# basically we follw that idea. Code (ie jumps and constant loads) are all relative.
# But we have pointers. In C the linker takes care of bending those, we have to
# do that ourselves, in write_ref. That's why we need the load adddess and basically
# we just add it to pointers.

View File

@ -7,10 +7,35 @@ class RubyXC < Thor
class_option :mesages , type: :numeric
class_option :elf , type: :boolean
desc "stats FILE" , "Give object statistics on compiled FILE"
long_desc <<-LONGDESC
Compile the give file name and print statistics on the binary.
A Binary file is in essence an ObjectSpace, ie a collection of objects.
This command tells you how many objects of each kind, the amount of bytes
objects of that class take, and the total amount of bytes taken.
Together with various options this may be used to tune the executable, or just fyi.
LONGDESC
def stats(file)
compile(file)
by_class = Hash.new(0)
Risc::Position.positions.each do |object , _ |
by_class[object.class] += 1 if Risc::Position.is_object(object)
end
obj, total = 0 , 0
by_class.each do |clazz , num|
dis = (clazz == Symbol) ? 8 : clazz.memory_size
puts clazz.name.split("::").last + " == #{num} / #{num*dis}"
obj += num
total += num * dis
end
puts "\nTotal Objects=#{obj} Words=#{total}"
end
desc "compile FILE" , "Compile given FILE to binary"
long_desc <<-LONGDESC
Compile the give file name to binary object file (see long descr.)
Compile the give file name to binary object file (see below.)
Output will be elf object file of the same name, with .o, in root directory.
@ -18,16 +43,9 @@ class RubyXC < Thor
executing it. This can be done on a mac by installing a cross linker
(brew install arm-linux-gnueabihf-binutils), or on the target arm machine.
LONGDESC
def compile(file)
begin
ruby = File.read(file)
rescue
fail MalformattedArgumentError , "No such file #{file}"
end
puts "compiling #{file}"
linker = ::RubyX::RubyXCompiler.new(extract_options).ruby_to_binary( ruby , :arm )
linker = do_compile(file)
elf = { debug: options[:elf] || false }
writer = Elf::ObjectWriter.new(linker , elf)
@ -100,6 +118,17 @@ class RubyXC < Thor
end
private
# Open file, create compiler, compile and return linker
def do_compile(file)
begin
ruby = File.read(file)
rescue
fail MalformattedArgumentError , "No such file #{file}"
end
puts "compiling #{file}"
::RubyX::RubyXCompiler.new(extract_options).ruby_to_binary( ruby , :arm )
end
def extract_options
opt = { Integer: options[:integers] || 1024 ,
Message: options[:messages] || 1024}

View File

@ -20,5 +20,14 @@ module RubyX
def test_interpret
assert_output(/interpreting/) {RubyXC.start(["interpret" , "test/mains/source/add__4.rb"])}
end
def test_execute
assert_output(/Running/) {RubyXC.start(["execute" , "test/mains/source/add__4.rb"])}
end
def test_stats
out, err = capture_io {RubyXC.start(["stats" , "test/mains/source/add__4.rb"])}
assert out.include?("Space") , out
assert out.include?("Total") , out
assert out.include?("Objects=") , out
end
end
end