IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Aug 13, 2008, 5:25:55 PM (18 years ago)
Author:
Paul Price
Message:

Adding threading for pmSubtractionConvolve. This was more difficult than for the others because the threads are working on a common image. Turns out that making child images using psImageSubset is not thread-safe: the image (which all threads are using) is modified. Wrapped those calls up in mutexes, and now threading seems to work fine.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/imcombine/pmSubtraction.c

    r18962 r19059  
    2121#include "pmSubtractionStamps.h"
    2222#include "pmSubtractionEquation.h"
     23#include "pmSubtractionThreads.h"
    2324
    2425#include "pmSubtraction.h"
     
    2829#define PIXEL_LIST_BUFFER 100           // Number of entries to add to pixel list at a time
    2930#define MIN_SAMPLE_STATS    7           // Minimum number to use sample statistics; otherwise use quartiles
     31
    3032
    3133//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     
    213215                                  region.y0 - size, region.y1 + size); // Add a border
    214216
    215     // Casting away const so psImageSubset can add the child
     217    // Casting away const
     218    psMutexLock((psImage*)image);
    216219    psImage *subImage = psImageSubset((psImage*)image, border); // Subimage to convolve
     220    psMutexUnlock((psImage*)image);
     221
     222    // Casting away const
     223    psMutexLock((psImage*)mask);
    217224    psImage *subMask = mask ? psImageSubset((psImage*)mask, border) : NULL; // Subimage mask
     225    psMutexUnlock((psImage*)mask);
     226
    218227    psImage *convolved = psImageConvolveFFT(NULL, subImage, subMask, maskVal, kernel); // Convolution
     228
     229    psMutexLock((psImage*)image);
    219230    psFree(subImage);
     231    psMutexUnlock((psImage*)image);
     232
     233    psMutexLock((psImage*)mask);
    220234    psFree(subMask);
     235    psMutexUnlock((psImage*)mask);
    221236
    222237    // Now, we have to chop off the borders, and stick it in where it belongs
     238    // No locking because we own this one
    223239    psImage *subConv = psImageSubset(convolved, psRegionSet(size, -size, size, -size)); // Cut off the edges
     240
     241    psMutexLock(target);
    224242    psImage *subTarget = psImageSubset(target, region); // Target for this subregion
     243    psMutexUnlock(target);
    225244    if (background != 0.0) {
    226245        psBinaryOp(subTarget, subConv, "+", psScalarAlloc(background, PS_TYPE_F32));
     
    233252    psFree(subConv);
    234253    psFree(convolved);
     254    psMutexLock(target);
    235255    psFree(subTarget);
     256    psMutexUnlock(target);
    236257    return;
    237258}
     
    285306        // Use Fast Fourier Transform to do the convolution
    286307        // This provides a big speed-up for large kernels
     308
    287309        convolveFFT(convImage, image, subMask, maskVal, *kernelImage, region, background, kernels->size);
    288310        if (weight) {
     
    711733
    712734
     735// XXX Put kernelImage, kernelWeight and polyValues on thread-dependent data
     736static bool subtractionConvolvePatch(int numCols, int numRows, int x0, int y0,
     737                                     pmReadout *out1, pmReadout *out2, psImage *convMask,
     738                                     const pmReadout *ro1, const pmReadout *ro2, const psImage *subMask,
     739                                     psMaskType blank, psMaskType maskSource, psMaskType maskTarget,
     740                                     const psRegion *region, const pmSubtractionKernels *kernels,
     741                                     bool doBG, bool useFFT)
     742{
     743    int size = kernels->size;           // Half-size of kernel
     744    int xMin = region->x0, xMax = region->x1, yMin = region->y0, yMax = region->y1; // Bounds of patch
     745
     746    // Size to use when calculating normalised coordinates (different from actual size when convolving
     747    // subimage)
     748    int xNormSize = (kernels->numCols > 0 ? kernels->numCols : numCols);
     749    int yNormSize = (kernels->numRows > 0 ? kernels->numRows : numRows);
     750
     751    // Normalised coordinates
     752    float yNorm = 2.0 * (float)(yMin + y0 + size + 1 - yNormSize/2.0) / (float)yNormSize; // Normalised coord
     753    float xNorm = 2.0 * (float)(xMin + x0 + size + 1 - xNormSize/2.0) / (float)xNormSize; // Normalised coord
     754
     755    psKernel *kernelImage = NULL;       // Kernel for the images
     756    psKernel *kernelWeight = NULL;      // Kernel for the weight maps
     757
     758    // Only generate polynomial values every kernel footprint, since we have already assumed
     759    // (with the stamps) that it does not vary rapidly on this scale.
     760    psImage *polyValues = p_pmSubtractionPolynomial(NULL, kernels->spatialOrder,
     761                                                    xNorm, yNorm); // Pre-calculated polynomial values
     762    float background = doBG ? p_pmSubtractionSolutionBackground(kernels, polyValues) : 0.0; // Background term
     763
     764    if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
     765        convolveRegion(out1->image, out1->weight, &kernelImage, &kernelWeight, ro1->image, ro1->weight,
     766                       subMask, maskSource, kernels, polyValues, background, *region, useFFT,
     767                       false);
     768    }
     769    if (kernels->mode == PM_SUBTRACTION_MODE_2 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
     770        convolveRegion(out2->image, out2->weight, &kernelImage, &kernelWeight, ro2->image, ro2->weight,
     771                       subMask, maskSource, kernels, polyValues, background, *region, useFFT,
     772                       kernels->mode == PM_SUBTRACTION_MODE_DUAL);
     773    }
     774
     775    psFree(kernelImage);
     776    psFree(kernelWeight);
     777    psFree(polyValues);
     778
     779    // Propagate the mask
     780    if (subMask) {
     781        for (int y = yMin; y < yMax; y++) {
     782            for (int x = xMin; x < xMax; x++) {
     783                if (subMask->data.PS_TYPE_MASK_DATA[y][x] & maskTarget) {
     784                    convMask->data.PS_TYPE_MASK_DATA[y][x] |= blank;
     785                }
     786            }
     787        }
     788    }
     789
     790    return true;
     791}
     792
     793bool pmSubtractionConvolveThread(const psThreadJob *job)
     794{
     795    PS_ASSERT_THREAD_JOB_NON_NULL(job, false);
     796
     797    psArray *args = job->args;          // Arguments
     798    int numCols = PS_SCALAR_VALUE(args->data[0], S32); // Number of columns
     799    int numRows = PS_SCALAR_VALUE(args->data[1], S32); // Number of rows
     800    int x0 = PS_SCALAR_VALUE(args->data[2], S32); // Offset in x
     801    int y0 = PS_SCALAR_VALUE(args->data[3], S32); // Offset in x
     802    pmReadout *out1 = args->data[4];    // Output readout 1
     803    pmReadout *out2 = args->data[5];    // Output readout 2
     804    psImage *convMask = args->data[6];  // Output convolved mask
     805    const pmReadout *ro1 = args->data[7]; // Input readout 1
     806    const pmReadout *ro2 = args->data[8]; // Input readout 2
     807    const psImage *subMask = args->data[9]; // Subtraction mask
     808    psMaskType blank = PS_SCALAR_VALUE(args->data[10], U8); // Output mask value
     809    psMaskType maskSource = PS_SCALAR_VALUE(args->data[11], U8); // Mask value corresponding to source image
     810    psMaskType maskTarget = PS_SCALAR_VALUE(args->data[12], U8); // Mask value corresponding to target image
     811    const psRegion *region = args->data[13]; // Region to convolve
     812    const pmSubtractionKernels *kernels = args->data[14]; // Kernels
     813    bool doBG = PS_SCALAR_VALUE(args->data[15], U8); // Do background subtraction?
     814    bool useFFT = PS_SCALAR_VALUE(args->data[16], U8); // Use FFT for convolution?
     815
     816    return subtractionConvolvePatch(numCols, numRows, x0, y0, out1, out2, convMask,
     817                                    ro1, ro2, subMask, blank, maskSource, maskTarget,
     818                                    region, kernels, doBG, useFFT);
     819}
    713820
    714821bool pmSubtractionConvolve(pmReadout *out1, pmReadout *out2, const pmReadout *ro1, const pmReadout *ro2,
     
    767874    }
    768875
     876    bool threaded = pmSubtractionThreaded(); // Running threaded?
     877
    769878    // Outputs
    770879    psImage *convImage1 = NULL, *convWeight1 = NULL; // Convolved image and weight from input 1
     
    773882        if (!convImage1) {
    774883            convImage1 = out1->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     884            if (threaded) {
     885                psMutexInit(convImage1);
     886            }
    775887        }
    776888        if (weight1) {
    777889            if (!out1->weight) {
    778890                out1->weight = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     891                if (threaded) {
     892                    psMutexInit(out1->weight);
     893                }
    779894            }
    780895            convWeight1 = out1->weight;
     
    787902        if (!convImage2) {
    788903            convImage2 = out2->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     904            if (threaded) {
     905                psMutexInit(convImage2);
     906            }
    789907        }
    790908        if (weight2) {
    791909            if (!out2->weight) {
    792910                out2->weight = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     911                if (threaded) {
     912                    psMutexInit(out2->weight);
     913                }
    793914            }
    794915            convWeight2 = out2->weight;
     
    833954        yMax = PS_MIN(region->y1, yMax);
    834955    }
    835 
    836     // Size to use when calculating normalised coordinates (different from actual size when convolving
    837     // subimage)
    838     int xNormSize = (kernels->numCols > 0 ? kernels->numCols : numCols);
    839     int yNormSize = (kernels->numRows > 0 ? kernels->numRows : numRows);
    840956
    841957    psMaskType maskSource;              // Mask these pixels when convolving
     
    858974    }
    859975
     976#if 0
     977    // XXX Use thread-specific data to store these
    860978    psImage *polyValues = NULL;         // Pre-calculated polynomial values
    861979    psKernel *kernelImage = NULL;       // Kernel for the images
    862980    psKernel *kernelWeight = NULL;      // Kernel for the weight maps
     981#endif
    863982
    864983    for (int j = yMin; j < yMax; j += fullSize) {
    865984        int ySubMax = PS_MIN(j + fullSize, yMax); // Range for subregion of interest
    866         float yNorm = 2.0 * (float)(j + y0 + size + 1 - yNormSize/2.0) /
    867             (float)yNormSize; // Normalised coordinate
    868985        for (int i = xMin; i < xMax; i += fullSize) {
    869986            int xSubMax = PS_MIN(i + fullSize, xMax); // Range for subregion of interest
    870             float xNorm = 2.0 * (float)(i + x0 + size + 1 - xNormSize/2.0) /
    871                 (float)xNormSize; // Normalised coordinate
    872 
    873             // Only generate polynomial values every kernel footprint, since we have already assumed
    874             // (with the stamps) that it does not vary rapidly on this scale.
    875             polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, xNorm, yNorm);
    876             float background = doBG ? p_pmSubtractionSolutionBackground(kernels, polyValues) :
    877                 0.0; // Background term
    878             psRegion subRegion = psRegionSet(i, xSubMax, j, ySubMax); // Sub-region to convolve
    879 
    880             if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
    881                 convolveRegion(convImage1, convWeight1, &kernelImage, &kernelWeight, image1, weight1,
    882                                subMask, maskSource, kernels, polyValues, background, subRegion, useFFT,
    883                                false);
     987
     988            psRegion *subRegion = psRegionAlloc(i, xSubMax, j, ySubMax); // Bounds of subtraction
     989            if (threaded) {
     990                psThreadJob *job = psThreadJobAlloc("PSMODULES_SUBTRACTION_CONVOLVE");
     991                psArray *args = job->args;
     992                PS_ARRAY_ADD_SCALAR(args, numCols, PS_TYPE_S32);
     993                PS_ARRAY_ADD_SCALAR(args, numRows, PS_TYPE_S32);
     994                PS_ARRAY_ADD_SCALAR(args, x0, PS_TYPE_S32);
     995                PS_ARRAY_ADD_SCALAR(args, y0, PS_TYPE_S32);
     996                psArrayAdd(args, 1, out1);
     997                psArrayAdd(args, 1, out2);
     998                psArrayAdd(args, 1, convMask);
     999                psArrayAdd(args, 1, (pmReadout*)ro1); // Casting away const
     1000                psArrayAdd(args, 1, (pmReadout*)ro2); // Casting away const
     1001                psArrayAdd(args, 1, (psImage*)subMask); // Casting away const
     1002                PS_ARRAY_ADD_SCALAR(args, blank, PS_TYPE_U8);
     1003                PS_ARRAY_ADD_SCALAR(args, maskSource, PS_TYPE_U8);
     1004                PS_ARRAY_ADD_SCALAR(args, maskTarget, PS_TYPE_U8);
     1005                psArrayAdd(args, 1, subRegion);
     1006                psArrayAdd(args, 1, (pmSubtractionKernels*)kernels); // Casting away const
     1007                PS_ARRAY_ADD_SCALAR(args, doBG, PS_TYPE_U8);
     1008                PS_ARRAY_ADD_SCALAR(args, useFFT, PS_TYPE_U8);
     1009
     1010                if (!psThreadJobAddPending(job)) {
     1011                    psFree(job);
     1012                    return false;
     1013                }
     1014                psFree(job);
     1015            } else {
     1016                subtractionConvolvePatch(numCols, numRows, x0, y0, out1, out2, convMask, ro1, ro2, subMask,
     1017                                         blank, maskSource, maskTarget, subRegion, kernels, doBG, useFFT);
    8841018            }
    885             if (kernels->mode == PM_SUBTRACTION_MODE_2 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
    886                 convolveRegion(convImage2, convWeight2, &kernelImage, &kernelWeight, image2, weight2,
    887                                subMask, maskSource, kernels, polyValues, background, subRegion, useFFT,
    888                                kernels->mode == PM_SUBTRACTION_MODE_DUAL);
    889             }
    890 
    891             // Propagate the mask
    892             if (subMask) {
    893                 for (int y = j; y < ySubMax; y++) {
    894                     for (int x = i; x < xSubMax; x++) {
    895                         if (subMask->data.PS_TYPE_MASK_DATA[y][x] & maskTarget) {
    896                             convMask->data.PS_TYPE_MASK_DATA[y][x] |= blank;
    897                         }
    898                     }
    899                 }
    900             }
    901         }
    902     }
    903     psFree(kernelImage);
    904     psFree(kernelWeight);
    905     psFree(polyValues);
     1019            psFree(subRegion);
     1020        }
     1021    }
     1022
     1023    if (!psThreadPoolWait(true)) {
     1024        psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
     1025        return false;
     1026    }
    9061027
    9071028    // Copy anything that wasn't convolved
Note: See TracChangeset for help on using the changeset viewer.