|
Ublas : |
Subject: Re: [ublas] Move Semantics
From: Nasos Iliopoulos (nasos_i_at_[hidden])
Date: 2009-09-10 20:56:51
>Take the following:
>template<typename MatrixT>
>matrix<double> inv(const matrix_expression<MatrixT>& A)
>{
> matrix<double> B(A().size1(), A().size2());
> //Say a complicated sequence to invert A into B, which can't just return a matrix expression.
>
>return B;
>}
The code I tried it on was:
ublas::vector<double> doubleit(const ublas::vector<double> &m)
{ double<vector> r; r=2.0*m;
return r;
}
So I don't see any reason why it shouldn't work on the inverse. With copy elision what will happen in the code you posted is the following:
(let's say that you do C=inv(A);
A will be of course be passed by reference
B will be created normally.
when B is returned it will be returned with copy elision (i.e. no real copy will happen)
when C is assigned to that, move semantics will kick in since it is assigned to an rvalue and just storage will be swaped (so no copy again).
Haven't tried it to see what a back trace will do, but I may if it is considered by uBlas developers.
> //Now do it with matrix expressions on both sides...
> matrix<double> B = 2 * inv( .5 * A);
so in this case:
0.5*A will first create an expression.
if inv is defined to work on matrix expressions there should be no copy here.
inv will then create the inverse matrix inside it.
the inverse matrix from within inv will return with copy eilision, so no copy will happen
2*... will create a matrix expression.
up to know no unnecessary temporaries exist. From now on though:
B= assigned to this expression will create a temporary that the expression is evaluated into.
So, one unnecssary temporary here. Of course you could do:
B=inv(0.5*A); B*=2.0;
Lastly note this:
matrix<double> B = 2 * inv( .5 * A); will call the copy constructor (not move semantics friendly).
move semantics friendly: matrix<double> B ; B=....
Best Regards
Nasos Iliopoulos
From: jesseperla_at_[hidden]
Date: Thu, 10 Sep 2009 20:05:39 -0400
To: ublas_at_[hidden]
Subject: Re: [ublas] Move Semantics
On Thu, Sep 10, 2009 at 5:43 PM, Nasos Iliopoulos <nasos_i_at_[hidden]> wrote:
Jesse,
>I don't know that much about this stuff, but my understanding is that
rvalue refereces and move semantics allow a library to overload the
rvalue assignment to do a this kind of pointer swapping. But this
stuff is probably very difficult to do.
I guess I knew what I was talking about when I suggested I don't know what I am talking about.
That's the trick data().swap(..) does, it takes the passed by value data and swaps its pointer with the object calling it <--I can discuss a bit more about that but it may get too technical (i.e. std::swap(..,..) vs container.swap(...) ). Also the compiler should be (in my case is) responsible to take care of the value passed using copy elision. If it is an rvalue it will pass it in without copying; or copy it if it is not - which is what we want.
I did some tests and if the you are interested I can prepare to post them. The memory in those tests certainly shows half memory usage with move semantics for a large vector. Tracing back gives no indication of the existence of two containers and the performance is increased by about 20-30%. Also there is no indication of shallow copy (left and right side containers remain two distinct objects with distinct storage).
Wow... is it really that easy? I thought the above code would cause all sorts of aliasing disasters...
Is this really good enough to use for functions returning big matrices as return values?
Take the following:
template<typename MatrixT>
matrix<double> inv(const matrix_expression<MatrixT>& A)
{
matrix<double> B(A().size1(), A().size2());
//Say a complicated sequence to invert A into B, which can't just return a matrix expression.
return B;
}
vs. a standard one with the return value passed in by non-const reference.
template<typename MatrixT>
void inv(const matrix_expression<MatrixT>& A, matrix<double>& B)
{
//Complicated sequence to invert A into B, which can't just return a matrix expression.
}
//Now take the client code, for very large matrices.
matrix<double> B = inv(A); //Does the swap method above cause an invalid data pointer due to returning a temporary?
Any overhead in the copy vs. inv(A, B); ?
//Now do it with matrix expressions on both sides...
matrix<double> B = 2 * inv( .5 * A);
Is there any overhead on this vs.:
matrix<double> B(A.size1(), A.size2());
inv(.5 * A, B);
B *= 2;
_________________________________________________________________
Hotmail® is up to 70% faster. Now good news travels really fast.
http://windowslive.com/online/hotmail?ocid=PID23391::T:WLMTAGL:ON:WL:en-US:WM_HYGN_faster:082009