Ruby program hanging SU on test - is there a log file?


#1

I’m trying to debug the logic in a Ruby program which iterates over several loops.

It keeps hanging Sketchup, with no puts statements coming to the console (though there are plenty at earlier stages of the iteration - it crashes part way through).

If I stop the iteration earlier, these puts are all visible.

When I force quit after the program hangs, I can see for a second in the background the Ruby console with the puts showing, and other stuff I can only glimpse, including a SIGTERM something…

Is the console output saved anywhere in a log file to look at? Or only in memory and the console display at the time?

Or is there a way of putting a begin... rescue error trap round all of the program?

At the moment, I’ve introduced some other error which stops it working early in the iteration - when I find and fix that, I could post the code here if that would help.

PS. Trying it again, just before SIGTERM I glimpsed a message that there’s an error in
main:26 to_f

My program isn’t called main, and my line 26 is a blank line.

And I only have a couple of .to_f's in my function get_inputs() reading the input values, which don’t give any problems. IT’s the principal function which has the iterations, not get_inputs()


#2

The termination signal is likely being caused by YOU via the task manager “End task” upon sketchup.exe. Ignore it.

Not normally, but there some logging features that can be switched on.

There is a Logger class in the ruby standard library, and I thought that the Ruby debugger leveraged it. So you may need to do some reading in the debugger’s documentation.


Cannot remember if the SketchUp developer tools has this (perhaps not.):


#3

If I had to guess, it likely is another DC exception.

Always switch off other extensions when testing. Get it working and then test with things like DC switched back on.


#4

No, but you should be using methods, which are explicit code blocks that do not need an opening begin, so you can add any number of rescue clauses (as well as an else and/or ensure clause,) to any or all of your methods. The rescue clause can output messages and then reraise the exception for “higher” handling.

At some point there is likely a master method (a command method) that kicks things off, and calls a series of other methods. This method can have a master rescue clause that traps all exceptions, even those previously trapped by sub-ordinate methods, and re-raised up to the “master” method. (This would allow central handling or central notification to the user of problems.)


#5

Thank you, Dan

I’ll try to follow up your suggestions over the next few days.

I think it is most likely I have a runaway loop. But I can’t see where at the moment.


#6

Supplementing what Dan already wrote,

sigterm is the UNIX signal sent when you tell the OS to kill (terminate) a process. Dan is right that this is due to you force quitting SketchUp, not to a program error.

In Ruby the start point for a running program is always called “main”, so seeing that in a message just means that the error was bounced all the way back to the base of the call stack where a default exception handler caught it. What you saw is probably the line in the console’s load or run command that launched your code, though I don’t know what the glimpse of to_f might mean.

When Ruby is stuck, e.g. in an endless loop, it blocks the SU process completely, and that can prevent puts outputs from appearing on the console. They are queuing up, but can’t get handled until your code lets go. So, I am inclined to suspect that you are right - you have an endless loop that is hogging Ruby and thereby blocking the rest of SU.

You might try some UI.messagebox outputs, since unlike puts they stop the Ruby processing until the user clicks OK. If you’ve gotten NetBeans debugging working, you could also try some carefully placed breakpoints and single-stepping to analyze where and why your code is looping.


#7

Oh of course, but we can’t see where without posting part of the code.

One way to avoid many loop problems is to use the ruby iterators (like, .each, etc.) inside of while and for loops. But even for loops can leverage Ruby’s built-in collection looping, ie:

for item in collection
  puts item.inspect
end

… will loop only over each item in the collection. (It will not seek past the end.)

It is not necessary to explicitly create an iteration step variable (although it can be done if needed,) like:

for i in 0..collection.size-1
  puts collection[i].inspect
end

… which can also be done like:

collection.each_with_index do |item,i|
  puts "#{i} = #{item.inspect}"
end

Anyway, if you are using while or until loops, check them first.

If you are making recursive method calls you should most definitely be employing a rescue clause trapping any SystemStackError. The normal rescue keyword only traps StandardError and it’s subclasses. But a few higher level system errors like SystemStackError, SignalException and NoMemoryError are not StandardError subclasses. (They are siblings being direct child classes of Exception.) So you must explicitly trap for them:

def some_method(*args)
  #
  # lots of code
  #
rescue SystemStackError => e
  puts "Whoops Stack overflow! Our recursive calls are too deep."
  puts e.inspect
  puts e.backtrace if $VERBOSE
rescue NoMemoryError => e
  puts "Whoops, we've gone and run out of memory space !"
  puts e.inspect
  puts e.backtrace if $VERBOSE
rescue => e
  puts "Whoops, a StandardError happened !"
  puts e.inspect
  puts e.backtrace if $VERBOSE
else
  puts "Hey success! Look Ma, no errors!"
ensure
  return false
end

But you can see how error handling can get repetitive.
This is when I write a central error handling method to do this repetitive stuff.
Ie, an exception is an object just like everything else in Ruby. So you can pass references to exceptions between methods.

Often I save the references to exceptions in a collection (array or hash.) If I’m saving LoadError references, I’ll use a hash and make the key the filename in which the error occurred. Then my collection is within my plugin module, and it only contains exceptions caused by my code, and I can iterate it at my leisure to review what errors happened. If I want to start fresh, I can clear the collection, make code changes, and reload the module, and retest. So, as long as Ruby does not crash, I can use the collection as a “live” exception log.
This may not work in your case as you are locking up SketchUp and Ruby.

Now, another bit of advice. If you cause a stack error, or a memory error, I’d not continue doing anything on the machine, until after a reboot. So this means make backups of your code. Save changes before testing, even if you may not be sure the changes are how you wish to do things. This is where multiple backups, ie code scenarios, are a good idea.


#8

Thanks again, Dan, for excellent advice.

My iterations are incremental, and variable, additions to the z-value of a ‘slice’ of a building. So I don’t have a set of ‘things’ to iterate over, and if (as I suspect) at some point I’m either calculating a step size of zero (so nothing gets added to the z-value), or else I’m somehow failing to increment the loop counter.

It’s intended to draw a quarter-ellipse sides and faces of columns, optionally on a slant, for the RiverArch building that NewThinking2 (Scott Baker) is designing. Earlier versions of the program worked, but I was trying to refactor it and enable it to use smaller slice heights, and have screwed it up completely at the moment.

In another glimpse of the Ruby console after I force quit the program, I see that my loop counter i has increased to absurdly large values, in spite ot a line while i <= 10.

LATER.
Put in a UI.messagbox to alert if height increment gets set to zero, and it does. So now to look for logic error that allows that to happen.


#9

Well, I think I’ve sorted the logic error in calculating the slice height to take me either one standard slice up, to the next floor level if lower than a standard floor height, or to the top of the floor.

And also negotiated my way round the top of the lower apex of the ellipse and/or the upper apex.

But I still can’t get the looping to terminate when it has got to the top (z_level > a1) and the next_slice_height is calculated at 0.0.

I’ve put in UI.messageboxes with a break clause after them, but it isn’t stopping the looping.

The program gets stuck with i = 108, and keeps looping, popping up the messagebox saying the next slice height will be zero, and still requiring a force quit to stop it

Code attached if anyone would care to look and help me see where I’m going wrong.

draw_arch_v3-3.rb.zip (4.1 KB)

At the moment, I’m just drawing points, but I want faces and floor lines - the code to produce them is largely commented out.

An older version of the code produced columns like these, but it is not right at the top, and needed manual editing:

Columns.skp (1.5 MB)

But these were drawn one face at a time, before exploding and remaking into whole-column components. I want after I get this bit working to call draw_arch four times, once for each face of a column with a single set of inputs.


#10

John, I think you botched the attachment! The above is what I see in your post, and I can’t download the code from it. Well, actually I managed to trick the website into giving me it, but by devious means.


#11

Very sorry, Steve. Will try again here:
draw_arch_v3-3.rb.zip (4.1 KB)

I think I got the link mixed up with text , and didn’t disentangle it cleanly.


#12

John, when I load that code (even after wrapping it in a module) I get this warning!

load "/Users/steve/Downloads/draw_arch_v3-3.rb"
/Users/steve/Downloads/draw_arch_v3-3.rb:36: warning: redefining Object#initialize may cause infinite loop

Initialize is supposed to be the method within a class that is implicitly called by Object#new when you create an instance. There is no class defined in the file you distributed, so you are affecting the base Object class!


#13

I did see the warning, but didn’t understand its significance.

Should I just leave it out? It was my attempt to have ‘run once’ code to fill the input box with default values to get going.

I think I remember seeing an alternative something like:

@defaults.defined ? @defaults = [starting_values] || [last_used]_values}

but I don’t think I have the syntax right and can’t immediately find the example I thnk I saw some time ago
.
My normal method of operation is to:

  • load the .rb file in the console
  • type initialize
  • type get_inputs

then adjust the parameters if needed, and press OK.

Subsequent runs only need me to press up-arrow three times to retrieve the earlier line, then press {Enter} again.


#14

Your Ruby code is quite poorly formatted.
Put it all inside a module.
Then run the relevant parts using some menu/command code…
e.g. why you include ‘initialize’ in it when it’s not a ‘class’ is a mystery…

Please explain - in non-code English - what t is you wish to do…


#15

John I think the bug is that when you break out of the in-floor loop you fail to increment the i counter, so it get stuck at 107:

          if next_slice_height <0.05
            UI.messagebox "#{i}, next slice height is zero - breaking out of in-floor loop"
            next_slice_height = slice_height
            break
          end

# SLB: this isn't executed    
          i += 1 # next slice
          in_floor_level += next_slice_height
          z_level += next_slice_height
  
        end # while in floor

# SLB: because break jumps to here


#16

By the way, I wrapped your file in a module I named JWMTest and then everything within that module in a class I named DrawArch. Then after loading the file I do:

da = JWMTest::DrawArch.new    # this implicitly invokes your initialize
da.get_inputs()               # this launches your processing

And it runs just dandy using the debugger!


#17

TIG, Steve: I hadn’t bothered to wrap my code in a module, or a class, since it will only execute standalone on my own machine. However, I suppose with other installed plugins with which it might conflict, it would indeed be better practice to do so, and I shall.

You say (I’m sure rightly!) that the code is ‘poorly formatted’. In what ways could I improve it? I did use the NetBeans IDE to ‘Format code’ to get the indenting regular, but i may have mucked it up since doing that.

Or did you mean ‘poorly structured’ - which it quite likely is!

TIG: you asked “What is it I am trying to do?”

I’m trying to create quarter-elliptical columns and other arched parts of an arched building that Scott Baker (@NewThinking2) is designing, on which I offered to help, out of interest and curiosity.

The overall building looks like this:

A previous version of the program drew one quarter of the arch and the floor levels shown in the image, and later the columns shown in my earlier attachment.

That program drew one face at a time - outer curved face, inner curved face, and side faces. Then drew the floor lines as shown in the image, with their corners exactly on (quarter) elliptical curves.

Optionally, the arch and column faces may slant with a slope of 2 feet in every ten feet.

The building has almost 100 floors, and is 1000’ high and 2000’ overall end to end.

It has variable floor heights, shown in the image above. Most ‘standard height’ floors (variable name std_floor_height) are 10’ high. The lowest floor in line with the centre of the arch 1 is lower - 9’10", floors 2, 33 and 64 are 15’3, and the first floor (87) that spans all the way across the arch is 20’ high. There’s a hand drawn added floor 0, which is just a projection straight down of floor 1.

We wanted it drawn in ‘slices’ which could have a higher resolution than the floor height.

Near the top, the slice height needs to get smaller to preserve the appearance of curvature rather than just a few very long nearly horizontal straight lines.

There’s a notch 15’ deep and 21’ wide on the inner arch, to carry external elevators.

The shape proved impractical to draw ‘by hand’ with native tools, or even plugins, especially to draw the floor perimeters accurately with corners on the elliptical curve. I first tried by stretching a semicircle with 180 segments, and using Fredo Tools Shear to slant the sides and the notch, which gave the overall shape, but not the floor heights.

As I write, I see Steve Baumgartner has posted that he has identified the bug where my code fails to stop as it goes up the building.

But I’d still welcome further suggestions to improve structure and formatting, TIG, and thanks for looking at the code.


#18

Steve, THANK YOU again. I’ve been going nuts for the last couple of days knowing the logic wasn’t right, and too close to it to see it.


#19

Is this what you expected the component to look like?


#20

By the way, for anyone who has been following this and our other thread about NetBeans setup for debugging, I found this error fairly quickly using the debugger!