Given an LAPACK-like linear algebra routine to apply a planar rotation to
two vectors

        proc rot(r : complex, ref acj : [?aciD] Real, ref aci : [?acjD] Real)
        {
                for (ai, aj) in zip(aci, acj) do
                {
                        const w = r * (ai, aj):complex;

                        (ai, aj) = (w.re, w.im);
                }
        }

I am computing an SVD. Any vector size more than 2000 with my algorithm
is probably suspect. That is cool because I do not need to go above 1000
for the types of problem I am attacking. Within the algorithm, there are
two independent tasks operating on two independend matrices 'v' and 'a'

        rot(tv, v[i..j, k - 1], v[i..j, k])
and
        rot(ta, a[m..n, k - 1], a[m..n, k])

which are the major numerical computations in the workload, a QR iteration.
Neither of these two computations depend on the other.

Note that the computations being done with 'rot'

a)      use vectors which have stride > 1 as they work on rows of a matrix
        with column major ordering, and

b)      have vectors from size 6 to 1600 for the problems at hand, which are
        largely test cases with well known solutions.

So, using Chapel code like

        cobegin
        {
                rot(tv, v[i..j, k - 1], v[i..j, k]);
                rot(ta, a[m..n, k - 1], a[m..n, k]);
        }

seemed like a reasonable idea to maybe halve the computation time.
if the 2 'tasks' could run independently of each other.

I only have 6 cores to exploit at this development stage. It normally
gives me a good indication of what will or not work in parallel.

I left the 'for' loop in 'rot' alone because I did not want to have it
trying to run in parallel and confusing the scheduler. I thought halving
the run-time was more than a good performance gain.

But it is slower than serial C for a vector size of 1600.

So, let's throw out the cobegin, run these two calls to 'rot' one after
another but let the routine 'rot' run its loop as a forall in parallel.

And it is twice as fast as serial C for the same vector size.

Nice!

On just 6 cores, with a vector length of 1600, the implementation of SVD running in parallel is twice the speed of a serial C implementation with very little work. And the algorithm is still very obvious and readable. The nice clean code appears to parallelize nicely. But for reasons I do not quite comprehend fully.

I would have thought the parallel overhead of a 'cobegin' would have
been much less than that in a 'forall' loop (over what in my cases is
1600 complex numbers being read out of cache, multiplied together, and
then copied back into cache memory).

Is my thinking wrong?

My data is still living in cache, but only just.

I am using 1.20.0 for the moment, not the latest.

Thanks - Damian

Pacific Engineering Systems International, 277-279 Broadway, Glebe NSW 2037
Ph:+61-2-8571-0847 .. Fx:+61-2-9692-9623 | unsolicited email not wanted here
Views & opinions here are mine and not those of any past or present employer


_______________________________________________
Chapel-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/chapel-developers

Reply via email to