Thread safetiness of IBEX Functions

Hi all,

I am interested in parallelizing the utilization of the same contractor built with static ibex::Function as discussed in:

http://www.ibex-lib.org/node/16

A quick and dirty test using OpenMP throws a segmentation fault at runtime (in principle, you just have to pass -fopenmp to your compiler) :

class C : ibex::Ctc { 

	// Identity contractor

public: 
	void contract(ibex::IntervalVector& box) { 
		f.backward(ibex::Interval::ZERO, box);
	} 

	static ibex::Function f = ibex::Function("x1", "x2", "x1+x2"); 
}; 

ibex::Function C::f("x1", "x2", "x1+x2"); 

int main() { 

	C c; 
	std::vector boxes; 

	for (int i = 0; i < 10000; i++)
		boxes.push_back(ibex::IntervalVector(2, ibex::Interval(-1, 2))); 

#pragma omp parallel for 
	for (int i = 0; i < 10000; i++) 
		c.contract(boxes[i]); 

	return 0; 
}


While the same program without the shared static Function runs perfectly fine:


class C : ibex::Ctc {

    // Identity contractor

public:

    void contract(ibex::IntervalVector& box) {
        f.backward(ibex::Interval::ZERO, box);
    }

    ibex::Function f = ibex::Function("x1", "x2", "x1+x2");

};

int main() {

    C c;
    std::vector boxes;

    for (int i = 0; i < 10000; i++)
        boxes.push_back(ibex::IntervalVector(2, ibex::Interval(-1, 2)));

#pragma omp parallel for
    for (int i = 0; i < 10000; i++)
        c.contract(boxes[i]);

    return 0;
}

Before I dive into the internals of ibex::Function, do you have any idea of the amount of work required to make the use of ibex::Functions thread-safe in a static context? Regards PS:I can't figure out how to properly format code

 

Hi Jeremy,

 

So far, "Function" is not thread-safe. Even your second variant, using a non-static field, is not safe because the same Function object is eventually called by different threads.

We will try to fix that soon (if you want so, please post an "enhancement" issue in git: https://github.com/ibex-team/ibex-lib/issues);

Meanwhile, you have no choice: duplicate functions. Worse, the function creation is not thread-safe neither so you have to make it "atomic".

Here is the code. To see the difference, I have added a delay of 1s in the contract function. With the #pragma, it takes ~1s while it takes ~10s without.

Regards,

Gilles

#include "ibex.h"

using namespace ibex;

class C : Ctc {
public:

    C() {

        #pragma omp critical
        {
            f = new Function("x","y","x+y");
        }
    }

    void contract(IntervalVector& box) {
        sleep(1);
        f->backward(Interval::ZERO, box);
    }

    Function* f;
};

int main() {

    C ctc[10];
    std::vector<IntervalVector> boxes;

    for (int i = 0; i < 10; i++) {
        boxes.push_back(IntervalVector(2, Interval(-1, 2)));
    }

#pragma omp parallel for
    for (int i = 0; i < 10; i++) {
        ctc[i].contract(boxes[i]);
    }

    return 0;
}

 

PS:I can't figure out how to properly format code

To format the code:

-chose "Formatted" font instead of "Normal"

-Increase indent of the block

-select "Full HTML" in Text format (below the editor window)

Regards,

Gilles

Hi Gilles, thank you for the answers, it makes sense. I am going this way for now, the speed up is already great!
Regards,
Jeremy