Author Topic: Crash of PJSR with Numeric control  (Read 4642 times)

Offline georg.viehoever

  • PTeam Member
  • PixInsight Jedi Master
  • ******
  • Posts: 2132
Crash of PJSR with Numeric control
« on: 2009 June 14 05:14:29 »
Hi Juan,

this report is probably related to the issue I described in http://pixinsight.com/forum/index.php?topic=1159.msg6028#msg6028.

Run the attached script (on Windows), move the slider around eratically. Sooner or later, or when you close the window, you get something like
Code: [Select]
processing in slider done
*** PCL Win32 System Exception: At address 00000000 with exception code C0000005 :
Access violation: invalid memory write operation at address 00000000
Dialog done

I often need to reset the PJSR runtime after that to get it working again. I don't get this if I remove the gc() (which is necessary to avoid memory problems in the Canon Banding Script).

A second issue: Enter "q" (or some non numeric string) in the text field, then click on the slider. This terminates the dialog, sometimes causing PCL Win32 System Exceptions as well. This also happens when I remove the gc() statement.

Georg

Code: [Select]
#include <pjsr/NumericControl.jsh>
function MyDialog() {
   this.__base__ = Dialog;
   this.__base__();

   this.amountControl=new NumericControl(this);
    with (this.amountControl) {
      label.text = "Amount:";
      setRange( 0, 4.0 );
      slider.setRange( 0, 1000 );
      slider.minWidth = 250;
      setPrecision( 2 );
      setValue( 1.0);
      toolTip = "Define amount of correction";
      onValueUpdated = function( value ) {
         console.writeln("processing in slider, amount=",value);
         for(var i=0;i<100;++i){
            gc();
         }
         console.writeln("processing in slider done");
         return;
      }; //function onValueUpdated();
   }  //with amountControl

   this.windowTitle = "TestWindow";
   this.adjustToContents();
}  //class MyDialog
MyDialog.prototype = new Dialog;


function main() {
   console.show();
   console.writeln("Script started");
   var dialog = new MyDialog();
   dialog.execute();
   console.writeln("Dialog done");
   console.hide();
}
main();
Georg (6 inch Newton, unmodified Canon EOS40D+80D, unguided EQ5 mount)

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: Crash of PJSR with Numeric control
« Reply #1 on: 2009 June 17 10:46:10 »
Hi Georg,

I have confirmed this bug. The problem happens when gc() is called from a NumericControl.onValueUpdated event handler. In this case, garbage collection is causing some data corruption that I still have to identify.

NumericControl is an aggregate control object implemented as JavaScript code (pjsr/NumericControl.jsh). Native control objects seem to not have this problem. For example, this script works without problems:

Code: [Select]
function MyDialog()
{
   this.__base__ = Dialog;
   this.__base__();

   this.spinControl = new SpinBox( this );
   this.spinControl.onValueUpdated = function( value )
   {
      console.writeln( "processing in SpinBox, amount=", value );
      gc();
      console.writeln( "processing in SpinBox done" );
   };
}

MyDialog.prototype = new Dialog;

function main()
{
   console.show();
   console.writeln( "Script started" );
   var dialog = new MyDialog();
   dialog.execute();
   console.writeln( "Dialog done" );
}

main();

The workaround is evident: don't call gc() from an event handler of the NumericControl (or NumericEdit) object. For now, I have no other solution, since calling gc() anywhere in the "path" of a NumericControl event leads to crash. The following script demonstrates this:

Code: [Select]
#include <pjsr/NumericControl.jsh>

function MyDialog()
{
   this.__base__ = Dialog;
   this.__base__();

   this.filterRadius = 0;

   this.imgControl = new Control( this );
   with( this.imgControl )
   {
      setMinSize( 400, 400 );
      onPaint = function()
      {
         var length = 1 + (this.parent.filterRadius << 1);
         var size = length*length;
         var filter = new Array( size );
         for ( var i = 0; i < size; ++i )
            filter[i] = 1;

         var img = new Image;
         img.assign( ImageWindow.activeWindow.mainView.image );
         if ( length >= 3 )
            if ( length <= 15 )
               img.convolve( filter );
            else
               img.convolveFFT( filter );

         var G = new Graphics( this );
         G.drawScaledBitmap( this.boundsRect, img.render() );
         G.end();

         //console.writeln( gcBytes() ); // new in PI 1.5.3: returns the number of gc()-able bytes

         //gc();  // ### Removing leading comment leads to a crash
      };
   }

   this.sizeControl = new NumericControl( this );
   with ( this.sizeControl )
   {
      real = false;
      setRange( 0, 150 );
      label.text = "Filter radius:";
      slider.setRange( 0, 150 );
      slider.minWidth = 300;
      setValue( this.filterRadius );
      toolTip = "<p>Define the radius of a box averaging filter.</p>";
      onValueUpdated = function( value )
      {
         this.parent.filterRadius = value;
         this.parent.imgControl.update();
      };
   }

   this.sizer = new VerticalSizer;
   this.sizer.margin = 6;
   this.sizer.spacing = 6;
   this.sizer.add( this.imgControl, 100 );
   this.sizer.add( this.sizeControl );

   this.windowTitle = "TestWindow";
   this.adjustToContents();
}

MyDialog.prototype = new Dialog;

function main()
{
   console.show();
   console.writeln( "Script started" );
   var dialog = new MyDialog();
   dialog.execute();
   console.writeln( "Dialog done" );
   console.hide();
}

main();

By the way, the above script can also be useful for your task.

In PI 1.5.3 I'll implement an automatic, asynchronous garbage collection feature. The idea is having a global variable like this:

Code: [Select]
autoGCInterval = 100;
The above sentence enables automatic garbage collection at 100 ms intervals. By default, the value of autoGCInterval will be zero, which means that no automatic garbage collection takes place. I think this should fix all memory problems with the PJSR.

Thank you for pushing things to the limit, and sorry for the inconveniences.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline georg.viehoever

  • PTeam Member
  • PixInsight Jedi Master
  • ******
  • Posts: 2132
Re: Crash of PJSR with Numeric control
« Reply #2 on: 2009 June 17 12:03:01 »
Juan,

Thanks for investigating this issue.
- will the asynchronous garbage collection feature resolve the issue for NumericControl if I dont call gc() inside the event handler? Or is gc() called at undefined times causing similar issues if it just happens at the same time as an event handler?
- Any new projections for the 1.5.3 release date?

Thanks for your amazing work!

Georg
Georg (6 inch Newton, unmodified Canon EOS40D+80D, unguided EQ5 mount)

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: Crash of PJSR with Numeric control
« Reply #3 on: 2009 June 18 16:56:45 »
Hi Georg, and all PJSR developers,

I have extremely good news :)

All garbage collection problems have been fixed. Simplifying, the problem was that SpiderMonkey's garbage collector was incorrectly collecting event handlers (which are Function objects and hence are subject to garbage collection). Unexpected destruction of event handlers was causing severe corruption of internal data structures, especially if the collector was invoked in response to an event (directly or indirectly). This is the reason why calling gc() from an onValueUpdated handler (or from other event handler indirectly invoked from onValueUpdated) was crashing.

The cause of these errors is that I wasn't rooting event handler objects well. A root object in the JavaScript engine means that the garbage collector will not collect it, nor any object depending on it. Since event handlers aren't children (methods) of any particular object, they need explicit rooting to prevent their accidental destruction. For example, in the following snippet:

Code: [Select]
function MyDialog
{
   // ...
   this.mySlider = new Slider( this );
   with ( this.mySlider )
   {
      onValueUpdated = function( value )
      {
         // ...
      };
   }
}

this.mySlider.onValueUpdated is an unrooted Function object. It is initially assigned to the onValueUpdated property of this.mySlider, but the JavaScript engine thinks that once it has been assigned, it is no longer used since there is no explicit call to it, and hence it is susceptible of garbage collection as soon as the script begins execution.

Now all event handler functions are automatically rooted by the PJSR upon creation, and unrooted once the script terminates execution, just before calling the garbage collector to clean up the terminated script. This has fixed the problem definitely.

PixInsight version 1.5.3 adds a number of important new routines and properties to the PJSR. Among them:

Code: [Select]
Boolean Global.jsAbortable
This property is false by default. When a script sets it to true, the script becomes abortable, that is, the user can interrupt its execution by clicking the Pause/Abort button on the Processing Console. For this option to work, the script must be running without an active modal dialog, since modal windows prevent interaction with other elements of the GUI. This option is good for debugging scripts that can enter infinite loops and the like.

Code: [Select]
Boolean Global.jsAutoGC
This property is false by default. When a script sets it to true, PixInsight enables an automatic, asynchronous garbage collection routine. With this option enabled, a script doesn't need to worry about explicit garbage collection because the PJSR performs it behind the scenes. The frequency of garbage collection attempts is proportional to the complexity of the running script. Asynchronous garbage collection has a very small though noticeable impact on execution performance (this is the reason why it is disabled by default).

With the new features and modifications, the PJSR is now extremely stable and doesn't have the old memory problems anymore. Real-time tasks are now fully supported in the PJSR, which is an important step forward.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline georg.viehoever

  • PTeam Member
  • PixInsight Jedi Master
  • ******
  • Posts: 2132
Re: Crash of PJSR with Numeric control
« Reply #4 on: 2009 June 18 23:18:46 »
Wow, this just sounds like a great leap forward! I cannot wait to see 1.5.3!

Fanatastic!

Georg
Georg (6 inch Newton, unmodified Canon EOS40D+80D, unguided EQ5 mount)