* Bug #12057 fixed - Scopes with big scope buffer size simulation was much 27/10127/7
Clément DAVID [Fri, 18 Jan 2013 16:04:41 +0000 (17:04 +0100)]
                     more slower.

 - use a 2 objects approach to avoid copy cost on a huge buffer
 - use a 4K points threshold on misconfiguration
 - cmscope and cscope updated
 - update the unit tests to check the number of points at the end

Change-Id: I700d22d3769fae517575c95ca6e1eab30992cd37

scilab/CHANGES_5.4.X
scilab/modules/scicos_blocks/src/c/cmscope.c
scilab/modules/scicos_blocks/src/c/cscope.c
scilab/modules/xcos/tests/nonreg_tests/bug_12057.dia.ref [new file with mode: 0644]
scilab/modules/xcos/tests/nonreg_tests/bug_12057.tst [new file with mode: 0644]
scilab/modules/xcos/tests/nonreg_tests/bug_12057_cmscope.xcos [new file with mode: 0644]
scilab/modules/xcos/tests/nonreg_tests/bug_12057_cscope.xcos [new file with mode: 0644]
scilab/modules/xcos/tests/unit_tests/cmscope.dia.ref
scilab/modules/xcos/tests/unit_tests/cmscope.tst
scilab/modules/xcos/tests/unit_tests/cscope.dia.ref
scilab/modules/xcos/tests/unit_tests/cscope.tst

index f818787..7bf2da5 100644 (file)
@@ -127,6 +127,9 @@ Xcos
 * Bug #12031 fixed - Changes in context of superblock did not always have
                      effect.
 
+* Bug #12057 fixed - Scopes with big scope buffer size simulation was much
+                     more slower.
+
 * Bug #12162 fixed - tbx_build_blocks did not report errors.
 
 * Bug #12167 fixed - Text of ports in superblocks were not updated.
index e154dc3..574f09c 100644 (file)
@@ -22,6 +22,7 @@
 #include "setGraphicObjectProperty.h"
 #include "graphicObjectProperties.h"
 #include "createGraphicObject.h"
+#include "deleteGraphicObject.h"
 
 #include "CurrentFigure.h"
 #include "CurrentObject.h"
@@ -42,6 +43,8 @@
 // #define LOG(...) printf(__VA_ARGS__)
 #define LOG(...)
 
+#define HISTORY_POINTS_THRESHOLD 4096
+
 /*****************************************************************************
  * Internal container structure
  ****************************************************************************/
@@ -54,17 +57,22 @@ typedef struct
     struct
     {
         int *numberOfPoints;
+        double ***bufferCoordinates;
         int *maxNumberOfPoints;
-        double ***coordinates;
+        double ***historyCoordinates;
     } internal;
 
     struct
     {
         int *periodCounter;
 
+        BOOL *disableBufferUpdate;
+        int *historyUpdateCounter;
+
         char const* cachedFigureUID;
         char **cachedAxeUID;
-        char ***cachedPolylinesUIDs;
+        char ***cachedBufferPolylinesUIDs;
+        char ***cachedHistoryPolylinesUIDs;
     } scope;
 } sco_data;
 
@@ -83,13 +91,27 @@ static sco_data *getScoData(scicos_block * block);
 static void freeScoData(scicos_block * block);
 
 /**
- * Realloc any internal data
+ * Realloc the history buffer data
  *
  * \param block the block
  * \param input the selected input
  * \param numberOfPoints realloc to store this number of points
  */
-static sco_data *reallocScoData(scicos_block * block, int input, int numberOfPoints);
+static sco_data *reallocHistoryBuffer(scicos_block * block, int input, int numberOfPoints);
+
+/**
+ * Set values into the coordinates buffer.
+ *
+ * \param block the block
+ * \param input the selected input
+ * \param coordinates the buffer
+ * \param numberOfPoints the number of points to set (actual)
+ * \param bufferPoints the buffer size (max)
+ * \param t the time to set
+ * \param value the value to set
+ */
+static void setBuffersCoordinates(scicos_block * block, int input, double* coordinates, const int numberOfPoints,
+                                  const int bufferPoints, const double t, const double value);
 
 /**
  * Append the data to the current data
@@ -140,18 +162,26 @@ static char *getAxe(char const* pFigureUID, scicos_block * block, int input);
  * \param block the block
  * \param input the current input index (0-indexed)
  * \param row the current row index (0-indexed)
+ * \param history get the history polyline
  * \return a valid polyline UID or NULL on error
  */
-static char *getPolyline(char *pAxeUID, scicos_block * block, int input, int row);
+static char *getPolyline(char *pAxeUID, scicos_block * block, int input, int row, BOOL history);
+
+/**
+ * Delete all the buffer polylines.
+ *
+ * \param block the block
+ */
+static void deleteBufferPolylines(scicos_block * block);
 
 /**
- * Set the polylines buffer size
+ * Set the polylines history size and push the history buffer
  *
  * \param block the block
  * \param input the input port index
  * \param maxNumberOfPoints the size of the buffer
  */
-static BOOL setPolylinesBuffers(scicos_block * block, int input, int maxNumberOfPoints);
+static BOOL pushHistory(scicos_block * block, int input, int maxNumberOfPoints);
 
 /**
  * Set the polylines bounds
@@ -229,6 +259,15 @@ SCICOS_BLOCKS_IMPEXP void cmscope(scicos_block * block, scicos_flag flag)
             break;
 
         case Ending:
+            sco = getScoData(block);
+            for (i = 0; i < block->nin; i++)
+            {
+                sco = reallocHistoryBuffer(block, i, sco->internal.maxNumberOfPoints[i] + sco->internal.numberOfPoints[i]);
+                sco->scope.disableBufferUpdate[i] = FALSE;
+                sco->scope.historyUpdateCounter[i] = 0;
+                pushHistory(block, i, sco->internal.maxNumberOfPoints[i]);
+            }
+            deleteBufferPolylines(block);
             freeScoData(block);
             break;
 
@@ -275,50 +314,80 @@ static sco_data *getScoData(scicos_block * block)
 
         for (i = 0; i < block->nin; i++)
         {
+            // 0 points out of a block->ipar[2] points buffer
             sco->internal.numberOfPoints[i] = 0;
-            sco->internal.maxNumberOfPoints[i] = block->ipar[2];
+            // 0 points out of a 0 points history
+            sco->internal.maxNumberOfPoints[i] = 0;
         }
 
-        sco->internal.coordinates = (double ***)CALLOC(block->nin, sizeof(double **));
-        if (sco->internal.coordinates == NULL)
+        sco->internal.bufferCoordinates = (double ***)CALLOC(block->nin, sizeof(double **));
+        if (sco->internal.bufferCoordinates == NULL)
         {
-            goto error_handler_coordinates;
+            goto error_handler_bufferCoordinates;
         }
 
         for (i = 0; i < block->nin; i++)
         {
-            sco->internal.coordinates[i] = (double **)CALLOC(block->insz[i], sizeof(double *));
-            if (sco->internal.coordinates[i] == NULL)
+            sco->internal.bufferCoordinates[i] = (double **)CALLOC(block->insz[i], sizeof(double *));
+            if (sco->internal.bufferCoordinates[i] == NULL)
             {
-                goto error_handler_coordinates_i;
+                goto error_handler_bufferCoordinates_i;
             }
         }
         for (i = 0; i < block->nin; i++)
         {
             for (j = 0; j < block->insz[i]; j++)
             {
-                sco->internal.coordinates[i][j] = (double *)CALLOC(3 * block->ipar[2], sizeof(double));
+                sco->internal.bufferCoordinates[i][j] = (double *)CALLOC(3 * block->ipar[2], sizeof(double));
 
-                if (sco->internal.coordinates[i][j] == NULL)
+                if (sco->internal.bufferCoordinates[i][j] == NULL)
                 {
-                    goto error_handler_coordinates_ij;
+                    goto error_handler_bufferCoordinates_ij;
                 }
             }
         }
 
+        sco->internal.historyCoordinates = (double ***)CALLOC(block->nin, sizeof(double **));
+        if (sco->internal.historyCoordinates == NULL)
+        {
+            goto error_handler_historyCoordinates;
+        }
+
+        for (i = 0; i < block->nin; i++)
+        {
+            sco->internal.historyCoordinates[i] = (double **)CALLOC(block->insz[i], sizeof(double *));
+            if (sco->internal.historyCoordinates[i] == NULL)
+            {
+                goto error_handler_historyCoordinates_i;
+            }
+        }
+
         sco->scope.periodCounter = (int *) CALLOC(block->nin, sizeof(int));
         if (sco->scope.periodCounter == NULL)
         {
             goto error_handler_periodCounter;
         }
 
+        sco->scope.disableBufferUpdate = (int *) CALLOC(block->nin, sizeof(BOOL));
+        if (sco->scope.disableBufferUpdate == NULL)
+        {
+            goto error_handler_disableBufferUpdate;
+        }
+        sco->scope.historyUpdateCounter = (int *) CALLOC(block->nin, sizeof(int));
+        if (sco->scope.historyUpdateCounter == NULL)
+        {
+            goto error_handler_historyUpdateCounter;
+        }
+
         sco->scope.cachedFigureUID = NULL;
         sco->scope.cachedAxeUID = (char **)CALLOC(block->nin, sizeof(char *));
 
-        sco->scope.cachedPolylinesUIDs = (char ***)CALLOC(block->nin, sizeof(char **));
+        sco->scope.cachedBufferPolylinesUIDs = (char ***)CALLOC(block->nin, sizeof(char **));
+        sco->scope.cachedHistoryPolylinesUIDs = (char ***)CALLOC(block->nin, sizeof(char **));
         for (i = 0; i < block->nin; i++)
         {
-            sco->scope.cachedPolylinesUIDs[i] = (char **)CALLOC(block->insz[i], sizeof(char *));
+            sco->scope.cachedBufferPolylinesUIDs[i] = (char **)CALLOC(block->insz[i], sizeof(char *));
+            sco->scope.cachedHistoryPolylinesUIDs[i] = (char **)CALLOC(block->insz[i], sizeof(char *));
         }
 
         *(block->work) = sco;
@@ -329,25 +398,38 @@ static sco_data *getScoData(scicos_block * block)
     /*
      * Error management (out of normal flow)
      */
+
+error_handler_historyUpdateCounter:
+    FREE(sco->scope.disableBufferUpdate);
+error_handler_disableBufferUpdate:
+    FREE(sco->scope.periodCounter);
 error_handler_periodCounter:
+    i = block->nin;
+error_handler_historyCoordinates_i:
+    for (j = 0; j < i; j++)
+    {
+        FREE(sco->internal.historyCoordinates[i]);
+    }
+    FREE(sco->internal.historyCoordinates);
+error_handler_historyCoordinates:
     i = block->nin - 1;
-    j = 2 ^ 31;
-error_handler_coordinates_ij:
+    j = block->insz[i] - 1;
+error_handler_bufferCoordinates_ij:
     for (k = 0; k < i; k++)
     {
-        for (l = 0; l < j && l < block->insz[i]; l++)
+        for (l = 0; l < j; l++)
         {
-            FREE(sco->internal.coordinates[k][l]);
+            FREE(sco->internal.bufferCoordinates[k][l]);
         }
     }
     i = block->nin - 1;
-error_handler_coordinates_i:
+error_handler_bufferCoordinates_i:
     for (j = 0; j < i; j++)
     {
-        FREE(sco->internal.coordinates[i]);
+        FREE(sco->internal.bufferCoordinates[i]);
     }
-    FREE(sco->internal.coordinates);
-error_handler_coordinates:
+    FREE(sco->internal.bufferCoordinates);
+error_handler_bufferCoordinates:
     FREE(sco->internal.maxNumberOfPoints);
 error_handler_maxNumberOfPoints:
     FREE(sco->internal.numberOfPoints);
@@ -370,66 +452,100 @@ static void freeScoData(scicos_block * block)
         {
             for (j = 0; j < block->insz[i]; j++)
             {
-                FREE(sco->internal.coordinates[i][j]);
+                if (sco->internal.historyCoordinates[i][j] != NULL)
+                {
+                    FREE(sco->internal.historyCoordinates[i][j]);
+                }
+                FREE(sco->internal.bufferCoordinates[i][j]);
             }
-            FREE(sco->internal.coordinates[i]);
+            FREE(sco->internal.historyCoordinates[i]);
+            FREE(sco->internal.bufferCoordinates[i]);
         }
-        FREE(sco->internal.coordinates);
+        FREE(sco->internal.historyCoordinates);
+        FREE(sco->internal.bufferCoordinates);
 
-        for (i = 0; i < block->nin; i++)
+        FREE(sco->scope.periodCounter);
+
+        FREE(sco->scope.disableBufferUpdate);
+        FREE(sco->scope.historyUpdateCounter);
+
+        for (i = 0; i < block->insz[0]; i++)
         {
-            for (j = 0; j < block->insz[i]; j++)
-            {
-                FREE(sco->scope.cachedPolylinesUIDs[i][j]);
-            }
-            FREE(sco->scope.cachedAxeUID[i]);
+            FREE(sco->scope.cachedHistoryPolylinesUIDs[i]);
+            FREE(sco->scope.cachedBufferPolylinesUIDs[i]);
         }
+        FREE(sco->scope.cachedAxeUID);
 
         FREE(sco);
         *(block->work) = NULL;
     }
 }
 
-static sco_data *reallocScoData(scicos_block * block, int input, int numberOfPoints)
+static sco_data *reallocHistoryBuffer(scicos_block * block, int input, int numberOfPoints)
 {
     sco_data *sco = (sco_data *) * (block->work);
     int i;
 
     double *ptr;
-    int setLen;
+    int allocatedNumberOfPoints;
+
     int previousNumberOfPoints = sco->internal.maxNumberOfPoints[input];
-    int newPoints = numberOfPoints - previousNumberOfPoints;
+    int numberOfCopiedPoints = numberOfPoints - sco->internal.maxNumberOfPoints[input];
 
-    LOG("%s: %s at %d to %d\n", "cmscope", "reallocScoData", input, numberOfPoints);
+    double *buffer;
+    int bufferNumberOfPoints = block->ipar[2];
+    int bufferNewPointInc;
+
+    if (previousNumberOfPoints == 0)
+    {
+        allocatedNumberOfPoints = numberOfPoints;
+        bufferNewPointInc = 0;
+    }
+    else
+    {
+        allocatedNumberOfPoints = numberOfPoints - 1;
+        bufferNewPointInc = 1;
+    }
+
+    if (sco->scope.historyUpdateCounter[input] <= 0)
+    {
+        if (numberOfPoints > HISTORY_POINTS_THRESHOLD)
+        {
+            sco->scope.disableBufferUpdate[input] = TRUE;
+            sco->scope.historyUpdateCounter[input] = numberOfPoints / HISTORY_POINTS_THRESHOLD;
+        }
+        else
+        {
+            sco->scope.disableBufferUpdate[input] = FALSE;
+            sco->scope.historyUpdateCounter[input] = 0;
+        }
+    }
 
     for (i = 0; i < block->insz[input]; i++)
     {
-        ptr = (double *)REALLOC(sco->internal.coordinates[input][i], 3 * numberOfPoints * sizeof(double));
+        ptr = (double *)MALLOC(3 * allocatedNumberOfPoints * sizeof(double));
         if (ptr == NULL)
         {
             goto error_handler;
         }
 
+        // memcpy existing X-axis values from the history
+        memcpy(ptr, sco->internal.historyCoordinates[input][i], previousNumberOfPoints * sizeof(double));
+        // memcpy existing Y-axis values from the history
+        memcpy(ptr + allocatedNumberOfPoints, sco->internal.historyCoordinates[input][i] + previousNumberOfPoints, previousNumberOfPoints * sizeof(double));
         // clear the last points, the Z-axis values
-        memset(ptr + 2 * numberOfPoints, 0, numberOfPoints * sizeof(double));
-
-        // memcpy existing Y-axis values (use memmove to handle memory overlapping)
-        memmove(ptr + numberOfPoints, ptr + previousNumberOfPoints, previousNumberOfPoints * sizeof(double));
+        memset(ptr + 2 * allocatedNumberOfPoints, 0, allocatedNumberOfPoints * sizeof(double));
 
-        // then set the last points to the last values for Y-axis and X-axis values
-        for (setLen = newPoints - 1; setLen >= 0; setLen--)
-        {
-            ptr[numberOfPoints + previousNumberOfPoints + setLen] = ptr[numberOfPoints + previousNumberOfPoints - 1];
-        }
-        for (setLen = newPoints - 1; setLen >= 0; setLen--)
-        {
-            ptr[previousNumberOfPoints + setLen] = ptr[previousNumberOfPoints - 1];
-        }
+        // then set the last points to the last values for X-axis and Y-axis values from the buffer points
+        buffer = sco->internal.bufferCoordinates[input][i];
+        memcpy(ptr + previousNumberOfPoints, buffer + bufferNewPointInc, (numberOfCopiedPoints - bufferNewPointInc) * sizeof(double));
+        memcpy(ptr + allocatedNumberOfPoints + previousNumberOfPoints, buffer + bufferNumberOfPoints + bufferNewPointInc, (numberOfCopiedPoints - bufferNewPointInc) * sizeof(double));
 
-        sco->internal.coordinates[input][i] = ptr;
+        FREE(sco->internal.historyCoordinates[input][i]);
+        sco->internal.historyCoordinates[input][i] = ptr;
     }
 
-    sco->internal.maxNumberOfPoints[input] = numberOfPoints;
+    sco->internal.maxNumberOfPoints[input] = allocatedNumberOfPoints;
     return sco;
 
 error_handler:
@@ -439,14 +555,37 @@ error_handler:
     return NULL;
 }
 
+static void setBuffersCoordinates(scicos_block * block, int input, double* coordinates, const int numberOfPoints,
+                                  const int bufferPoints, const double t, const double value)
+{
+    int setLen;
+    sco_data *sco = (sco_data *) * (block->work);
+
+    if (sco->scope.disableBufferUpdate[input] == TRUE)
+    {
+        coordinates[numberOfPoints] = t;
+        coordinates[bufferPoints + numberOfPoints] = value;
+        return;
+    }
+
+    // X-axis values first
+    for (setLen = numberOfPoints; setLen < bufferPoints; setLen++)
+    {
+        coordinates[setLen] = t;
+    }
+    // then Y-axis values
+    for (setLen = numberOfPoints; setLen < bufferPoints; setLen++)
+    {
+        coordinates[bufferPoints + setLen] = value;
+    }
+    // then Z-axis values (always clear'ed)
+}
+
 static void appendData(scicos_block * block, int input, double t, double *data)
 {
     int i;
 
     sco_data *sco = (sco_data *) * (block->work);
-    int maxNumberOfPoints = sco->internal.maxNumberOfPoints[input];
-    int numberOfPoints = sco->internal.numberOfPoints[input];
-
 
     /*
      * Handle the case where the t is greater than the data_bounds
@@ -455,8 +594,26 @@ static void appendData(scicos_block * block, int input, double t, double *data)
     {
         sco->scope.periodCounter[input]++;
 
-        numberOfPoints = 0;
-        sco->internal.numberOfPoints[input] = 0;
+        // set the buffer coordinates to the last point
+        for (i = 0; i < block->insz[input]; i++)
+        {
+            sco->internal.bufferCoordinates[input][i][0] = sco->internal.bufferCoordinates[input][i][sco->internal.numberOfPoints[input] - 1];
+            sco->internal.bufferCoordinates[input][i][block->ipar[2]] = sco->internal.bufferCoordinates[input][i][block->ipar[2] + sco->internal.numberOfPoints[input] - 1];
+        }
+        sco->internal.numberOfPoints[input] = 1;
+
+        // clear the history coordinates
+        sco->internal.maxNumberOfPoints[input] = 0;
+        for (i = 0; i < block->insz[input]; i++)
+        {
+            if (sco->internal.historyCoordinates[input][i] != NULL)
+            {
+                FREE(sco->internal.historyCoordinates[input][i]);
+                sco->internal.historyCoordinates[input][i] = NULL;
+            }
+        }
+
+        // configure scope setting
         if (setPolylinesBounds(block, input, sco->scope.periodCounter[input]) == FALSE)
         {
             set_block_error(-5);
@@ -468,14 +625,24 @@ static void appendData(scicos_block * block, int input, double t, double *data)
     /*
      * Handle the case where the scope has more points than maxNumberOfPoints
      */
-    if (sco != NULL && numberOfPoints >= maxNumberOfPoints)
+    if (sco != NULL && sco->internal.numberOfPoints[input] >= block->ipar[2])
     {
-        // on a full scope, re-alloc
+        int maxNumberOfPoints = sco->internal.maxNumberOfPoints[input];
+
+        // on a full scope, re-alloc history coordinates
         maxNumberOfPoints = maxNumberOfPoints + block->ipar[2];
-        sco = reallocScoData(block, input, maxNumberOfPoints);
+        sco = reallocHistoryBuffer(block, input, maxNumberOfPoints);
+
+        // set the buffer coordinates to the last point
+        for (i = 0; i < block->insz[input]; i++)
+        {
+            sco->internal.bufferCoordinates[input][i][0] = sco->internal.bufferCoordinates[input][i][block->ipar[2] - 1];
+            sco->internal.bufferCoordinates[input][i][block->ipar[2]] = sco->internal.bufferCoordinates[input][i][2 * block->ipar[2] - 1];
+        }
+        sco->internal.numberOfPoints[input] = 1;
 
         // reconfigure related graphic objects
-        if (setPolylinesBuffers(block, input, maxNumberOfPoints) == FALSE)
+        if (pushHistory(block, input, sco->internal.maxNumberOfPoints[input]) == FALSE)
         {
             set_block_error(-5);
             freeScoData(block);
@@ -488,23 +655,10 @@ static void appendData(scicos_block * block, int input, double t, double *data)
      */
     if (sco != NULL)
     {
-        int setLen;
-
         for (i = 0; i < block->insz[input]; i++)
         {
-            // X-axis values first
-            for (setLen = maxNumberOfPoints - numberOfPoints - 1; setLen >= 0; setLen--)
-            {
-                sco->internal.coordinates[input][i][numberOfPoints + setLen] = t;
-            }
-
-            // then Y-axis values
-            for (setLen = maxNumberOfPoints - numberOfPoints - 1; setLen >= 0; setLen--)
-            {
-                sco->internal.coordinates[input][i][maxNumberOfPoints + numberOfPoints + setLen] = data[i];
-            }
-
-            // do not update Z-axis values, always cleared
+            const double value = data[i];
+            setBuffersCoordinates(block, input, sco->internal.bufferCoordinates[input][i], sco->internal.numberOfPoints[input], block->ipar[2], t, value);
         }
 
         sco->internal.numberOfPoints[input]++;
@@ -522,7 +676,7 @@ static BOOL pushData(scicos_block * block, int input, int row)
 
     pFigureUID = getFigure(block);
     pAxeUID = getAxe(pFigureUID, block, input);
-    pPolylineUID = getPolyline(pAxeUID, block, input, row);
+    pPolylineUID = getPolyline(pAxeUID, block, input, row, FALSE);
 
     sco = getScoData(block);
     if (sco == NULL)
@@ -530,10 +684,16 @@ static BOOL pushData(scicos_block * block, int input, int row)
         return FALSE;
     }
 
+    // do not push any data if disabled
+    if (sco->scope.disableBufferUpdate[input] == TRUE)
+    {
+        return TRUE;
+    }
+
     // select the right input and row
-    data = sco->internal.coordinates[input][row];
+    data = sco->internal.bufferCoordinates[input][row];
 
-    return setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_COORDINATES__, data, jni_double_vector, sco->internal.maxNumberOfPoints[input]);
+    return setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_COORDINATES__, data, jni_double_vector, block->ipar[2]);
 }
 
 /*****************************************************************************
@@ -552,6 +712,7 @@ static void setFigureSettings(char const* pFigureUID, scicos_block * block)
 {
     int win_pos[2];
     int win_dim[2];
+    char* label;
 
     int *ipar = block->ipar;
 
@@ -569,7 +730,16 @@ static void setFigureSettings(char const* pFigureUID, scicos_block * block)
     {
         setGraphicObjectProperty(pFigureUID, __GO_SIZE__, &win_dim, jni_int_vector, 2);
     }
-};
+
+    label = GetLabelPtrs(block);
+    if (label != NULL)
+    {
+        if (strlen(label) > 0)
+        {
+            setGraphicObjectProperty(pFigureUID, __GO_NAME__, label, jni_string, 1);
+        }
+    }
+}
 
 /**
  * Set properties on the axes.
@@ -711,7 +881,11 @@ static char *getAxe(char const* pFigureUID, scicos_block * block, int input)
         // allocate the polylines through the getter
         for (i = 0; i < block->insz[input]; i++)
         {
-            getPolyline(pAxe, block, input, i);
+            getPolyline(pAxe, block, input, i, TRUE);
+        }
+        for (i = 0; i < block->insz[input]; i++)
+        {
+            getPolyline(pAxe, block, input, i, FALSE);
         }
 
         setAxesSettings(pAxe, block, input);
@@ -728,13 +902,17 @@ static char *getAxe(char const* pFigureUID, scicos_block * block, int input)
     return sco->scope.cachedAxeUID[input];
 }
 
-static char *getPolyline(char *pAxeUID, scicos_block * block, int input, int row)
+static char *getPolyline(char *pAxeUID, scicos_block * block, int input, int row, BOOL history)
 {
     char *pPolyline;
     BOOL b__true = TRUE;
 
     int color;
 
+    char*** polylinesUIDs;
+    int polylineIndex;
+    int polylineDefaultNumElement;
+
     sco_data *sco = (sco_data *) * (block->work);
 
     // assert the sco is not NULL
@@ -743,13 +921,26 @@ static char *getPolyline(char *pAxeUID, scicos_block * block, int input, int row
         return NULL;
     }
 
+    if (!history)
+    {
+        polylinesUIDs = sco->scope.cachedBufferPolylinesUIDs;
+        polylineIndex = block->insz[input] + row;
+        polylineDefaultNumElement = block->ipar[2];
+    }
+    else
+    {
+        polylinesUIDs = sco->scope.cachedHistoryPolylinesUIDs;
+        polylineIndex = row;
+        polylineDefaultNumElement = 0;
+    }
+
     // fast path for an existing object
-    if (sco->scope.cachedPolylinesUIDs != NULL && sco->scope.cachedPolylinesUIDs[input] != NULL && sco->scope.cachedPolylinesUIDs[input][row] != NULL)
+    if (polylinesUIDs != NULL && polylinesUIDs[input] != NULL && polylinesUIDs[input][row] != NULL)
     {
-        return sco->scope.cachedPolylinesUIDs[input][row];
+        return polylinesUIDs[input][row];
     }
 
-    pPolyline = findChildWithKindAt(pAxeUID, __GO_POLYLINE__, row);
+    pPolyline = findChildWithKindAt(pAxeUID, __GO_POLYLINE__, polylineIndex);
 
     /*
      * Allocate if necessary
@@ -775,7 +966,7 @@ static char *getPolyline(char *pAxeUID, scicos_block * block, int input, int row
          * Default setup (will crash if removed)
          */
         {
-            int polylineSize[2] = { 1, block->ipar[2] };
+            int polylineSize[2] = { 1, polylineDefaultNumElement };
             setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_NUM_ELEMENTS_ARRAY__, polylineSize, jni_int_vector, 2);
         }
 
@@ -808,15 +999,34 @@ static char *getPolyline(char *pAxeUID, scicos_block * block, int input, int row
     /*
      * then cache with local storage
      */
-    if (sco->scope.cachedPolylinesUIDs != NULL && sco->scope.cachedPolylinesUIDs[input] != NULL)
+    if (pPolyline != NULL && polylinesUIDs != NULL && polylinesUIDs[input] != NULL)
     {
-        sco->scope.cachedPolylinesUIDs[input][row] = strdup(pPolyline);
+        polylinesUIDs[input][row] = strdup(pPolyline);
         releaseGraphicObjectProperty(__GO_PARENT__, pPolyline, jni_string, 1);
     }
-    return sco->scope.cachedPolylinesUIDs[input][row];
+    return polylinesUIDs[input][row];
 }
 
-static BOOL setPolylinesBuffers(scicos_block * block, int input, int maxNumberOfPoints)
+static void deleteBufferPolylines(scicos_block * block)
+{
+    int i, j;
+
+    char *pPolylineUID;
+
+    sco_data *sco;
+
+    sco = getScoData(block);
+    for (i = 0; i < block->nin; i++)
+    {
+        for (j = 0; j < block->insz[i]; j++)
+        {
+            pPolylineUID = sco->scope.cachedBufferPolylinesUIDs[i][j];
+            deleteGraphicObject(pPolylineUID);
+        }
+    }
+}
+
+static BOOL pushHistory(scicos_block * block, int input, int maxNumberOfPoints)
 {
     int i;
 
@@ -824,18 +1034,33 @@ static BOOL setPolylinesBuffers(scicos_block * block, int input, int maxNumberOf
     char *pAxeUID;
     char *pPolylineUID;
 
+    double *data;
+    sco_data *sco;
+
     BOOL result = TRUE;
     int polylineSize[2] = { 1, maxNumberOfPoints };
 
-    LOG("%s: %s at %d to %d\n", "cmscope", "setPolylinesBuffers", input, maxNumberOfPoints);
-
+    sco = getScoData(block);
     pFigureUID = getFigure(block);
     pAxeUID = getAxe(pFigureUID, block, input);
 
+    // push the data only if the counter == 0, decrement the counter if positive
+    if (sco->scope.historyUpdateCounter[input] > 0)
+    {
+        sco->scope.historyUpdateCounter[input]--;
+    }
+    if (sco->scope.historyUpdateCounter[input] > 0)
+    {
+        return result;
+    }
+
     for (i = 0; i < block->insz[input]; i++)
     {
-        pPolylineUID = getPolyline(pAxeUID, block, input, i);
+        pPolylineUID = getPolyline(pAxeUID, block, input, i, TRUE);
         result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_NUM_ELEMENTS_ARRAY__, polylineSize, jni_int_vector, 2);
+
+        data = sco->internal.historyCoordinates[input][i];
+        result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_COORDINATES__, data, jni_double_vector, maxNumberOfPoints);
     }
 
     return result;
index d847337..2c5d6a7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
- *  Copyright (C) 2011 - Scilab Enterprises - Clement DAVID
+ *  Copyright (C) 2011-2012 - Scilab Enterprises - Clement DAVID
  *
  *  This file must be used under the terms of the CeCILL.
  *  This source file is licensed as described in the file COPYING, which
@@ -22,6 +22,7 @@
 #include "setGraphicObjectProperty.h"
 #include "graphicObjectProperties.h"
 #include "createGraphicObject.h"
+#include "deleteGraphicObject.h"
 
 #include "CurrentFigure.h"
 #include "CurrentObject.h"
@@ -38,6 +39,8 @@
 #include "BuildObjects.h"
 #include "AxesModel.h"
 
+#define HISTORY_POINTS_THRESHOLD 4096
+
 /*****************************************************************************
  * Internal container structure
  ****************************************************************************/
@@ -50,17 +53,22 @@ typedef struct
     struct
     {
         int numberOfPoints;
+        double ***bufferCoordinates;
         int maxNumberOfPoints;
-        double ***coordinates;
+        double ***historyCoordinates;
     } internal;
 
     struct
     {
         int periodCounter;
 
+        BOOL disableBufferUpdate;
+        int historyUpdateCounter;
+
         char const* cachedFigureUID;
         char *cachedAxeUID;
-        char **cachedPolylinesUIDs;
+        char **cachedBufferPolylinesUIDs;
+        char **cachedHistoryPolylinesUIDs;
     } scope;
 } sco_data;
 
@@ -79,13 +87,25 @@ static sco_data *getScoData(scicos_block * block);
 static void freeScoData(scicos_block * block);
 
 /**
- * Realloc any internal data
+ * Realloc the history buffer data
  *
  * \param block the block
- * \param input the selected input
  * \param numberOfPoints realloc to store this number of points
  */
-static sco_data *reallocScoData(scicos_block * block, int numberOfPoints);
+static sco_data *reallocHistoryBuffer(scicos_block * block, int numberOfPoints);
+
+/**
+ * Set values into the coordinates buffer.
+ *
+ * \param block the block
+ * \param coordinates the buffer
+ * \param numberOfPoints the number of points to set (actual)
+ * \param bufferPoints the buffer size (max)
+ * \param t the time to set
+ * \param value the value to set
+ */
+static void setBuffersCoordinates(scicos_block * block, double* coordinates, const int numberOfPoints,
+                                  const int bufferPoints, const double t, const double value);
 
 /**
  * Append the data to the current data
@@ -135,18 +155,26 @@ static char *getAxe(char const* pFigureUID, scicos_block * block, int input);
  * \param pAxeUID the parent axe UID
  * \param block the block
  * \param row the current row index (0-indexed)
+ * \param history get the history polyline
  * \return a valid polyline UID or NULL on error
  */
-static char *getPolyline(char *pAxeUID, scicos_block * block, int row);
+static char *getPolyline(char *pAxeUID, scicos_block * block, int row, BOOL history);
 
 /**
- * Set the polylines buffer size
+ * Delete all the buffer polylines.
+ *
+ * \param block the block
+ */
+static void deleteBufferPolylines(scicos_block * block);
+
+/**
+ * Set the polylines history size and push the history buffer
  *
  * \param block the block
  * \param input the input port index
  * \param maxNumberOfPoints the size of the buffer
  */
-static BOOL setPolylinesBuffers(scicos_block * block, int input, int maxNumberOfPoints);
+static BOOL pushHistory(scicos_block * block, int input, int maxNumberOfPoints);
 
 /**
  * Set the polylines bounds
@@ -222,6 +250,12 @@ SCICOS_BLOCKS_IMPEXP void cscope(scicos_block * block, scicos_flag flag)
             break;
 
         case Ending:
+            sco = getScoData(block);
+            sco = reallocHistoryBuffer(block, sco->internal.maxNumberOfPoints + sco->internal.numberOfPoints);
+            sco->scope.disableBufferUpdate = FALSE;
+            sco->scope.historyUpdateCounter = 0;
+            pushHistory(block, 0, sco->internal.maxNumberOfPoints);
+            deleteBufferPolylines(block);
             freeScoData(block);
             break;
 
@@ -255,40 +289,65 @@ static sco_data *getScoData(scicos_block * block)
             goto error_handler_sco;
         }
 
+        // 0 points out of a block->ipar[2] points buffer
         sco->internal.numberOfPoints = 0;
-        sco->internal.maxNumberOfPoints = block->ipar[2];
 
-        sco->internal.coordinates = (double ***)CALLOC(block->nin, sizeof(double **));
-        if (sco->internal.coordinates == NULL)
+        sco->internal.bufferCoordinates = (double ***)CALLOC(block->nin, sizeof(double **));
+        if (sco->internal.bufferCoordinates == NULL)
         {
-            goto error_handler_coordinates;
+            goto error_handler_bufferCoordinates;
         }
 
         for (i = 0; i < block->nin; i++)
         {
-            sco->internal.coordinates[i] = (double **)CALLOC(block->insz[i], sizeof(double *));
-            if (sco->internal.coordinates[i] == NULL)
+            sco->internal.bufferCoordinates[i] = (double **)CALLOC(block->insz[i], sizeof(double *));
+            if (sco->internal.bufferCoordinates[i] == NULL)
             {
-                goto error_handler_coordinates_i;
+                goto error_handler_bufferCoordinates_i;
             }
         }
         for (i = 0; i < block->nin; i++)
         {
             for (j = 0; j < block->insz[i]; j++)
             {
-                sco->internal.coordinates[i][j] = (double *)CALLOC(3 * block->ipar[2], sizeof(double));
+                sco->internal.bufferCoordinates[i][j] = (double *)CALLOC(3 * block->ipar[2], sizeof(double));
 
-                if (sco->internal.coordinates[i][j] == NULL)
+                if (sco->internal.bufferCoordinates[i][j] == NULL)
                 {
-                    goto error_handler_coordinates_ij;
+                    goto error_handler_bufferCoordinates_ij;
                 }
             }
         }
 
+        // 0 points out of a 0 points history
+        sco->internal.maxNumberOfPoints = 0;
+
+        sco->internal.historyCoordinates = (double ***)CALLOC(block->nin, sizeof(double **));
+        if (sco->internal.historyCoordinates == NULL)
+        {
+            goto error_handler_historyCoordinates;
+        }
+
+        for (i = 0; i < block->nin; i++)
+        {
+            sco->internal.historyCoordinates[i] = (double **)CALLOC(block->insz[i], sizeof(double *));
+            if (sco->internal.historyCoordinates[i] == NULL)
+            {
+                goto error_handler_historyCoordinates_i;
+            }
+        }
+
         sco->scope.periodCounter = 0;
+
+        // flag to avoid pushing the buffer each time
+        sco->scope.disableBufferUpdate = FALSE;
+        // counter use to delay the history push
+        sco->scope.historyUpdateCounter = 0;
+
         sco->scope.cachedFigureUID = NULL;
         sco->scope.cachedAxeUID = NULL;
-        sco->scope.cachedPolylinesUIDs = (char **)CALLOC(block->insz[0], sizeof(char *));
+        sco->scope.cachedBufferPolylinesUIDs = (char **)CALLOC(block->insz[0], sizeof(char *));
+        sco->scope.cachedHistoryPolylinesUIDs = (char **)CALLOC(block->insz[0], sizeof(char *));
 
         *(block->work) = sco;
     }
@@ -299,22 +358,31 @@ static sco_data *getScoData(scicos_block * block)
      * Error management (out of normal flow)
      */
 
-error_handler_coordinates_ij:
+error_handler_historyCoordinates_i:
+    for (j = 0; j < i; j++)
+    {
+        FREE(sco->internal.historyCoordinates[i]);
+    }
+    FREE(sco->internal.historyCoordinates);
+error_handler_historyCoordinates:
+    i = block->nin - 1;
+    j = block->insz[i] - 1;
+error_handler_bufferCoordinates_ij:
     for (k = 0; k < i; k++)
     {
         for (l = 0; l < j; l++)
         {
-            FREE(sco->internal.coordinates[k][l]);
+            FREE(sco->internal.bufferCoordinates[k][l]);
         }
     }
     i = block->nin - 1;
-error_handler_coordinates_i:
+error_handler_bufferCoordinates_i:
     for (j = 0; j < i; j++)
     {
-        FREE(sco->internal.coordinates[i]);
+        FREE(sco->internal.bufferCoordinates[i]);
     }
-    FREE(sco->internal.coordinates);
-error_handler_coordinates:
+    FREE(sco->internal.bufferCoordinates);
+error_handler_bufferCoordinates:
     FREE(sco);
 error_handler_sco:
     // allocation error
@@ -333,15 +401,22 @@ static void freeScoData(scicos_block * block)
         {
             for (j = 0; j < block->insz[i]; j++)
             {
-                FREE(sco->internal.coordinates[i][j]);
+                if (sco->internal.historyCoordinates[i][j] != NULL)
+                {
+                    FREE(sco->internal.historyCoordinates[i][j]);
+                }
+                FREE(sco->internal.bufferCoordinates[i][j]);
             }
-            FREE(sco->internal.coordinates[i]);
+            FREE(sco->internal.historyCoordinates[i]);
+            FREE(sco->internal.bufferCoordinates[i]);
         }
-        FREE(sco->internal.coordinates);
+        FREE(sco->internal.historyCoordinates);
+        FREE(sco->internal.bufferCoordinates);
 
         for (i = 0; i < block->insz[0]; i++)
         {
-            FREE(sco->scope.cachedPolylinesUIDs[i]);
+            FREE(sco->scope.cachedHistoryPolylinesUIDs[i]);
+            FREE(sco->scope.cachedBufferPolylinesUIDs[i]);
         }
         FREE(sco->scope.cachedAxeUID);
 
@@ -350,47 +425,71 @@ static void freeScoData(scicos_block * block)
     }
 }
 
-static sco_data *reallocScoData(scicos_block * block, int numberOfPoints)
+static sco_data *reallocHistoryBuffer(scicos_block * block, int numberOfPoints)
 {
     sco_data *sco = (sco_data *) * (block->work);
-    int i, j;
+    int i;
 
     double *ptr;
-    int setLen;
+    int allocatedNumberOfPoints;
+
     int previousNumberOfPoints = sco->internal.maxNumberOfPoints;
-    int newPoints = numberOfPoints - previousNumberOfPoints;
+    int numberOfCopiedPoints = numberOfPoints - sco->internal.maxNumberOfPoints;
 
-    for (i = 0; i < block->nin; i++)
+    double *buffer;
+    int bufferNumberOfPoints = block->ipar[2];
+    int bufferNewPointInc;
+
+    if (previousNumberOfPoints == 0)
     {
-        for (j = 0; j < block->insz[i]; j++)
+        allocatedNumberOfPoints = numberOfPoints;
+        bufferNewPointInc = 0;
+    }
+    else
+    {
+        allocatedNumberOfPoints = numberOfPoints - 1;
+        bufferNewPointInc = 1;
+    }
+
+    if (sco->scope.historyUpdateCounter <= 0)
+    {
+        if (numberOfPoints > HISTORY_POINTS_THRESHOLD)
         {
-            ptr = (double *)REALLOC(sco->internal.coordinates[i][j], 3 * numberOfPoints * sizeof(double));
-            if (ptr == NULL)
-            {
-                goto error_handler;
-            }
+            sco->scope.disableBufferUpdate = TRUE;
+            sco->scope.historyUpdateCounter = numberOfPoints / HISTORY_POINTS_THRESHOLD;
+        }
+        else
+        {
+            sco->scope.disableBufferUpdate = FALSE;
+            sco->scope.historyUpdateCounter = 0;
+        }
+    }
 
-            // clear the last points, the Z-axis values
-            memset(ptr + 2 * numberOfPoints, 0, numberOfPoints * sizeof(double));
+    for (i = 0; i < block->insz[0]; i++)
+    {
+        ptr = (double *)MALLOC(3 * allocatedNumberOfPoints * sizeof(double));
+        if (ptr == NULL)
+        {
+            goto error_handler;
+        }
 
-            // memcpy existing Y-axis values (use memmove to handle memory overlapping)
-            memmove(ptr + numberOfPoints, ptr + previousNumberOfPoints, previousNumberOfPoints * sizeof(double));
+        // memcpy existing X-axis values from the history
+        memcpy(ptr, sco->internal.historyCoordinates[0][i], previousNumberOfPoints * sizeof(double));
+        // memcpy existing Y-axis values from the history
+        memcpy(ptr + allocatedNumberOfPoints, sco->internal.historyCoordinates[0][i] + previousNumberOfPoints, previousNumberOfPoints * sizeof(double));
+        // clear the last points, the Z-axis values
+        memset(ptr + 2 * allocatedNumberOfPoints, 0, allocatedNumberOfPoints * sizeof(double));
 
-            // then set the last points to the last values for Y-axis and X-axis values
-            for (setLen = newPoints - 1; setLen >= 0; setLen--)
-            {
-                ptr[numberOfPoints + previousNumberOfPoints + setLen] = ptr[numberOfPoints + previousNumberOfPoints - 1];
-            }
-            for (setLen = newPoints - 1; setLen >= 0; setLen--)
-            {
-                ptr[previousNumberOfPoints + setLen] = ptr[previousNumberOfPoints - 1];
-            }
+        // then set the last points to the last values for X-axis and Y-axis values from the buffer points
+        buffer = sco->internal.bufferCoordinates[0][i];
+        memcpy(ptr + previousNumberOfPoints, buffer + bufferNewPointInc, (numberOfCopiedPoints - bufferNewPointInc) * sizeof(double));
+        memcpy(ptr + allocatedNumberOfPoints + previousNumberOfPoints, buffer + bufferNumberOfPoints + bufferNewPointInc, (numberOfCopiedPoints - bufferNewPointInc) * sizeof(double));
 
-            sco->internal.coordinates[i][j] = ptr;
-        }
+        FREE(sco->internal.historyCoordinates[0][i]);
+        sco->internal.historyCoordinates[0][i] = ptr;
     }
 
-    sco->internal.maxNumberOfPoints = numberOfPoints;
+    sco->internal.maxNumberOfPoints = allocatedNumberOfPoints;
     return sco;
 
 error_handler:
@@ -400,13 +499,37 @@ error_handler:
     return NULL;
 }
 
+static void setBuffersCoordinates(scicos_block* block, double* coordinates, const int numberOfPoints,
+                                  const int bufferPoints, const double t, const double value)
+{
+    int setLen;
+    sco_data *sco = (sco_data *) * (block->work);
+
+    if (sco->scope.disableBufferUpdate == TRUE)
+    {
+        coordinates[numberOfPoints] = t;
+        coordinates[bufferPoints + numberOfPoints] = value;
+        return;
+    }
+
+    // X-axis values first
+    for (setLen = numberOfPoints; setLen < bufferPoints; setLen++)
+    {
+        coordinates[setLen] = t;
+    }
+    // then Y-axis values
+    for (setLen = numberOfPoints; setLen < bufferPoints; setLen++)
+    {
+        coordinates[bufferPoints + setLen] = value;
+    }
+    // then Z-axis values (always clear'ed)
+}
+
 static void appendData(scicos_block * block, int input, double t, double *data)
 {
     int i;
 
     sco_data *sco = (sco_data *) * (block->work);
-    int maxNumberOfPoints = sco->internal.maxNumberOfPoints;
-    int numberOfPoints = sco->internal.numberOfPoints;
 
     /*
      * Handle the case where the t is greater than the data_bounds
@@ -415,8 +538,26 @@ static void appendData(scicos_block * block, int input, double t, double *data)
     {
         sco->scope.periodCounter++;
 
-        numberOfPoints = 0;
-        sco->internal.numberOfPoints = 0;
+        // set the buffer coordinates to the last point
+        for (i = 0; i < block->insz[input]; i++)
+        {
+            sco->internal.bufferCoordinates[input][i][0] = sco->internal.bufferCoordinates[input][i][sco->internal.numberOfPoints - 1];
+            sco->internal.bufferCoordinates[input][i][block->ipar[2]] = sco->internal.bufferCoordinates[input][i][block->ipar[2] + sco->internal.numberOfPoints - 1];
+        }
+        sco->internal.numberOfPoints = 1;
+
+        // clear the history coordinates
+        sco->internal.maxNumberOfPoints = 0;
+        for (i = 0; i < block->insz[input]; i++)
+        {
+            if (sco->internal.historyCoordinates[input][i] != NULL)
+            {
+                FREE(sco->internal.historyCoordinates[input][i]);
+                sco->internal.historyCoordinates[input][i] = NULL;
+            }
+        }
+
+        // configure scope setting
         if (setPolylinesBounds(block, input, sco->scope.periodCounter) == FALSE)
         {
             set_block_error(-5);
@@ -428,14 +569,24 @@ static void appendData(scicos_block * block, int input, double t, double *data)
     /*
      * Handle the case where the scope has more points than maxNumberOfPoints
      */
-    if (sco != NULL && numberOfPoints >= maxNumberOfPoints)
+    if (sco != NULL && sco->internal.numberOfPoints >= block->ipar[2])
     {
-        // on a full scope, re-alloc
+        int maxNumberOfPoints = sco->internal.maxNumberOfPoints;
+
+        // on a full scope, re-alloc history coordinates
         maxNumberOfPoints = maxNumberOfPoints + block->ipar[2];
-        sco = reallocScoData(block, maxNumberOfPoints);
+        sco = reallocHistoryBuffer(block, maxNumberOfPoints);
+
+        // set the buffer coordinates to the last point
+        for (i = 0; i < block->insz[input]; i++)
+        {
+            sco->internal.bufferCoordinates[input][i][0] = sco->internal.bufferCoordinates[input][i][block->ipar[2] - 1];
+            sco->internal.bufferCoordinates[input][i][block->ipar[2]] = sco->internal.bufferCoordinates[input][i][2 * block->ipar[2] - 1];
+        }
+        sco->internal.numberOfPoints = 1;
 
         // reconfigure related graphic objects
-        if (setPolylinesBuffers(block, input, maxNumberOfPoints) == FALSE)
+        if (pushHistory(block, input, sco->internal.maxNumberOfPoints) == FALSE)
         {
             set_block_error(-5);
             freeScoData(block);
@@ -448,23 +599,10 @@ static void appendData(scicos_block * block, int input, double t, double *data)
      */
     if (sco != NULL)
     {
-        int setLen;
-
         for (i = 0; i < block->insz[input]; i++)
         {
-            // X-axis values first
-            for (setLen = maxNumberOfPoints - numberOfPoints - 1; setLen >= 0; setLen--)
-            {
-                sco->internal.coordinates[input][i][numberOfPoints + setLen] = t;
-            }
-
-            // then Y-axis values
-            for (setLen = maxNumberOfPoints - numberOfPoints - 1; setLen >= 0; setLen--)
-            {
-                sco->internal.coordinates[input][i][maxNumberOfPoints + numberOfPoints + setLen] = data[i];
-            }
-
-            // do not update Z-axis values, always cleared
+            const double value = data[i];
+            setBuffersCoordinates(block, sco->internal.bufferCoordinates[input][i], sco->internal.numberOfPoints, block->ipar[2], t, value);
         }
 
         sco->internal.numberOfPoints++;
@@ -482,7 +620,7 @@ static BOOL pushData(scicos_block * block, int input, int row)
 
     pFigureUID = getFigure(block);
     pAxeUID = getAxe(pFigureUID, block, input);
-    pPolylineUID = getPolyline(pAxeUID, block, row);
+    pPolylineUID = getPolyline(pAxeUID, block, row, FALSE);
 
     sco = getScoData(block);
     if (sco == NULL)
@@ -490,10 +628,16 @@ static BOOL pushData(scicos_block * block, int input, int row)
         return FALSE;
     }
 
+    // do not push any data if disabled
+    if (sco->scope.disableBufferUpdate == TRUE)
+    {
+        return TRUE;
+    }
+
     // select the right input and row
-    data = sco->internal.coordinates[input][row];
+    data = sco->internal.bufferCoordinates[input][row];
 
-    return setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_COORDINATES__, data, jni_double_vector, sco->internal.maxNumberOfPoints);
+    return setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_COORDINATES__, data, jni_double_vector, block->ipar[2]);
 }
 
 /*****************************************************************************
@@ -655,7 +799,11 @@ static char *getAxe(char const* pFigureUID, scicos_block * block, int input)
         // allocate the polylines through the getter
         for (i = 0; i < block->insz[input]; i++)
         {
-            getPolyline(pAxe, block, i);
+            getPolyline(pAxe, block, i, TRUE);
+        }
+        for (i = 0; i < block->insz[input]; i++)
+        {
+            getPolyline(pAxe, block, i, FALSE);
         }
     }
 
@@ -670,13 +818,17 @@ static char *getAxe(char const* pFigureUID, scicos_block * block, int input)
     return sco->scope.cachedAxeUID;
 }
 
-static char *getPolyline(char *pAxeUID, scicos_block * block, int row)
+static char *getPolyline(char *pAxeUID, scicos_block * block, int row, BOOL history)
 {
     char *pPolyline;
     BOOL b__true = TRUE;
 
     int color;
 
+    char** polylinesUIDs;
+    int polylineIndex;
+    int polylineDefaultNumElement;
+
     sco_data *sco = (sco_data *) * (block->work);
 
     // assert the sco is not NULL
@@ -685,13 +837,26 @@ static char *getPolyline(char *pAxeUID, scicos_block * block, int row)
         return NULL;
     }
 
+    if (!history)
+    {
+        polylinesUIDs = sco->scope.cachedBufferPolylinesUIDs;
+        polylineIndex = block->insz[0] + row;
+        polylineDefaultNumElement = block->ipar[2];
+    }
+    else
+    {
+        polylinesUIDs = sco->scope.cachedHistoryPolylinesUIDs;
+        polylineIndex = row;
+        polylineDefaultNumElement = 0;
+    }
+
     // fast path for an existing object
-    if (sco->scope.cachedPolylinesUIDs != NULL && sco->scope.cachedPolylinesUIDs[row] != NULL)
+    if (polylinesUIDs != NULL && polylinesUIDs[row] != NULL)
     {
-        return sco->scope.cachedPolylinesUIDs[row];
+        return polylinesUIDs[row];
     }
 
-    pPolyline = findChildWithKindAt(pAxeUID, __GO_POLYLINE__, row);
+    pPolyline = findChildWithKindAt(pAxeUID, __GO_POLYLINE__, polylineIndex);
 
     /*
      * Allocate if necessary
@@ -717,7 +882,7 @@ static char *getPolyline(char *pAxeUID, scicos_block * block, int row)
          * Default setup (will crash if removed)
          */
         {
-            int polylineSize[2] = { 1, block->ipar[2] };
+            int polylineSize[2] = { 1, polylineDefaultNumElement };
             setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_NUM_ELEMENTS_ARRAY__, polylineSize, jni_int_vector, 2);
         }
 
@@ -743,15 +908,34 @@ static char *getPolyline(char *pAxeUID, scicos_block * block, int row)
     /*
      * then cache with local storage
      */
-    if (pPolyline != NULL && sco->scope.cachedPolylinesUIDs != NULL && sco->scope.cachedPolylinesUIDs[row] == NULL)
+    if (pPolyline != NULL && polylinesUIDs != NULL && polylinesUIDs[row] == NULL)
     {
-        sco->scope.cachedPolylinesUIDs[row] = strdup(pPolyline);
+        polylinesUIDs[row] = strdup(pPolyline);
         releaseGraphicObjectProperty(__GO_PARENT__, pPolyline, jni_string, 1);
     }
-    return sco->scope.cachedPolylinesUIDs[row];
+    return polylinesUIDs[row];
 }
 
-static BOOL setPolylinesBuffers(scicos_block * block, int input, int maxNumberOfPoints)
+static void deleteBufferPolylines(scicos_block * block)
+{
+    int i, j;
+
+    char *pPolylineUID;
+
+    sco_data *sco;
+
+    sco = getScoData(block);
+    for (i = 0; i < block->nin; i++)
+    {
+        for (j = 0; j < block->insz[i]; j++)
+        {
+            pPolylineUID = sco->scope.cachedBufferPolylinesUIDs[j];
+            deleteGraphicObject(pPolylineUID);
+        }
+    }
+}
+
+static BOOL pushHistory(scicos_block * block, int input, int maxNumberOfPoints)
 {
     int i;
 
@@ -759,16 +943,33 @@ static BOOL setPolylinesBuffers(scicos_block * block, int input, int maxNumberOf
     char *pAxeUID;
     char *pPolylineUID;
 
+    double *data;
+    sco_data *sco;
+
     BOOL result = TRUE;
     int polylineSize[2] = { 1, maxNumberOfPoints };
 
+    sco = getScoData(block);
     pFigureUID = getFigure(block);
     pAxeUID = getAxe(pFigureUID, block, input);
 
+    // push the data only if the counter == 0, decrement the counter if positive
+    if (sco->scope.historyUpdateCounter > 0)
+    {
+        sco->scope.historyUpdateCounter--;
+    }
+    if (sco->scope.historyUpdateCounter > 0)
+    {
+        return result;
+    }
+
     for (i = 0; i < block->insz[input]; i++)
     {
-        pPolylineUID = getPolyline(pAxeUID, block, i);
+        pPolylineUID = getPolyline(pAxeUID, block, i, TRUE);
         result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_NUM_ELEMENTS_ARRAY__, polylineSize, jni_int_vector, 2);
+
+        data = sco->internal.historyCoordinates[input][i];
+        result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_COORDINATES__, data, jni_double_vector, maxNumberOfPoints);
     }
 
     return result;
diff --git a/scilab/modules/xcos/tests/nonreg_tests/bug_12057.dia.ref b/scilab/modules/xcos/tests/nonreg_tests/bug_12057.dia.ref
new file mode 100644 (file)
index 0000000..99636e8
--- /dev/null
@@ -0,0 +1,28 @@
+// =============================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2013 - Scilab Enterprises - Clément DAVID
+//
+//  This file is distributed under the same license as the Scilab package.
+// =============================================================================
+// <-- XCOS TEST -->
+//
+// <-- Non-regression test for bug 12057 -->
+//
+// <-- Bugzilla URL -->
+// http://bugzilla.scilab.org/show_bug.cgi?id=12057
+//
+// <-- Short Description -->
+// Scopes with big scope buffer size simulation was much more slower.
+// 
+// This test check cscope and cmscope huge-buffer (more than 4k points)
+// optimization.
+assert_checktrue(importXcosDiagram(SCI + "/modules/xcos/tests/nonreg_tests/bug_12057_cscope.xcos"));
+timer();
+xcos_simulate(scs_m, 4);
+t = timer();
+assert_checktrue(t < 60);
+assert_checktrue(importXcosDiagram(SCI + "/modules/xcos/tests/nonreg_tests/bug_12057_cmscope.xcos"));
+timer();
+xcos_simulate(scs_m, 4);
+t = timer();
+assert_checktrue(t < 60);
diff --git a/scilab/modules/xcos/tests/nonreg_tests/bug_12057.tst b/scilab/modules/xcos/tests/nonreg_tests/bug_12057.tst
new file mode 100644 (file)
index 0000000..e24dc24
--- /dev/null
@@ -0,0 +1,33 @@
+// =============================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2013 - Scilab Enterprises - Clément DAVID
+//
+//  This file is distributed under the same license as the Scilab package.
+// =============================================================================
+
+// <-- XCOS TEST -->
+//
+// <-- Non-regression test for bug 12057 -->
+//
+// <-- Bugzilla URL -->
+// http://bugzilla.scilab.org/show_bug.cgi?id=12057
+//
+// <-- Short Description -->
+// Scopes with big scope buffer size simulation was much more slower.
+// 
+// This test check cscope and cmscope huge-buffer (more than 4k points)
+// optimization.
+
+assert_checktrue(importXcosDiagram(SCI + "/modules/xcos/tests/nonreg_tests/bug_12057_cscope.xcos"));
+timer();
+xcos_simulate(scs_m, 4);
+t = timer();
+
+assert_checktrue(t < 60);
+
+assert_checktrue(importXcosDiagram(SCI + "/modules/xcos/tests/nonreg_tests/bug_12057_cmscope.xcos"));
+timer();
+xcos_simulate(scs_m, 4);
+t = timer();
+
+assert_checktrue(t < 60);
diff --git a/scilab/modules/xcos/tests/nonreg_tests/bug_12057_cmscope.xcos b/scilab/modules/xcos/tests/nonreg_tests/bug_12057_cmscope.xcos
new file mode 100644 (file)
index 0000000..51ef9a2
Binary files /dev/null and b/scilab/modules/xcos/tests/nonreg_tests/bug_12057_cmscope.xcos differ
diff --git a/scilab/modules/xcos/tests/nonreg_tests/bug_12057_cscope.xcos b/scilab/modules/xcos/tests/nonreg_tests/bug_12057_cscope.xcos
new file mode 100644 (file)
index 0000000..3fb53a1
Binary files /dev/null and b/scilab/modules/xcos/tests/nonreg_tests/bug_12057_cscope.xcos differ
index 52c6e99..bdf7ced 100644 (file)
@@ -1,5 +1,6 @@
 // =============================================================================
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2013 - Scilab Enterprises - Clément DAVID
 // Copyright (C) 2011 - DIGITEO - Clément DAVID
 //
 //  This file is distributed under the same license as the Scilab package.
@@ -32,11 +33,10 @@ function assert_checkcmscope()
     assert_checkequal(a1.y_label.text, "y");
     assert_checkequal(a2.y_label.text, "y");
     assert_checkequal(a3.y_label.text, "y");
-    // check removed due to junk data at the end
-    // assert_checkequal(size(p11.data), [299 2]);
-    // assert_checkequal(size(p12.data), [299 2]);
-    // assert_checkequal(size(p21.data), [299 2]);
-    // assert_checkequal(size(p31.data), [299 2]);
+    assert_checkequal(size(p11.data), [299 2]);
+    assert_checkequal(size(p12.data), [299 2]);
+    assert_checkequal(size(p21.data), [299 2]);
+    assert_checkequal(size(p31.data), [299 2]);
 endfunction
 assert_checkcmscope();
 // Simulate again to check multi-simulations cases
index bf63697..44907fb 100644 (file)
@@ -1,5 +1,6 @@
 // =============================================================================
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2013 - Scilab Enterprises - Clément DAVID
 // Copyright (C) 2011 - DIGITEO - Clément DAVID
 //
 //  This file is distributed under the same license as the Scilab package.
@@ -43,11 +44,10 @@ function assert_checkcmscope()
     assert_checkequal(a2.y_label.text, "y");
     assert_checkequal(a3.y_label.text, "y");
     
-    // check removed due to junk data at the end
-    // assert_checkequal(size(p11.data), [299 2]);
-    // assert_checkequal(size(p12.data), [299 2]);
-    // assert_checkequal(size(p21.data), [299 2]);
-    // assert_checkequal(size(p31.data), [299 2]);
+    assert_checkequal(size(p11.data), [299 2]);
+    assert_checkequal(size(p12.data), [299 2]);
+    assert_checkequal(size(p21.data), [299 2]);
+    assert_checkequal(size(p31.data), [299 2]);
 endfunction
 assert_checkcmscope();
 
index 7ed6152..fc43d98 100644 (file)
@@ -1,5 +1,6 @@
 // =============================================================================
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2013 - Scilab Enterprises - Clément DAVID
 // Copyright (C) 2011 - DIGITEO - Clément DAVID
 //
 //  This file is distributed under the same license as the Scilab package.
@@ -22,11 +23,10 @@ function assert_checkcscope()
     assert_checkequal(a.data_bounds, [30 -2 ; 60 3]);
     assert_checkequal(a.x_label.text, "t");
     assert_checkequal(a.y_label.text, "y");
-    // check removed due to junk data at the end
-    // assert_checkequal(size(p1.data), [315 2]);
-    // assert_checkequal(size(p2.data), [315 2]);
-    // assert_checkequal(size(p3.data), [315 2]);
-    // assert_checkequal(size(p4.data), [315 2]);
+    assert_checkequal(size(p1.data), [301 2]);
+    assert_checkequal(size(p2.data), [301 2]);
+    assert_checkequal(size(p3.data), [301 2]);
+    assert_checkequal(size(p4.data), [301 2]);
     assert_checkequal(p1.polyline_style, 1);
     assert_checkequal(p2.polyline_style, 1);
     assert_checkequal(p3.polyline_style, 1);
index 85543f8..7f7b6fc 100644 (file)
@@ -1,5 +1,6 @@
 // =============================================================================
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2013 - Scilab Enterprises - Clément DAVID
 // Copyright (C) 2011 - DIGITEO - Clément DAVID
 //
 //  This file is distributed under the same license as the Scilab package.
@@ -31,11 +32,10 @@ function assert_checkcscope()
     assert_checkequal(a.x_label.text, "t");
     assert_checkequal(a.y_label.text, "y");
 
-    // check removed due to junk data at the end
-    // assert_checkequal(size(p1.data), [315 2]);
-    // assert_checkequal(size(p2.data), [315 2]);
-    // assert_checkequal(size(p3.data), [315 2]);
-    // assert_checkequal(size(p4.data), [315 2]);
+    assert_checkequal(size(p1.data), [301 2]);
+    assert_checkequal(size(p2.data), [301 2]);
+    assert_checkequal(size(p3.data), [301 2]);
+    assert_checkequal(size(p4.data), [301 2]);
 
     assert_checkequal(p1.polyline_style, 1);
     assert_checkequal(p2.polyline_style, 1);