[Numpy-discussion] Parallelizable Performance Python Example

James Snyder jbsnyder at fanplastic.org
Tue Sep 22 13:03:14 EDT 2009


Hi -

I've recently been trying to adjust the performance python example (http://www.scipy.org/PerformancePython 
) so that it could be compared under a parallelized version.  I've  
adjusted the Gauss-Seidel 4 point method to a red-black checkerboarded  
(http://www.cs.colorado.edu/~mcbryan/3656.04/mail/87.htm) version that  
is much more easily parallelized on a shared memory system.

I've got some examples of this working, but I seem to be having  
trouble making it anywhere near efficient for the NumPy example (it 's  
around an order of magnitude slower than the non-red-black version).

Here's essentially what I'm doing with the NumPy solver:

    def numericTimeStep(self, dt=0.0):
        """
        Takes a time step using a NumPy expression.
        This has been adjusted to use checkerboard style indexing.
        """
        g = self.grid
        dx2, dy2 = np.float32(g.dx**2), np.float32(g.dy**2)
        dnr_inv = np.float32(0.5/(dx2 + dy2))
        u = g.u
        g.old_u = u.copy() # needed to compute the error.

        if self.count == 0:
            # Precompute Matrix Indexes
            X, Y = np.meshgrid(range(1,u.shape[0]-1),range(1,u.shape 
[1]-1))
            checker = (X+Y) % 2
            self.idx1 = checker==1
            self.idx2 = checker==0

        # The actual iteration
        g.u[1:-1, 1:-1][self.idx1] = ((g.u[0:-2, 1:-1][self.idx1] + g.u 
[2:, 1:-1][self.idx1])*dy2 +
                         (g.u[1:-1,0:-2][self.idx1] + g.u[1:-1, 2:] 
[self.idx1])*dx2)*dnr_inv

        g.u[1:-1, 1:-1][self.idx2] = ((g.u[0:-2, 1:-1][self.idx2] + g.u 
[2:, 1:-1][self.idx2])*dy2 +
                        (g.u[1:-1,0:-2][self.idx2] + g.u[1:-1, 2:] 
[self.idx2])*dx2)*dnr_inv


        return g.computeError()

Any ideas?  I presume that the double-indexing is maybe what's killing  
this, and I could precompute some boolean indexing arrays, but the  
original version of this solver (plain Gauss-Seidel, 4 point  
averaging) is rather simple and clean :-):

    def numericTimeStep(self, dt=0.0):
        """Takes a time step using a NumPy expression."""
        g = self.grid
        dx2, dy2 = g.dx**2, g.dy**2
        dnr_inv = 0.5/(dx2 + dy2)
        u = g.u
        g.old_u = u.copy() # needed to compute the error.

        # The actual iteration
        u[1:-1, 1:-1] = ((u[0:-2, 1:-1] + u[2:, 1:-1])*dy2 +
                         (u[1:-1,0:-2] + u[1:-1, 2:])*dx2)*dnr_inv

        return g.computeError()


Here's a pure python version of the red-black solver (which is, of  
course, incredibly slow, but not that much slower than the non-red- 
black version):
    def slowTimeStep(self, dt=0.0):
        """Takes a time step using straight forward Python loops."""
        g = self.grid
        nx, ny = g.u.shape
        dx2, dy2 = np.float32(g.dx**2), np.float32(g.dy**2)
        dnr_inv = np.float32(0.5/(dx2 + dy2))
        u = g.u

        err = 0.0
        for offset in range(0,2):
          for i in range(1, nx-1):
              for j in range(1 + (i + offset) % 2, ny-1, 2):
                  tmp = u[j,i]
                  u[j,i] = ((u[j-1, i] + u[j+1, i])*dx2 +
                            (u[j, i-1] + u[j, i+1])*dy2)*dnr_inv
                  diff = u[j,i] - tmp
                  err += diff*diff

        return np.sqrt(err)


--
James Snyder
Biomedical Engineering
Northwestern University
jbsnyder at fanplastic.org
http://fanplastic.org/key.txt
ph: 847.448.0386
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4012 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/numpy-discussion/attachments/20090922/b5e1a41e/attachment.bin>


More information about the NumPy-Discussion mailing list