New versions of StarAlignment and ImageIntegration

Juan Conejero

PixInsight Staff
Sep 2, 2004
Valencia, Spain
Hi all,

Yesterday I released updates for the ImageRegistration and ImageIntegration modules (new versions and, respectively). These updates provide important performance improvements for the StarAlignment and ImageIntegration tools by way of high-level parallelization, which I'm going to describe briefly in this post.


As you surely know, most PixInsight tools and algorithm implementations are strongly parallelized to make use of modern multicore processors. Many tools benefit easily and largely from parallel processing. For example, a tool like CurvesTransformation implements what we know as embarrassingly parallel algorithm in the programming jargon. Similar examples are HistogramTransformation, Resample and Convolution, among many others. All of these tools basically divide the image into chunks of pixels and process each chunk separately with a dedicated processor core. Since most of these tools write to individual pixels without any thread contention, parallelization can be very efficient in these cases.

The following graph plots instantaneous CPU load measurements for each processor core as a function of execution time in seconds, during an execution of the Resample process to generate a very large image (about 20 GiB). The machine, which I have used for all of the tests presented in this post, is an Intel Xeon E5-2695 v2 @ 2.40GHz (see benchmark) with 24 logical processors and 64 GiB of RAM. This is the main workstation where I carry out most of PixInsight development on Linux and multiple virtual machines. The thick line represents average instantaneous CPU load (the average of 24 core loads).

As you can see, CPU usage is very efficient in this case, with an average load around the 95% during the entire process execution.

However, there are other tasks that either cannot be parallelized, or where parallelization can only provide relatively small improvements. Inherent thread contention and the sequential nature of some algorithms are the main causes for this. Two good examples are MultiscaleLinearTransform and MultiscaleMedianTransform. As you know, these algorithms decompose an image into a set of multiscale layers. However, to compute a given layer, one needs to compute all of the previous ones first. This dependency prevents parallelizing the algorithm as a whole. Many subtasks of MLT and MMT can still be fully parallelized, such as convolutions, morphological transformations, and arithmetic pixel wise operations. Fortunately, the overall complexities of MLT and MMT are dominated by these subtasks, so the current implementations are reasonably efficient. In other cases, parallelization can only provide more modest improvements. For example, the next graph corresponds to an execution of the HDRMultiscaleTransform process.

The HDRMT algorithm cannot be parallelized at a high level. HDRMT computes wavelet transforms to generate succesive HDRMT components, but significant parts of the algorithm have to be executed sequentially. As you can see, the impact of this limitation on the use of CPU resources is significant.

High-Level Parallelization

In the case of StarAlignment, only a few subtasks can be parallelized efficiently. RANSAC can be executed concurrently to increase the probability of finding a valid solution. Some steps of the point matching algorithms, but not all of them, can also be parallelized, and the final pixel interpolation task is a purely parallel task. However, star detection basically cannot be parallelized. In summary, the StarAlignment process does not benefit as much as we'd like from parallel execution. Considering that this process is a crucial element of preprocessing, it has been one of the main performance bottlenecks in our preprocessing pipelines.

In the next graph we see CPU usage during execution of a StarAlignment instance to register 75 16-Mpx calibrated CCD images in a batch operation. This is the version of SA that we have been using before the latest update.

CPU resources are being fully used only during brief intervals. As is obvious from the graph, the result is quite poor because the average load is very low. This happens because for batch registration of image files, we have been applying StarAlignment sequentially. This is no longer the case with the new version. When two or more registration targets are disk files, StarAlignment processes all of them concurrently using all logical processors available. This is what we call high-level parallelization. Using the same data set as in the previous graph (75 x 16 Mpx images), the CPU usage graph can be seen below.

Thanks to a much more efficient usage of the available resources, StarAlignment is now three times faster in this test. It has also good scalability: for sufficiently large data sets, the achieved performance improvements should increase linearly with the number of logical processors available.

The case of ImageIntegration is quite different. The normalization, rejection and integration subtasks have been parallelized since the first versions of the tool, with excellent performance. These subtasks have only been optimized slightly in the new version. However, the initial statistics calculation stage has been rather pathetic up until now, as the following graph shows clearly.

With high-level parallelization of the statistics calculation phase, the improvement is spectacular:

The initial low CPU usage is caused by the reference integration image, which must be analyzed before the rest of the data set. The CPU load decrements during the initial phase are better understood if we analyze the graphs of I/O wait states and normalized RAM usage:

In this test all of the input data were stored in a solid state disk drive (Samsung SSD EVO 840 1TB). It is interesting to compare these graphs with the same test performed on rotational disks (2 x HGST Ultrastar 7K4000 4TB RAID 1):

These graphs describe quite nicely the performance difference between SDDs and rotational disks. I/O wait states can be understood as wasted time in terms of processing performance: Since the running tasks depend on the input data, the running threads necessarily have to wait until the data have been loaded from disk files and stored in RAM. A rotational disk forces much longer I/O wait states involving more processor cores, which degrades performance considerably.

Finally, the relatively low CPU usage during the normalization/rejection/integration phases, around an 80%, is due to a locality of reference issue caused by the complex data structures required to implement these tasks. This shows some room for future improvements, although not as relevant as the ones implemented in this update.


With these updates, some important facts and conclusions must be pointed out:

- The new versions of StarAlignment and ImageIntegration run 3-4 times faster in intensive tests, providing much better scalability than previous versions. This solves some critical performance bottlenecks that we have been suffering in our preprocessing pipelines.

- With the new versions, fast I/O hardware is critical. The use of SSD disks or M.2 SDDs is highly recommended.

- With high-level parallelization, more RAM is always necessary. This is because logical processors now load image disk files concurrently.

- Unlike previous versions of these tools, increasing the number of processor cores will improve performance almost linearly.

- Users should realize that a powerful workstation is an important part of their equipment, as important as a good camera or a good telescope. With the large amounts of data acquired with modern instruments, one needs to have enough processing power to manage the data efficiently.

Next Steps

For monochrome CCD users, I think our batch preprocessing pipelines are now reasonably efficient, with relatively small room for improvement on the current platform.

For OSC and DSLR camera users, an important performance bottleneck still remains: the Debayer process. Since Debayer processes images sequentially and implements noise evaluation, which cannot be parallelized, it can be quite slow. So one of my next priorities is to rewrite this process to implement batch debayering of disk files with high-level parallelization. ? Note: This has already been implemented in current 1.8.x versions of PixInsight (since 2018).

For the StarAlignment tool, I am working on a completely new local distortion correction algorithm, much more versatile, efficient and accurate. Hopefully this will be an important improvement for mosaic construction and registration of wide field images, as well as images acquired with different instruments. ? Note: A new arbitrary distortion correction algorithm has already been implemented in the StarAlignment tool in current 1.8.x versions of PixInsight (since 2019).

For ImageIntegration, we have new pixel rejection algorithms on the drawing board, including some multiscale rejection techniques. ? Note: These algorithms have already been implemented in current 1.8.x versions of PixInsight (since 2018/2019).

Employed Analysis Tools

For those of you interested in knowing how things are being done, I have generated all of the graphs shown in this post with the following script:

 * SystemMonitor - A script to monitor CPU and memory usage while a process
 * instance is running in PixInsight.
 * The script generates three graphics in SVG format:
 * - cpu-load-usr.svg
 *    The instantaneous CPU load in user mode vs. execution time (including
 *    both normal and niced processes).
 * - cpu-load-iowait.svg
 *    The instantaneous CPU load wasted while waiting for I/O operations to
 *    complete, vs. execution time.
 * - mem-usage.svg
 *    The instantaneous, normalized memory usage vs. execution time. A value of
 *    1.0 means that all of the available memory is being used. This value only
 *    measures RAM usage, excluding swap storage.
 * The script makes use of the /proc filesystem on Linux, including /proc/stat
 * and proc/meminfo. For detailed information on these files and their meaning,
 * see the following sources:
 * Other specific references and resources are specified in the source code.
 * This script only runs on the reference Linux implementation of PixInsight.
 * Written by Juan Conejero, PTeam.
 * December 2016.

#error This script can only be used on Linux.

#define SAMPLING_INTERVAL        0.5   // seconds
#define GRAPH_WIDTH              4000
#define GRAPH_HEIGHT             1000
#define GRAPH_TICK_SIZE          16
#define GRAPH_TEXT_SIZE          28
#define GRAPH_MARGIN             40
#define GRAPH_FONT               "Helvetica"
#define GRAPH_THIN_LINE_WIDTH    1.0
#define GRAPH_OPEN_WINDOW        true
#define GRAPH_OUTPUT_DIR         "/tmp"

function CPUMonitor()
   this.updateTimer = new Timer;
   this.updateTimer.interval = SAMPLING_INTERVAL;
   this.updateTimer.periodic = true;
   this.updateTimer.parent = this;
   this.updateTimer.onTimeout = function()

   this.start = function()
      this.count = 0;
      this.time = [];
      this.cpus = [];
      this.memUsed = [];
      this.memTotal = this.rawMemTotal();
      this.elapsedTime = new ElapsedTime;

   this.stop = function()
      this.totalTime = this.elapsedTime.value;

   this.plot = function()
      let P = new this.Plotter( this );
      P.plotCPU( "usr" );
      P.plotCPU( "iowait" );

   this.update = function()
      let r = this.rawCPULoad();
      if ( this.count > 0 )
         let v = { usr:[], iowait:[] };
         for ( let i = 0; i < r.usr.length; ++i )
            let du = Math.max( 0, r.usr[i] - this.last.usr[i] );
            let dw = Math.max( 0, r.iowait[i] - this.last.iowait[i] );
            let dt =[i] -[i];
            if ( dt > 0 )
               du /= dt, dw /= dt;
            v.usr.push( du );
            v.iowait.push( dw );
         this.cpus.push( v );
      this.last = r;
      this.time.push( this.elapsedTime.value );
      this.memUsed.push( (this.memTotal - this.rawMemFree())/this.memTotal );

    * Extract raw CPU load statistics from /proc/stat on Linux:
   this.rawCPULoad = function()
      let r = { usr:[], iowait:[], total:[] };
      let P = new ExternalProcess( "cat /proc/stat" );
      if ( P.exitCode == 0 )
         let t = P.stdout.utf8ToString();
         let l = t.split( '\n' );
         for ( let i = 0, found = false; i < l.length; ++i )
            if ( l[i].startsWith( "cpu" ) )
               found = true;
               if ( l[i][3] != ' ' )
                  let k = l[i].split( ' ' );
                  r.usr.push( parseFloat( k[1] ) + parseFloat( k[2] ) ); // usr+nice
                  r.iowait.push( parseFloat( k[5] ) );
                  let s = 0;
                  for ( let j = 1; j <= 10; ++j )
                     s += parseFloat( k[j] );
         s );
            else if ( found )
      return r;

    * Extract total amount of memory available from /proc/meminfo on Linux:
   this.rawMemTotal = function()
      let P = new ExternalProcess( "cat /proc/meminfo" );
      if ( P.exitCode == 0 )
         let t = P.stdout.utf8ToString();
         let p = t.indexOf( "MemTotal:" );
         if ( p >= 0 )
            let q = t.indexOf( '\n', p+10 );
            if ( q >= 0 )
               return parseFloat( t.substring( p+10, q-3 ) );
      return 0;

    * Extract the amount of free memory from /proc/meminfo on Linux:
   this.rawMemFree = function()
      let P = new ExternalProcess( "cat /proc/meminfo" );
      if ( P.exitCode == 0 )
         let t = P.stdout.utf8ToString();
         let p = t.indexOf( "MemFree:" );
         if ( p >= 0 )
            let q = t.indexOf( '\n', p+10 );
            if ( q >= 0 )
               return parseFloat( t.substring( p+10, q-3 ) );
      return 0;

   this.Plotter = function( parent, width, height, tickSize, textSize, margin )
      this.parent = parent;

      if ( width == undefined )
         this.width = GRAPH_WIDTH;
         this.width = width;

      if ( height == undefined )
         this.height = GRAPH_HEIGHT;
         this.height = height;

      if ( tickSize == undefined )
         this.tickSize = GRAPH_TICK_SIZE;
         this.tickSize = tickSize;

      if ( textSize == undefined )
         this.textSize = GRAPH_TEXT_SIZE;
         this.textSize = textSize;

      if ( margin == undefined )
         this.margin = GRAPH_MARGIN;
         this.margin = margin;

      this.font = new Font( GRAPH_FONT );
      this.font.pixelSize = this.textSize;

      this.labelHeight = this.font.tightBoundingRect( "123" ).height;
      this.labelSeparation = this.font.width( '-' );
      this.xLabelHeight = this.labelHeight + this.labelSeparation;
      this.yLabelWidth = this.font.width( "1.0" ) + this.labelSeparation;

      this.rect = new Rect( this.margin + this.yLabelWidth + this.tickSize,
                            this.margin + 2*this.tickSize,
                            this.width  - this.margin - this.tickSize,
                            this.height - this.margin - this.xLabelHeight - 2*this.tickSize );

      this.dx = (this.rect.width - 2)/this.parent.totalTime;

      this.plotCPU = function( item )
         let svg = new SVG( GRAPH_OUTPUT_DIR + "/cpu-load-" + item + ".svg", this.width, this.height );
         svg.viewBox = new Rect( this.width, this.height );
         let G = new VectorGraphics( svg );
         G.antialiasing = true;
         this.drawBox( G );
         this.drawCPU( item, G );
         if ( GRAPH_OPEN_WINDOW )
            this.openWindow( svg.filePath );

      this.plotMem = function()
         let svg = new SVG( GRAPH_OUTPUT_DIR + "/mem-usage.svg", this.width, this.height );
         svg.viewBox = new Rect( this.width, this.height );
         let G = new VectorGraphics( svg );
         G.antialiasing = true;
         let yMax = this.memYMax();
         this.drawBox( G, yMax );
         this.drawMem( G, yMax );
         if ( GRAPH_OPEN_WINDOW )
            this.openWindow( svg.filePath );

      this.openWindow = function( filePath )
         let window = filePath )[0];;

      this.memYMax = function()
         let peak = Math.maxElem( this.parent.memUsed );
         return Math.min( (Math.trunc( peak*10 ) + 1)/10, 1.0 );

      this.drawBox = function( G, yMax )
         if ( yMax == undefined )
            yMax = 1.0;

         G.pen = new Pen( 0xff000000, GRAPH_THIN_LINE_WIDTH );
         G.font = this.font;
         G.drawRect( this.rect );

         // X-axis ticks
         for ( let i = 0; i <= this.parent.totalTime; ++i )
            let x = this.rect.x0 + 1 + i*this.dx;
            if ( i % 10 == 0 )
               G.drawLine( x, this.rect.y0 - 2*this.tickSize, x, this.rect.y0 );
               G.drawLine( x, this.rect.y1, x, this.rect.y1 + 2*this.tickSize );
               G.drawText( x - this.labelHeight/2, this.height-this.margin, format( "%d", i ) );
               G.drawLine( x, this.rect.y0 - this.tickSize, x, this.rect.y0 );
               G.drawLine( x, this.rect.y1, x, this.rect.y1 + this.tickSize );

         // Y-axis ticks
         for ( let i = 0, n = Math.round( yMax/0.1 ); i <= n; ++i )
            let f = i*0.1;
            let y = this.rect.y1 - 1 - f*(this.rect.height - 2)/yMax;
            G.drawLine( this.rect.x0 - this.tickSize, y, this.rect.x0, y );
            G.drawLine( this.rect.x1, y, this.rect.x1 + this.tickSize, y );
            G.drawText( this.rect.x0 - this.tickSize - this.yLabelWidth, y + this.labelHeight/2, format( "%.1f", f ) );

      this.drawCPU = function( item, G )
         // CPU load plots
         for ( let i = 0; i < this.parent.cpus[0][item].length; ++i )
            let cpuLines = [];
            for ( let j = 0; j < this.parent.cpus.length; ++j )
               cpuLines.push( new Point( this.rect.x0 + 1 + this.parent.time[j]*this.dx,
                     this.rect.y1 - 1 - (this.rect.height - 2)*this.parent.cpus[j][item][i] ) );
            G.pen = new Pen( this.colors[i], GRAPH_THIN_LINE_WIDTH );
            G.drawPolyline( cpuLines );

         // Average load plot
         let avgLines = [];
         for ( let i = 0; i < this.parent.cpus.length; ++i )
            let totalLoad = 0;
            for ( let j = 0; j < this.parent.cpus[i][item].length; ++j )
               totalLoad += this.parent.cpus[i][item][j];
            avgLines.push( new Point( this.rect.x0 + 1 + this.parent.time[i]*this.dx,
                  this.rect.y1 - 1 - (this.rect.height - 2)*totalLoad/this.parent.cpus[i][item].length ) );
         G.pen = new Pen( 0x60000000, GRAPH_THICK_LINE_WIDTH );
         G.drawPolyline( avgLines );

      this.drawMem = function( G, yMax )
         // Free memory plot
         let memLines = [];
         for ( let i = 0; i < this.parent.memUsed.length; ++i )
            memLines.push( new Point( this.rect.x0 + 1 + this.parent.time[i]*this.dx,
                  this.rect.y1 - 1 - (this.rect.height - 2)*this.parent.memUsed[i]/yMax ) );
         G.pen = new Pen( 0xFF000000, GRAPH_THIN_LINE_WIDTH );
         G.drawPolyline( memLines );

       * A list of distinct colors which are maximally dissimilar from all
       * previous colors:
       * I have commented out a few colors that are difficult to see on a white
       * background.
      this.colors = [
         0xFF000000, /*0xFFFFFF00,*/ 0xFF1CE6FF, 0xFFFF34FF, 0xFFFF4A46, 0xFF008941, 0xFF006FA6, 0xFFA30059,
         0xFFFFDBE5, 0xFF7A4900, 0xFF0000A6, 0xFF63FFAC, 0xFFB79762, 0xFF004D43, 0xFF8FB0FF, 0xFF997D87,
         0xFF5A0007, 0xFF809693, /*0xFFFEFFE6,*/ 0xFF1B4400, 0xFF4FC601, 0xFF3B5DFF, 0xFF4A3B53, 0xFFFF2F80,
         0xFF61615A, 0xFFBA0900, 0xFF6B7900, 0xFF00C2A0, 0xFFFFAA92, 0xFFFF90C9, 0xFFB903AA, 0xFFD16100,
         /*0xFFDDEFFF,*/ 0xFF000035, 0xFF7B4F4B, 0xFFA1C299, 0xFF300018, 0xFF0AA6D8, 0xFF013349, 0xFF00846F,
         0xFF372101, 0xFFFFB500, 0xFFC2FFED, 0xFFA079BF, 0xFFCC0744, 0xFFC0B9B2, 0xFFC2FF99, 0xFF001E09,
         0xFF00489C, 0xFF6F0062, 0xFF0CBD66, 0xFFEEC3FF, 0xFF456D75, 0xFFB77B68, 0xFF7A87A1, 0xFF788D66,
         0xFF885578, 0xFFFAD09F, 0xFFFF8A9A, 0xFFD157A0, 0xFFBEC459, 0xFF456648, 0xFF0086ED, 0xFF886F4C,
         0xFF34362D, 0xFFB4A8BD, 0xFF00A6AA, 0xFF452C2C, 0xFF636375, 0xFFA3C8C9, 0xFFFF913F, 0xFF938A81,
         0xFF575329, 0xFF00FECF, 0xFFB05B6F, 0xFF8CD0FF, 0xFF3B9700, 0xFF04F757, 0xFFC8A1A1, 0xFF1E6E00,
         0xFF7900D7, 0xFFA77500, 0xFF6367A9, 0xFFA05837, 0xFF6B002C, 0xFF772600, 0xFFD790FF, 0xFF9B9700,
         0xFF549E79, 0xFFFFF69F, 0xFF201625, 0xFF72418F, 0xFFBC23FF, 0xFF99ADC0, 0xFF3A2465, 0xFF922329,
         0xFF5B4534, 0xFFFDE8DC, 0xFF404E55, 0xFF0089A3, 0xFFCB7E98, 0xFFA4E804, 0xFF324E72, 0xFF6A3A4C,
         0xFF83AB58, 0xFF001C1E, 0xFFD1F7CE, 0xFF004B28, 0xFFC8D0F6, 0xFFA3A489, 0xFF806C66, 0xFF222800,
         0xFFBF5650, 0xFFE83000, 0xFF66796D, 0xFFDA007C, 0xFFFF1A59, 0xFF8ADBB4, 0xFF1E0200, 0xFF5B4E51,
         0xFFC895C5, 0xFF320033, 0xFFFF6832, 0xFF66E1D3, 0xFFCFCDAC, 0xFFD0AC94, 0xFF7ED379, 0xFF012C58,
         0xFF7A7BFF, 0xFFD68E01, 0xFF353339, 0xFF78AFA1, 0xFFFEB2C6, 0xFF75797C, 0xFF837393, 0xFF943A4D,
         0xFFB5F4FF, 0xFFD2DCD5, 0xFF9556BD, 0xFF6A714A, 0xFF001325, 0xFF02525F, 0xFF0AA3F7, 0xFFE98176,
         0xFFDBD5DD, 0xFF5EBCD1, 0xFF3D4F44, 0xFF7E6405, 0xFF02684E, 0xFF962B75, 0xFF8D8546, 0xFF9695C5,
         0xFFE773CE, 0xFFD86A78, 0xFF3E89BE, 0xFFCA834E, 0xFF518A87, 0xFF5B113C, 0xFF55813B, 0xFFE704C4,
         0xFF00005F, 0xFFA97399, 0xFF4B8160, 0xFF59738A, 0xFFFF5DA7, 0xFFF7C9BF, 0xFF643127, 0xFF513A01,
         0xFF6B94AA, 0xFF51A058, 0xFFA45B02, 0xFF1D1702, 0xFFE20027, 0xFFE7AB63, 0xFF4C6001, 0xFF9C6966,
         0xFF64547B, 0xFF97979E, 0xFF006A66, 0xFF391406, 0xFFF4D749, 0xFF0045D2, 0xFF006C31, 0xFFDDB6D0,
         0xFF7C6571, 0xFF9FB2A4, 0xFF00D891, 0xFF15A08A, 0xFFBC65E9, /*0xFFFFFFFE,*/ 0xFFC6DC99, 0xFF203B3C,
         0xFF671190, 0xFF6B3A64, 0xFFF5E1FF, 0xFFFFA0F2, 0xFFCCAA35, 0xFF374527, 0xFF8BB400, 0xFF797868,
         0xFFC6005A, 0xFF3B000A, 0xFFC86240, 0xFF29607C, 0xFF402334, 0xFF7D5A44, 0xFFCCB87C, 0xFFB88183,
         0xFFAA5199, 0xFFB5D6C3, 0xFFA38469, 0xFF9F94F0, 0xFFA74571, 0xFFB894A6, 0xFF71BB8C, 0xFF00B433,
         0xFF789EC9, 0xFF6D80BA, 0xFF953F00, 0xFF5EFF03, 0xFFE4FFFC, 0xFF1BE177, 0xFFBCB1E5, 0xFF76912F,
         0xFF003109, 0xFF0060CD, 0xFFD20096, 0xFF895563, 0xFF29201D, 0xFF5B3213, 0xFFA76F42, 0xFF89412E,
         0xFF1A3A2A, 0xFF494B5A, 0xFFA88C85, 0xFFF4ABAA, 0xFFA3F3AB, 0xFF00C6C8, 0xFFEA8B66, 0xFF958A9F,
         0xFFBDC9D2, 0xFF9FA064, 0xFFBE4700, 0xFF658188, 0xFF83A485, 0xFF453C23, 0xFF47675D, 0xFF3A3F00,
         0xFF061203, 0xFFDFFB71, 0xFF868E7E, 0xFF98D058, 0xFF6C8F7D, 0xFFD7BFC2, 0xFF3C3E6E, 0xFFD83D66,
         0xFF2F5D9B, 0xFF6C5E46, 0xFFD25B88, 0xFF5B656C, 0xFF00B57F, 0xFF545C46, 0xFF866097, 0xFF365D25,
         0xFF252F99, 0xFF00CCFF, 0xFF674E60, 0xFFFC009C, 0xFF92896B, 0xFF1E2324, 0xFFDEC9B2, 0xFF9D4948,
         0xFF85ABB4, 0xFF342142, 0xFFD09685, 0xFFA4ACAC, 0xFF00FFFF, 0xFFAE9C86, 0xFF742A33, 0xFF0E72C5,
         0xFFAFD8EC, 0xFFC064B9, 0xFF91028C, 0xFFFEEDBF, 0xFFFFB789, 0xFF9CB8E4, 0xFFAFFFD1, 0xFF2A364C,
         0xFF4F4A43, 0xFF647095, 0xFF34BBFF, 0xFF807781, 0xFF920003, 0xFFB3A5A7, 0xFF018615, 0xFFF1FFC8,
         0xFF976F5C, 0xFFFF3BC1, 0xFFFF5F6B, 0xFF077D84, 0xFFF56D93, 0xFF5771DA, 0xFF4E1E2A, 0xFF830055,
         0xFF02D346, 0xFFBE452D, 0xFF00905E, 0xFFBE0028, 0xFF6E96E3, 0xFF007699, 0xFFFEC96D, 0xFF9C6A7D,
         0xFF3FA1B8, 0xFF893DE3, 0xFF79B4D6, 0xFF7FD4D9, 0xFF6751BB, 0xFFB28D2D, 0xFFE27A05, 0xFFDD9CB8,
         0xFFAABC7A, 0xFF980034, 0xFF561A02, 0xFF8F7F00, 0xFF635000, 0xFFCD7DAE, 0xFF8A5E2D, 0xFFFFB3E1,
         0xFF6B6466, 0xFFC6D300, 0xFF0100E2, 0xFF88EC69, 0xFF8FCCBE, 0xFF21001C, 0xFF511F4D, 0xFFE3F6E3,
         0xFFFF8EB1, 0xFF6B4F29, 0xFFA37F46, 0xFF6A5950, 0xFF1F2A1A, 0xFF04784D, 0xFF101835, 0xFFE6E0D0,
         0xFFFF74FE, 0xFF00A45F, 0xFF8F5DF8, 0xFF4B0059, 0xFF412F23, 0xFFD8939E, 0xFFDB9D72, 0xFF604143,
         0xFFB5BACE, 0xFF989EB7, 0xFFD2C4DB, 0xFFA587AF, 0xFF77D796, 0xFF7F8C94, 0xFFFF9B03, 0xFF555196,
         0xFF31DDAE, 0xFF74B671, 0xFF802647, 0xFF2A373F, 0xFF014A68, 0xFF696628, 0xFF4C7B6D, 0xFF002C27,
         0xFF7A4522, 0xFF3B5859, 0xFFE5D381, /*0xFFFFF3FF,*/ 0xFF679FA0, 0xFF261300, 0xFF2C5742, 0xFF9131AF,
         0xFFAF5D88, 0xFFC7706A, 0xFF61AB1F, 0xFF8CF2D4, 0xFFC5D9B8, 0xFF9FFFFB, 0xFFBF45CC, 0xFF493941,
         0xFF863B60, 0xFFB90076, 0xFF003177, 0xFFC582D2, 0xFFC1B394, 0xFF602B70, 0xFF887868, 0xFFBABFB0,
         0xFF030012, 0xFFD1ACFE, 0xFF7FDEFE, 0xFF4B5C71, 0xFFA3A097, 0xFFE66D53, 0xFF637B5D, 0xFF92BEA5,
         0xFF00F8B3, 0xFFBEDDFF, 0xFF3DB5A7, 0xFFDD3248, 0xFFB6E4DE, 0xFF427745, 0xFF598C5A, 0xFFB94C59,
         0xFF8181D5, 0xFF94888B, 0xFFFED6BD, 0xFF536D31, 0xFF6EFF92, 0xFFE4E8FF, 0xFF20E200, 0xFFFFD0F2,
         0xFF4C83A1, 0xFFBD7322, 0xFF915C4E, 0xFF8C4787, 0xFF025117, 0xFFA2AA45, 0xFF2D1B21, 0xFFA9DDB0,
         0xFFFF4F78, 0xFF528500, 0xFF009A2E, 0xFF17FCE4, 0xFF71555A, 0xFF525D82, 0xFF00195A, 0xFF967874,
         0xFF555558, 0xFF0B212C, 0xFF1E202B, 0xFFEFBFC4, 0xFF6F9755, 0xFF6F7586, 0xFF501D1D, 0xFF372D00,
         0xFF741D16, 0xFF5EB393, 0xFFB5B400, 0xFFDD4A38, 0xFF363DFF, 0xFFAD6552, 0xFF6635AF, 0xFF836BBA,
         0xFF98AA7F, 0xFF464836, 0xFF322C3E, 0xFF7CB9BA, 0xFF5B6965, 0xFF707D3D, 0xFF7A001D, 0xFF6E4636,
         0xFF443A38, 0xFFAE81FF, 0xFF489079, 0xFF897334, 0xFF009087, 0xFFDA713C, 0xFF361618, 0xFFFF6F01,
         0xFF006679, 0xFF370E77, 0xFF4B3A83, 0xFFC9E2E6, 0xFFC44170, 0xFFFF4526, 0xFF73BE54, 0xFFC4DF72,
         0xFFADFF60, 0xFF00447D, 0xFFDCCEC9, 0xFFBD9479, 0xFF656E5B, 0xFFEC5200, 0xFFFF6EC2, 0xFF7A617E,
         0xFFDDAEA2, 0xFF77837F, 0xFFA53327, 0xFF608EFF, 0xFFB599D7, 0xFFA50149, 0xFF4E0025, 0xFFC9B1A9,
         0xFF03919A, 0xFF1B2A25, 0xFFE500F1, 0xFF982E0B, 0xFFB67180, 0xFFE05859, 0xFF006039, 0xFF578F9B,
         0xFF305230, 0xFFCE934C, 0xFFB3C2BE, 0xFFC0BAC0, 0xFFB506D3, 0xFF170C10, 0xFF4C534F, 0xFF224451,
         0xFF3E4141, 0xFF78726D, 0xFFB6602B, 0xFF200441, 0xFFDDB588, 0xFF497200, 0xFFC5AAB6, 0xFF033C61,
         0xFF71B2F5, 0xFFA9E088, 0xFF4979B0, 0xFFA2C3DF, 0xFF784149, 0xFF2D2B17, 0xFF3E0E2F, 0xFF57344C,
         0xFF0091BE, 0xFFE451D1, 0xFF4B4B6A, 0xFF5C011A, 0xFF7C8060, 0xFFFF9491, 0xFF4C325D, 0xFF005C8B,
         0xFFE5FDA4, 0xFF68D1B6, 0xFF032641, 0xFF140023, 0xFF8683A9, 0xFFCFFF00, 0xFFA72C3E, 0xFF34475A,
         0xFFB1BB9A, 0xFFB4A04F, 0xFF8D918E, 0xFFA168A6, 0xFF813D3A, 0xFF425218, 0xFFDA8386, 0xFF776133,
         0xFF563930, 0xFF8498AE, 0xFF90C1D3, 0xFFB5666B, 0xFF9B585E, 0xFF856465, 0xFFAD7C90, 0xFFE2BC00,
         0xFFE3AAE0, 0xFFB2C2FE, 0xFFFD0039, 0xFF009B75, 0xFFFFF46D, 0xFFE87EAC, 0xFFDFE3E6, 0xFF848590,
         0xFFAA9297, 0xFF83A193, 0xFF577977, 0xFF3E7158, 0xFFC64289, 0xFFEA0072, 0xFFC4A8CB, 0xFF55C899,
         0xFFE78FCF, 0xFF004547, 0xFFF6E2E3, 0xFF966716, 0xFF378FDB, 0xFF435E6A, 0xFFDA0004, 0xFF1B000F,
         0xFF5B9C8F, 0xFF6E2B52, 0xFF011115, 0xFFE3E8C4, 0xFFAE3B85, 0xFFEA1CA9, 0xFFFF9E6B, 0xFF457D8B,
         0xFF92678B, 0xFF00CDBB, 0xFF9CCC04, 0xFF002E38, 0xFF96C57F, 0xFFCFF6B4, 0xFF492818, 0xFF766E52,
         0xFF20370E, 0xFFE3D19F, 0xFF2E3C30, 0xFFB2EACE, 0xFFF3BDA4, 0xFFA24E3D, 0xFF976FD9, 0xFF8C9FA8,
         0xFF7C2B73, 0xFF4E5F37, 0xFF5D5462, 0xFF90956F, 0xFF6AA776, 0xFFDBCBF6, 0xFFDA71FF, 0xFF987C95,
         0xFF52323C, 0xFFBB3C42, 0xFF584D39, 0xFF4FC15F, 0xFFA2B9C1, 0xFF79DB21, 0xFF1D5958, 0xFFBD744E,
         0xFF160B00, 0xFF20221A, 0xFF6B8295, 0xFF00E0E4, 0xFF102401, 0xFF1B782A, 0xFFDAA9B5, 0xFFB0415D,
         0xFF859253, 0xFF97A094, 0xFF06E3C4, 0xFF47688C, 0xFF7C6755, 0xFF075C00, 0xFF7560D5, 0xFF7D9F00,
         0xFFC36D96, 0xFF4D913E, 0xFF5F4276, 0xFFFCE4C8, 0xFF303052, 0xFF4F381B, 0xFFE5A532, 0xFF706690,
         0xFFAA9A92, 0xFF237363, 0xFF73013E, 0xFFFF9079, 0xFFA79A74, 0xFF029BDB, 0xFFFF0169, 0xFFC7D2E7,
         0xFFCA8869, 0xFF80FFCD, 0xFFBB1F69, 0xFF90B0AB, 0xFF7D74A9, 0xFFFCC7DB, 0xFF99375B, 0xFF00AB4D,
         0xFFABAED1, 0xFFBE9D91, 0xFFE6E5A7, 0xFF332C22, 0xFFDD587B, 0xFFF5FFF7, 0xFF5D3033, 0xFF6D3800,
         0xFFFF0020, 0xFFB57BB3, 0xFFD7FFE6, 0xFFC535A9, 0xFF260009, 0xFF6A8781, 0xFFA8ABB4, 0xFFD45262,
         0xFF794B61, 0xFF4621B2, 0xFF8DA4DB, 0xFFC7C890, 0xFF6FE9AD, 0xFFA243A7, 0xFFB2B081, 0xFF181B00,
         0xFF286154, 0xFF4CA43B, 0xFF6A9573, 0xFFA8441D, 0xFF5C727B, 0xFF738671, 0xFFD0CFCB, 0xFF897B77,
         0xFF1F3F22, 0xFF4145A7, 0xFFDA9894, 0xFFA1757A, 0xFF63243C, 0xFFADAAFF, 0xFF00CDE2, 0xFFDDBC62,
         0xFF698EB1, 0xFF208462, 0xFF00B7E0, 0xFF614A44, 0xFF9BBB57, 0xFF7A5C54, 0xFF857A50, 0xFF766B7E,
         0xFF014833, 0xFFFF8347, 0xFF7A8EBA, 0xFF274740, 0xFF946444, 0xFFEBD8E6, 0xFF646241, 0xFF373917,
         0xFF6AD450, 0xFF81817B, 0xFFD499E3, 0xFF979440, 0xFF011A12, 0xFF526554, 0xFFB5885C, 0xFFA499A5,
         0xFF03AD89, 0xFFB3008B, 0xFFE3C4B5, 0xFF96531F, 0xFF867175, 0xFF74569E, 0xFF617D9F, 0xFFE70452,
         0xFF067EAF, 0xFFA697B6, 0xFFB787A8, 0xFF9CFF93, 0xFF311D19, 0xFF3A9459, 0xFF6E746E, 0xFFB0C5AE,
         0xFF84EDF7, 0xFFED3488, 0xFF754C78, 0xFF384644, 0xFFC7847B, 0xFF00B6C5, 0xFF7FA670, 0xFFC1AF9E,
         0xFF2A7FFF, 0xFF72A58C, 0xFFFFC07F, 0xFF9DEBDD, 0xFFD97C8E, 0xFF7E7C93, 0xFF62E674, 0xFFB5639E,
         0xFFFFA861, 0xFFC2A580, 0xFF8D9C83, 0xFFB70546, 0xFF372B2E, 0xFF0098FF, 0xFF985975, 0xFF20204C,
         0xFFFF6C60, 0xFF445083, 0xFF8502AA, 0xFF72361F, 0xFF9676A3, 0xFF484449, 0xFFCED6C2, 0xFF3B164A,
         0xFFCCA763, 0xFF2C7F77, 0xFF02227B, 0xFFA37E6F, 0xFFCDE6DC, 0xFFCDFFFB, 0xFFBE811A, 0xFFF77183,
         0xFFEDE6E2, 0xFFCDC6B4, 0xFFFFE09E, 0xFF3A7271, 0xFFFF7B59, 0xFF4E4E01, 0xFF4AC684, 0xFF8BC891,
         0xFFBC8A96, 0xFFCF6353, 0xFFDCDE5C, 0xFF5EAADD, 0xFFF6A0AD, 0xFFE269AA, 0xFFA3DAE4, 0xFF436E83,
         0xFF002E17, 0xFFECFBFF, 0xFFA1C2B6, 0xFF50003F, 0xFF71695B, 0xFF67C4BB, 0xFF536EFF, 0xFF5D5A48,
         0xFF890039, 0xFF969381, 0xFF371521, 0xFF5E4665, 0xFFAA62C3, 0xFF8D6F81, 0xFF2C6135, 0xFF410601,
         0xFF564620, 0xFFE69034, 0xFF6DA6BD, 0xFFE58E56, 0xFFE3A68B, 0xFF48B176, 0xFFD27D67, 0xFFB5B268,
         0xFF7F8427, 0xFFFF84E6, 0xFF435740, 0xFFEAE408, 0xFFF4F5FF, 0xFF325800, 0xFF4B6BA5, 0xFFADCEFF,
         0xFF9B8ACC, 0xFF885138, 0xFF5875C1, 0xFF7E7311, 0xFFFEA5CA, 0xFF9F8B5B, 0xFFA55B54, 0xFF89006A,
         0xFFAF756F, 0xFF2A2000, 0xFF7499A1, 0xFFFFB550, 0xFF00011E, 0xFFD1511C, 0xFF688151, 0xFFBC908A,
         0xFF78C8EB, 0xFF8502FF, 0xFF483D30, 0xFFC42221, 0xFF5EA7FF, 0xFF785715, 0xFF0CEA91, /*0xFFFFFAED,*/
         0xFFB3AF9D, 0xFF3E3D52, 0xFF5A9BC2, 0xFF9C2F90, 0xFF8D5700, 0xFFADD79C, 0xFF00768B, 0xFF337D00,
         0xFFC59700, 0xFF3156DC, 0xFF944575, 0xFFECFFDC, 0xFFD24CB2, 0xFF97703C, 0xFF4C257F, 0xFF9E0366,
         0xFF88FFEC, 0xFFB56481, 0xFF396D2B, 0xFF56735F, 0xFF988376, 0xFF9BB195, 0xFFA9795C, 0xFFE4C5D3,
         0xFF9F4F67, 0xFF1E2B39, 0xFF664327, 0xFFAFCE78, 0xFF322EDF, 0xFF86B487, 0xFFC23000, 0xFFABE86B,
         0xFF96656D, 0xFF250E35, 0xFFA60019, 0xFF0080CF, 0xFFCAEFFF, 0xFF323F61, 0xFFA449DC, 0xFF6A9D3B,
         0xFFFF5AE4, 0xFF636A01, 0xFFD16CDA, 0xFF736060, 0xFFFFBAAD, 0xFFD369B4, 0xFFFFDED6, 0xFF6C6D74,
         0xFF927D5E, 0xFF845D70, 0xFF5B62C1, 0xFF2F4A36, 0xFFE45F35, 0xFFFF3B53, 0xFFAC84DD, 0xFF762988,
         0xFF70EC98, 0xFF408543, 0xFF2C3533, 0xFF2E182D, 0xFF323925, 0xFF19181B, 0xFF2F2E2C, 0xFF023C32,
         0xFF9B9EE2, 0xFF58AFAD, 0xFF5C424D, 0xFF7AC5A6, 0xFF685D75, 0xFFB9BCBD, 0xFF834357, 0xFF1A7B42,
         0xFF2E57AA, 0xFFE55199, 0xFF316E47, 0xFFCD00C5, 0xFF6A004D, 0xFF7FBBEC, 0xFFF35691, 0xFFD7C54A,
         0xFF62ACB7, 0xFFCBA1BC, 0xFFA28A9A, 0xFF6C3F3B, 0xFFFFE47D, 0xFFDCBAE3, 0xFF5F816D, 0xFF3A404A,
         0xFF7DBF32, 0xFFE6ECDC, 0xFF852C19, 0xFF285366, 0xFFB8CB9C, 0xFF0E0D00, 0xFF4B5D56, 0xFF6B543F,
         0xFFE27172, 0xFF0568EC, 0xFF2EB500, 0xFFD21656, 0xFFEFAFFF, 0xFF682021, 0xFF2D2011, 0xFFDA4CFF,
         0xFF70968E, 0xFFFF7B7D, 0xFF4A1930, 0xFFE8C282, 0xFFE7DBBC, 0xFFA68486, 0xFF1F263C, 0xFF36574E,
         0xFF52CE79, 0xFFADAAA9, 0xFF8A9F45, 0xFF6542D2, 0xFF00FB8C, 0xFF5D697B, 0xFFCCD27F, 0xFF94A5A1,
         0xFF790229, 0xFFE383E6, 0xFF7EA4C1, 0xFF4E4452, 0xFF4B2C00, 0xFF620B70, 0xFF314C1E, 0xFF874AA6,
         0xFFE30091, 0xFF66460A, 0xFFEB9A8B, 0xFFEAC3A3, 0xFF98EAB3, 0xFFAB9180, 0xFFB8552F, 0xFF1A2B2F,
         0xFF94DDC5, 0xFF9D8C76, 0xFF9C8333, 0xFF94A9C9, 0xFF392935, 0xFF8C675E, 0xFFCCE93A, 0xFF917100,
         0xFF01400B, 0xFF449896, 0xFF1CA370, 0xFFE08DA7, 0xFF8B4A4E, 0xFF667776, 0xFF4692AD, 0xFF67BDA8,
         0xFF69255C, 0xFFD3BFFF, 0xFF4A5132, 0xFF7E9285, 0xFF77733C, 0xFFE7A0CC, 0xFF51A288, 0xFF2C656A,
         0xFF4D5C5E, 0xFFC9403A, 0xFFDDD7F3, 0xFF005844, 0xFFB4A200, 0xFF488F69, 0xFF858182, 0xFFD4E9B9,
         0xFF3D7397, 0xFFCAE8CE, 0xFFD60034, 0xFFAA6746, 0xFF9E5585, 0xFFBA6200

// --- BEGIN TEST INSTANCE ----------------------------------------------------

 * The following .jsh file must define the process instance to be tested and
 * assign it to a variable P.
#include "SystemMonitorInstance-II.jsh"

// --- END TEST INSTANCE ------------------------------------------------------

if ( P == undefined || !P instanceof ProcessInstance )
   throw new Error( "Variable P not defined, or not a valid process instance." );

let M = new CPUMonitor;;
//P.executeOn( ImageWindow.activeWindow.mainView );
This script only works on the reference Linux implementation of PixInsight because it makes extensive use of the /proc filesystem. If somebody has practical ideas to implement it on other platforms, I'd be very interested in hearing them.

The script requires an additional .jsh file with the JavaScript source code of the instance to be executed. For example, in this case the SystemMonitorInstance-II.jsh (see line 501 above) is as follows:

 * Test process instance for SystemMonitor.jsh
var P = new ImageIntegration;
P.images = [ // enabled, path, drizzlePath
   [true, "/home/juan/tmp/test-SA/output/001_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/002_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/003_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/004_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/005_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/006_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/007_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/008_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/009_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/010_r.xisf", ""], // row 10
   [true, "/home/juan/tmp/test-SA/output/011_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/012_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/013_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/014_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/015_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/016_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/017_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/018_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/019_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/020_r.xisf", ""], // row 20
   [true, "/home/juan/tmp/test-SA/output/021_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/022_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/023_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/024_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/025_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/026_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/027_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/028_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/029_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/030_r.xisf", ""], // row 30
   [true, "/home/juan/tmp/test-SA/output/031_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/032_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/033_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/034_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/035_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/036_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/037_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/038_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/039_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/040_r.xisf", ""], // row 40
   [true, "/home/juan/tmp/test-SA/output/041_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/042_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/043_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/044_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/045_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/046_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/047_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/048_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/049_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/050_r.xisf", ""], // row 50
   [true, "/home/juan/tmp/test-SA/output/051_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/052_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/053_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/054_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/055_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/056_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/057_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/058_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/059_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/060_r.xisf", ""], // row 60
   [true, "/home/juan/tmp/test-SA/output/061_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/062_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/063_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/064_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/065_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/066_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/067_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/068_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/069_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/070_r.xisf", ""], // row 70
   [true, "/home/juan/tmp/test-SA/output/071_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/072_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/073_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/074_r.xisf", ""],
   [true, "/home/juan/tmp/test-SA/output/075_r.xisf", ""]
P.inputHints = "";
P.combination = ImageIntegration.prototype.Average;
P.weightMode = ImageIntegration.prototype.NoiseEvaluation;
P.weightKeyword = "";
P.weightScale = ImageIntegration.prototype.WeightScale_IKSS;
P.ignoreNoiseKeywords = false;
P.normalization = ImageIntegration.prototype.AdditiveWithScaling;
P.rejection = ImageIntegration.prototype.LinearFit;
P.rejectionNormalization = ImageIntegration.prototype.Scale;
P.minMaxLow = 1;
P.minMaxHigh = 1;
P.pcClipLow = 0.200;
P.pcClipHigh = 0.100;
P.sigmaLow = 4.000;
P.sigmaHigh = 2.000;
P.linearFitLow = 5.000;
P.linearFitHigh = 2.500;
P.ccdGain = 1.00;
P.ccdReadNoise = 10.00;
P.ccdScaleNoise = 0.00;
P.clipLow = true;
P.clipHigh = true;
P.rangeClipLow = true;
P.rangeLow = 0.000000;
P.rangeClipHigh = false;
P.rangeHigh = 0.980000;
P.mapRangeRejection = true;
P.reportRangeRejection = false;
P.generate64BitResult = false;
P.generateRejectionMaps = true;
P.generateIntegratedImage = true;
P.generateDrizzleData = false;
P.closePreviousImages = true;
P.bufferSizeMB = 64; // ### 64 MiB to load a single image in each integration buffer
P.stackSizeMB = 16*1024; // ### 16 GiB to load the whole data set for rejection and integration
P.useROI = false;
P.roiX0 = 0;
P.roiY0 = 0;
P.roiX1 = 0;
P.roiY1 = 0;
P.useCache = false; // ### Do not use the image cache for testing purposes
P.evaluateNoise = true;
P.mrsMinDataFraction = 0.010;
P.noGUIMessages = true;
P.useFileThreads = true;
P.fileThreadOverload = 1.00;
Source code for process instances can be easily generated automatically from a variety of resources in PixInsight, including process windows, process icons, ProcessContainer, the Processing History window, etc.

In order to use this script to analyze processes accessing disk files, one must make sure that the Linux kernel drops all of its internal disk cache data before executing the script. The best way to achieve this is by executing the following commands with root privileges:

# sync
# echo 3 > /proc/sys/vm/drop_caches
See this document for detailed information on the drop_caches file writing operation.

This script is an invaluable performance analysis tool. It is also a nice example of the power and flexibility of JavaScript scripting in PixInsight. This is real image processing and analysis, so don't try to replicate this on your favorite retouching application or magical black box.

Enjoy it, and Happy Holidays to everybody!



PTeam Member
Jan 16, 2013

That is impressive. Now I understand what I was seeing in the process console during ImageIntegration yesterday. I knew something changed for the good even on my old 6 core machine, haha.

Hi Juan,

Excellent work - as usual.

Can I send you the bill for my new PC - because I obviously now need an upgrade on my old system. If my Darling Wife sees that I have no longer any excuse to spend as much time in front of my computer (waiting for things to happen) then she will naturally expect me to spend that recovered time with her, watching TV. So, you will understand that I cannot make the purchase using 'my' credit card. I trust this will be OK  ::)

Now, please, take some time off over the festive season !!


Well-known member
Aug 13, 2012
this is indeed fascinating stuff. Can you comment on how these improvements may alter our approach to configuration of swap space? For example, many of us implement either RAM disks or swap in RAM to maximize swap file performance. With these tool improvements would we be bettor off leaving that RAM available for use by these parallel processes?


PTeam Member
Nov 27, 2011
San Francisco
Both SA and II are now much faster on my iMac. Thank you.

Could high-level parallelization be applied to SA view targets by using temp disk files?



Well-known member
Jun 20, 2016

Thanks for the excellent new modules. They are much faster.

You mentioned that you are not able to parallelize the star detection module.
Perhaps it is already fast enough, but it seems to me that you could break the task into pieces.
For example, Break the image into left and right sections. Allow a small overlap region, i.e. Each half will be 52%. Then detect the stars, but only keep the stars with the centroid on the left / right side of the image in each case. this allows the use of 2 parallel processes etc. (One only needs to check the centroid in the central strip region).


in any case, now that you are running separate images concurrently, you have solved the problem in a different manner. The new modules are really screaming on my machine.

Juan Conejero

PixInsight Staff
Sep 2, 2004
Valencia, Spain
Thank you so much to everybody for your support.

Now, please, take some time off over the festive season !!
That would be great, Niall, but a new version of PixInsight should hit the street on January. Also lots of pending projects, such as XISF, tool updates, some documentation, maintenance, etc. So no, not a lot of time I can take off work for now...

You mentioned that you are not able to parallelize the star detection module.
Perhaps it is already fast enough, but it seems to me that you could break the task into pieces.
Eric, unfortunately, the star detection task cannot be split that way. This task uses multiscale transforms to isolate image structures, which cannot be performed on image sections. Although not a high priority, I plan on writing a new star detection engine without most of these limitations, which should be more parallelizable and hence run much faster.

Could high-level parallelization be applied to SA view targets by using temp disk files?
Mike, yes this is doable. However, I don't know if that would be a real advantage. Do you have any specific task where this feature would be interesting?

Can you comment on how these improvements may alter our approach to configuration of swap space? For example, many of us implement either RAM disks or swap in RAM to maximize swap file performance. With these tool improvements would we be bettor off leaving that RAM available for use by these parallel processes?
A general answer is difficult in this case. It mainly depends on the number of frames you acquire. The new versions of SA and II require much more RAM available to work properly. Basically, each processor core now loads an image and generates working duplicates as necessary, so the memory space requirements have been multiplied roughly by the number of processor cores. In the case of StarAlignment, it runs a 20% more threads than the number of processors available by default, since this has shown some significant speed improvements in my tests (shortly: overloading processor cores slightly leads to a reduction of the adverse impact of I/O wait states for large data sets). You'll have to find a good equilibrium between swap files and intensive preprocessing tasks when planning how to use your available RAM.

The next versions of SA and II will have additional parameters exposed to the user in order to make them more easily configurable. Right now you can disable high-level parallelization by setting useFileThreads=false. You can also change fileThreadOverload to control the number of excess threads launched by these processes (this parameter is 1.0 and 1.2 by default, respectively for II and SA).

Now that we are removing most of the bottlenecks in our preprocessing pipelines, I plan on releasing a new official benchmark to measure performance exclusively in preprocessing tasks, including calibration, debayering, registration, integration, and drizzle. Hopefully this will be a new helpful tool to make hardware and configuration decisions.


PTeam Member
Nov 27, 2011
San Francisco
Juan Conejero said:
Could high-level parallelization be applied to SA view targets by using temp disk files?
Mike, yes this is doable. However, I don't know if that would be a real advantage. Do you have any specific task where this feature would be interesting?
No longer, I modified my script to place reference and all view targets in /tmp/uniqueFileName. Works fast. Thank you,


Well-known member
Mar 27, 2005
Thanks Juan for a great Christmas Gift. I was hoping these would be released and I got my wish.


I two thoughts for the preprocessing wish list.  These are non core option but would be useful.  Stick this in the bell and whistle category.
Have image integration produce and save a text file for Mure NR variance.

Generate a standardize way to store cosmetic correction data for BPP.  I forget where  I saved the Icon at times.
Also it is too easy to move the dark frame and break the process.



Well-known member
Nov 6, 2012
Hi Juan,

Thank you for these.  I found it significantly faster than before in image calibration, registration, and integration.  It is really an important improvement.

One thing I found in the past is that, the statistical data calculated during image integration are not stored anywhere.  If I close PixInsight, turn it on again, and integrate the same batch of images, the same statistical calculation will be done again.  This is very time consuming.  With the new parallelization, this can be done much faster.  However, it is still a waste of time if the same images have to go through the same statistical calculation again and again.  Is this still the case?  If so, can those data be written somewhere (FITS header, or XISF header) without re-wrting the whole image, and be used in the future (given that the image itself is not changed)?  This should be more efficient, and can reduce the consumption of electricity (and hence make the polar bears happier).


Juan Conejero

PixInsight Staff
Sep 2, 2004
Valencia, Spain
Hi Wei-Hao,

Thank you. Since its first versions, ImageIntegration has always had a file cache feature to store statistical properties of images. Once an image has been integrated, its data is stored in the cache for fast retrieval in successive tool executions. The cache is always enabled by default, but it can be disabled by unchecking the Use file cache option. You can manage the integration cache by clicking the Preferences button (wrench icon) on the tool window. Read the tool tips on the ImageIntegration Cache Preferences dialog for more detailed information.

Storing statistical properties of images as metadata (FITS header keywords or XISF properties) is a bad idea in general, since it introduces a dependency that can be extremely difficult to manage. For example, what happens if you alter the pixel data of the image (in PixInsight or in other application) in a way that invalidates statistical metadata? Instead of this, ImageIntegration's cache stores the properties under its exclusive control, including a timestamp for each cache item. When a file is loaded again for integration, II looks for its file path in the cache and, if it is found, its stored timestamp is compared to the current file modification time. If the times match, the cache item is valid and stored data are retrieved. If the times differ, the cache item is discarded and new data are computed. There are different strategies for increased cache security, including cryptographic digests, sparse sampling, etc, but for II timestamps are simple and do the job quite well.


Well-known member
Nov 6, 2012
Hi Juan,

Thanks for the explanation.  I checked my II tool, and file cache is enabled as its default.  However, I pretty much remember that II re-calculate image statistics every time for the same image.  Are there other things that I should check?

Juan Conejero

PixInsight Staff
Sep 2, 2004
Valencia, Spain
I pretty much remember that II re-calculate image statistics every time for the same image.
As far as I can figure out, that can only happen if one or more of these conditions are true:

- The cache has been disabled.

- The cache items have expired. By default, cache items have a prescribed duration of 30 days. This is usually sufficient, since typically a user does not work integrating the same data set for so long. However, cache items can be made eternal by setting duration=0 in Preferences.

- The cache has been erased, either intentionally or accidentally. For example, this happens if you perform a reset of application settings.

- The files have changed inadvertently. Note that only a change in file modification times is sufficient to invalidate cache items. Some file management and system utility applications can cause these changes. For example, if you store your data on a folder controlled by the Dropbox application, file times can change without real changes to file contents.

- The files have been moved. As I've described above, II uses a relatively simplistic (but very fast) approach where only full file paths on the local filesystem and last modification times are used to validate cache items.

Other than these, we have a bug. However, this has not been reported before on any platform, and our intensive tests have shown no failure in II's file cache.


PTeam Member
Sep 3, 2004
Valencia (Spain)

I would want to expose the importance of running the new version of these tools in SSD drives. This is even more important if you are working on a laptop computer. Rotational hard drives in laptop computers are usually very slow so you'll get a very small benefit from reading files in parallel with these drives. Here you can see a comparison of the iowait graph reading files from a 2.5" HDD (the first graph) and a SSD (the second one):

This has a terrible effect on the processor usage:

While the statistics are calculated almost 4 times faster with the new version of the tool reading from an SSD drive, we only get 60% faster if we read the files from an HDD drive. Up to now, I always recommended to store the current projects in a second SSD drive in your computer (separated from the OS SSD); this is now even more important.

This test was done with a laptop having a quad-core, sixth generation i7 processor, running an integration of 35 color images, each one having 10-mepagixel resolution, and using linear fit clipping.

As you can see, we are updating some of the existing tools. Next year will be a wonderful one: we have been working hard on many improvements, so we'll be updating many tools, as well as releasing new ones. Stay tuned. ;-)

Best regards,


New member
Feb 21, 2016
Hi Juan,

this is really great stuff and a big improvement ! Thanks !

On a side-note: On my Linux PC (Fedora 25, x86_64, 4 cores on 1 socket), StarAlignment launches 5 parallel threads while ImageIntegation correctly launches 4 parallel threads.

IMHO it should be 4 processes on a 4-core system, right ?

Tools like nproc, lscpu and /proc/cpuinfo correctly report 4 cores on this system.

Am I missing something or could there be a small issue int he counting of CPUs ?

Many thanks,



Juan Conejero

PixInsight Staff
Sep 2, 2004
Valencia, Spain
Hi Michael,

Am I missing something or could there be a small issue int he counting of CPUs ?
Not at all, of course the number of logical processors available is correctly detected on all platforms.

This is the expected behavior. By default, StarAlignment uses a 20% more worker threads than the number of processors available. This is what we call thread overload. In my intensive tests before releasing the new version of SA, a moderate thread overload has shown small performance improvements. The reason is probably that if there are some spare threads available, they can be fired up as soon as other threads start waiting for I/O completion. In this way thread overload reduces idle wait states and allows to exploit the available processing power somewhat more. This technique only works in some cases for tasks where relatively long I/O operations represent a significant part of the total work.

You can control thread overload with the fileThreadOverload parameter, which can be changed by editing an instance's source code (click the Edit Instance Source Code button on the tool's window, or select the same option by right-clicking on a process icon). Set fileThreadOverload=1 to disable thread overload. The default values are 1.0 for ImageIntegration and 1.2 for StarAlignment.


New member
Feb 21, 2016
Hi Juan,

thanks for the clarification ! Makes sense !

The parallelization feature is really great. Love it. Much faster than before...


Alfredo Beltran

Well-known member
Jan 2, 2013

Based on this thread I have the following questions. Given parallelization takes advantage of several working threads, would it be better to have a very fast processor with 4-cores & 8-threads as the i7-7700k (4.2 - 4.5 GHz clock), or an 8-cores & 16 threads as the new AMD Ryzen 7 1700 (3.2 - 3.6 GHz clock) or the Xeon E5-2620 v4 (2.10 - 3.00 GHz) ? In other words, would there be more benefit from the faster processor with 4-cores than with a slower 8-cores processor?

On he other hand, since now this updated Pixinsight processes use more RAM, would it be a huge improvement to have faster RAM?