Numerical Stream code
Jin Mingjian
jin.phd at gmail.com
Thu Feb 14 03:57:01 PST 2013
Hi, Howward,
the price for convenience is the performance:) The specialization version
of stream has much mitigated the stress numerical computing, I guess.
After quickly scanning the sources, the DoubleStatistics does more things.
So, one of my suggestions is to use the direct average(like sum/length
) rather than use the default average() to see if there is some
improvement. And the benchmark is always a tricky stuff. You should warm up
your bench codes enough at least.
best regards,
Jin Mingjian
On Thu, Feb 14, 2013 at 2:34 PM, Howard Lovatt <howard.lovatt at gmail.com>wrote:
> Hi,
>
> I have been trying out lambdas on:
>
> openjdk version "1.8.0-ea"
> OpenJDK Runtime Environment (build
> 1.8.0-ea-lambda-nightly-h3307-20130211-b77-b00)
> OpenJDK 64-Bit Server VM (build 25.0-b15, mixed mode)
>
> To see if scientific type numerical code can use Streams. I wrote a
> synthetic benchmark that applies a kernel repeatedly over time and space to
> solve a diffusion equation in 1 D, e.g. heat diffusing into a metal rod
> from either end. The core of the code is:
>
> private enum Styles implements Style {
> CLike {
> @Override public double run() {
> uM1[0] = uT0; // t = 0
> for (int xi = 1; xi < numXs - 1; xi++) { uM1[xi] = u0X; }
> uM1[numXs - 1] = uT1;
> for (int ti = 1; ti < numTs; ti++, uTemp = uM1, uM1 = u0, u0 =
> uTemp) { // t > 0
> u0[0] = uT0; // x = 0
> for (int xi = 1; xi < numXs - 1; xi++) { u0[xi] =
> explicitFDM.u00(uM1[xi - 1], uM1[xi], uM1[xi + 1]); } // 0 < x < 1
> u0[numXs - 1] = uT1; // x = 1
> }
> double sum = 0; // Calculate average of last us
> for (final double u : uM1) { sum += u; }
> return sum / numXs;
> }
> },
>
> SerialStream {
> @Override public double run() {
> Arrays.indices(uM1).forEach(this::t0);
> for (int ti = 1; ti < numTs; ti++, uTemp = uM1, uM1 = u0, u0 =
> uTemp) { // t > 0
> Arrays.indices(uM1).forEach(this::tg0);
> }
> return Arrays.stream(uM1).average().getAsDouble(); // Really slow!
> }
> },
>
> ParallelStream {
> @Override public double run() {
> Arrays.indices(uM1).parallel().forEach(this::t0);
> for (int ti = 1; ti < numTs; ti++, uTemp = uM1, uM1 = u0, u0 =
> uTemp) { // t > 0
> Arrays.indices(uM1).parallel().forEach(this::tg0);
> }
> return Arrays.stream(uM1).parallel().average().getAsDouble(); //
> Really really slow!!
> }
> };
>
> double[] u0 = new double[numXs];
> double[] uM1 = new double[numXs];
> double[] uTemp = null;
>
> void t0(final int xi) {
> if (xi == 0) { uM1[0] = uT0; }
> else if (xi == numXs - 1) { uM1[numXs - 1] = uT1; }
> else { uM1[xi] = u0X; }
> }
>
> void tg0(final int xi) {
> if (xi == 0) { u0[0] = uT0; }
> else if (xi == numXs - 1) { u0[numXs - 1] = uT1; }
> else { u0[xi] = explicitFDM.u00(uM1[xi - 1], uM1[xi], uM1[xi + 1]); }
> }
> }
>
> And when run it produces:
>
> CLike: time = 2351 ms, result = 99.99581170383331
> SerialStream: time = 20532 ms, result = 99.99581170383331
> ParallelStream: time = 131317 ms, result = 99.99581170383331
>
> The slowness is a pity because the coding comes out quite well!
>
> I wasn't particularly expecting the Stream implementation to be fast,
> because they are a work in progress after all. However a factor of almost
> 10 for the serial case and over 50 for the parallel case seems excessive. I
> therefore suspect that I am doing something wrong.
>
> Can anyone enlighten me?
>
> Thanks,
>
> -- Howard.
>
>
More information about the lambda-dev
mailing list