From: Peter Zotov Date: 2012-07-03T12:59:24+09:00 Subject: Re: Using binding + set_trace_func to capture execution state Reginald Tan писал 03.07.2012 05:11: > Hi guys, I'm interested in building a program that will display the > callgraph trace of a program and at the same time will allow you to > inspect the variables in your program *after* the execution has ended > (diff from using debugger to halt execution and inspecting the > state). > > Initially I thought I could use set_trace_func and store the binding > in > a table and just retrieve that binding later on to evaluate the > resulting expression of my target variable, but it's not behaving as > I > expected. In the code provided below, I thought running it would > output > "1 3 5", but I get "5 5 5" instead. > > What am I missing here? Is there another way to go about what I'm > trying > to do? Thanks! > > > binding_table = {} > > def hello > x = 1 > x = 3 > x = 5 > end > > set_trace_func proc { |event, file, line, id, binding, classname| > if event == "line" > binding_table[line] = binding > end > } > > hello > > set_trace_func nil > > puts eval("x", binding_table[4]) > puts eval("x", binding_table[5]) > puts eval("x", binding_table[6]) Oh, it's very simple. The `binding' object denotes the variable scope. The scope doesn't change in this case; the values do. You can think of a Binding this way (long story short, it's implemented _very roughly_ like that in Rubinius): class Binding attr_accessor :locals def initialize @locals = {} end end ... and of variable access this way: def func binding.locals[:x] = 1 # x = 1 p binding.locals[:x] # p x binding.locals[:x] = 2 # x = 2 end Now the answer should be obvious. To achieve your goal you'd need to copy the state of variables at each tracefunc invocation. Even worse, as the objects themselves may change, you will need to do a deep copy each time (otherwise you'll pluck into exactly the same problem with object instance variables). I would suggest marshalling the objects and writing them to something like tmpfs, then using a special tool to navigate the captured information. This is going to consume a lot of memory. I repeat: a lot. Like tens of gigabytes for a complex thing like... Sinatra. And probably terabytes for Rails. -- WBR, Peter Zotov.