Thread overview
each! vs foreach parallel timings
Dec 27, 2015
Jay Norwood
Dec 27, 2015
Ali Çehreli
Dec 28, 2015
Jay Norwood
Dec 28, 2015
Jay Norwood
Dec 28, 2015
Ali Çehreli
December 27, 2015
I'm doing some re-writing and measuring.  The basic task is to take 10K samples (in struct S samples below) and calculate some metrics (just per sample for now).  It isn't evident to me how to write the parallel foreach in the same format as each!, so I just used the loop form that I understood.

Measured times below are for processing three simple metrics 100 times on 10K samples. This parallel mode could be very useful in my work, which involves processing a bunch of hardware performance data.


This is on windows, corei5, DMD32 D Compiler v2.069.2, debug build.

each! time:59 ms
parallel! time:20 ms

import std.stdio;
import std.algorithm;
import std.conv;
import std.range;
import std.typecons;
import std.parallelism;
import std.array;
import std.traits;
import std.datetime;

struct S { int sn; ulong a; ulong b; ulong c; ulong d; double e; ulong f; ulong m1; double m2; double m3;}

void apply_metrics(int i,ref S s){
	with(s){
		m1 = a+b;
		m2 = (c+d)/e;
		m3 = (c+f)/e;
		sn = i;
	}
}

int main()
{

	S[10000] samples;
	// initialize some values
	foreach ( int i, ref s; samples){
		int j=i+1;
		with (s){
			a=j; b=j*2; c=j*3; d=j*4; e=j*10; f=j*5;
		}
	}

	auto sw = StopWatch(AutoStart.yes);
	// apply several functions on each  sample, also number the samples
	foreach(j;iota(100))
	samples[].each!((int i, ref a)=>apply_metrics(i,a));
	writeln("each! time:", sw.peek().msecs, " ms");

	auto sw2 = StopWatch(AutoStart.yes);
	// do the same as above, but in parallel
	foreach(j;iota(100))
		foreach( i, ref a; parallel(samples[])){ apply_metrics(i,a);}
	writeln("parallel! time:", sw2.peek().msecs, " ms");
	return 0;
}
December 27, 2015
On 12/27/2015 11:30 AM, Jay Norwood wrote:

>      samples[].each!((int i, ref a)=>apply_metrics(i,a));

Are you using an older compiler? That tuple expansion does not work any more at least with dmd v2.069.0 but you can use enumerate():

        samples[].enumerate.each!(t=>apply_metrics(t[0].to!int,t[1]));

>          foreach( i, ref a; parallel(samples[])){ apply_metrics(i,a);}

That does not compile because i is size_t but apply_metrics() takes an int. One solution is to call to!int:

        foreach( i, ref a; parallel(samples[])){ apply_metrics(i.to!int,a);}

To not answer your actual question, I don't think it's possible. :)

Ali

December 28, 2015
On Sunday, 27 December 2015 at 23:42:57 UTC, Ali Çehreli wrote:
> On 12/27/2015 11:30 AM, Jay Norwood wrote:
>
> >      samples[].each!((int i, ref a)=>apply_metrics(i,a));
>
> Are you using an older compiler? That tuple expansion does not work any more at least with dmd v2.069.0 but you can use enumerate():
>
>         samples[].enumerate.each!(t=>apply_metrics(t[0].to!int,t[1]));
>
> >          foreach( i, ref a; parallel(samples[])){
> apply_metrics(i,a);}
>
> That does not compile because i is size_t but apply_metrics() takes an int. One solution is to call to!int:
>
>         foreach( i, ref a; parallel(samples[])){ apply_metrics(i.to!int,a);}
>
> To not answer your actual question, I don't think it's possible. :)
>
> Ali

The code I posted was compiled with v2.069.2.  It isn't creating a tuple return value in this code. I'll re-check it.
December 28, 2015
> On Sunday, 27 December 2015 at 23:42:57 UTC, Ali Çehreli wrote:
>> That does not compile because i is size_t but apply_metrics() takes an int. One solution is to call to!int:
>>
>>         foreach( i, ref a; parallel(samples[])){ apply_metrics(i.to!int,a);}
>>

It builds for me still, and executes ok, but must be because size_t and i are both 32 bits on Win32 build.

December 27, 2015
On 12/27/2015 04:17 PM, Jay Norwood wrote:
>> On Sunday, 27 December 2015 at 23:42:57 UTC, Ali Çehreli wrote:
>>> That does not compile because i is size_t but apply_metrics() takes
>>> an int. One solution is to call to!int:
>>>
>>>         foreach( i, ref a; parallel(samples[])){
>>> apply_metrics(i.to!int,a);}
>>>
>
> It builds for me still, and executes ok, but must be because size_t and
> i are both 32 bits on Win32 build.
>

Makes sense. I would still prefer size_t and even leave it out for the lambda:

void apply_metrics(size_t i,ref S s){
// ...

        sn = i.to!int;

// ...

    samples[].each!((i, ref a)=>apply_metrics(i,a));

Ali