| View previous topic :: View next topic |
| Author |
Message |
John Guest
|
Posted: Thu Apr 12, 2007 1:38 pm Post subject: Random and Multithreading |
|
|
Hello,
I have to apply a graphic filter on a Bitmap.
I have a corde 2 duo since a few weeks so I decided to port this filter
to multithreading, and I was very surprised that it takes more time in
multithreading than normal.
After spending some times on my code I have discovered that the
bottleneck was the random function.
So i have made a small example that do only random, and i was a lot
surpised.
here's the result for doing 48000000 randoms on my core 2 duo :
Normal : 204 ms
Multithread (2 threads) : 1109 ms.
so My questtions are :
- Am I missing something ?
- Is there any alternative to RTL random that support better and
faster random ?
here's the code :
Type
TRandom = class(TThread)
private
FCount: Integer;
protected
procedure Execute; override;
public
constructor Create(Count: integer; Suspended: Boolean);
end;
//The threaded random Class
constructor TRandom.Create(Count: integer; Suspended: Boolean);
begin
FreeOnTerminate := False;
inherited Create(Suspended);
FCount := Count;
end;
procedure TRandom.Execute;
var
i, j: integer;
begin
for i := 0 to FCount - 1 do
j := random(255);
end;
//the way it is called
procedure DoRandom(Count: integer; NbThreads: integer);
var
threads: array of THandle;
ft: array of TRandom;
i, j, NBCountThread, Lastthread, NBC: integer;
begin
try
//Number of count per thread
NBCountThread := Count div NbThreads;
Lastthread := NbThreads - 1;
SetLength(threads, NbThreads);
SetLength(ft, NbThreads);
j := 0;
// start all threads
for i := 0 to high(threads) {Lastthread} do
begin
if i < Lastthread then
begin
//Number of count for this thread
NBC := NBCountThread;
inc(j, nbc);
end
else
begin
//Number of count for last thread
NBC := Count - j;
end;
ft[i] := TRandom.Create(NBC, True);
// store handle of the thread so we know what to wait for
threads[i] := ft[i].Handle;
ft[i].Resume;
end;
// wait until all threads are done
WaitForMultipleObjects(NbThreads, @threads[0], true, INFINITE);
finally
for i := 0 to high(ft) do
if Ft[i] <> nil then
FreeAndNil(Ft[i]);
SetLength(ft, 0);
SetLength(Threads, 0);
end;
end;
//the same thing without multithreading
procedure NormalRandom(FCount: integer);
var
i, j: integer;
begin
for i := 0 to FCount - 1 do
j := random(255);
end;
//the test
procedure TForm1.Button2Click(Sender: TObject);
var
TC: integer;
begin
tc := Gettickcount;
NormalRandom(48000000);
tc := Gettickcount - tc;
Showmessage(inttostr(tc));
tc := Gettickcount;
DoRandom(48000000,2); //2 threads
tc := Gettickcount - tc;
Showmessage(inttostr(tc));
end;
thanks
John |
|
| Back to top |
|
 |
Les Pawelczyk Guest
|
Posted: Thu Apr 12, 2007 7:07 pm Post subject: Re: Random and Multithreading |
|
|
| Quote: | I have to apply a graphic filter on a Bitmap.
I have a corde 2 duo since a few weeks so I decided to port this filter to multithreading, and I was very surprised that it takes more time in multithreading than normal.
After spending some times on my code I have discovered that the bottleneck was the random function.
|
Random function makes use of RandSeed global variable. It modifies it every time it is called. If two different CPUs (cores) modify the same memory at the same time, it will cause cache thrashing and consequently serious slow-down.
Les. |
|
| Back to top |
|
 |
John Guest
|
Posted: Thu Apr 12, 2007 7:40 pm Post subject: Re: Random and Multithreading |
|
|
Thanks Les for your reply.
Is there a way to avoid this by using another fast ranndom routines ?
or any other solution ?
Thanks |
|
| Back to top |
|
 |
Dan Downs Guest
|
Posted: Thu Apr 12, 2007 8:05 pm Post subject: Re: Random and Multithreading |
|
|
| Quote: | Is there a way to avoid this by using another fast ranndom routines ?
or any other solution ?
|
I haven't looked at the implementation of random, but rolling your own
version that uses a thread local RandSeed variable instead of the global
would probably do it. I'm not sure how that would effect the randomness
though.
DD |
|
| Back to top |
|
 |
Les Pawelczyk Guest
|
Posted: Thu Apr 12, 2007 8:08 pm Post subject: Re: Random and Multithreading |
|
|
| Quote: | Is there a way to avoid this by using another fast ranndom routines ?
or any other solution ?
|
Yes, but any such solution would have to incorporate separate RandSeed variable (or variables) per thread in such a way that each of those variables (or sets of variables) would not share same cache lines. Cache lines are currently 64 bytes long and are aligned by 64 bytes. The way to make sure two variables (or sets of variables) are separated by 64 bytes in memory is to make them part of a record or object which is padded with dummy 64 byte long field (array[0..63] of byte for example).
Les. |
|
| Back to top |
|
 |
John Guest
|
Posted: Thu Apr 12, 2007 8:26 pm Post subject: Re: Random and Multithreading |
|
|
So one solution would be to "clone" the random function and puting it
directly tin the thread class and using RandSeed as a local variable ?
but I don't see any random function in system.pas |
|
| Back to top |
|
 |
John Herbster Guest
|
Posted: Thu Apr 12, 2007 8:41 pm Post subject: Re: Random and Multithreading |
|
|
"John" <NoSpam (AT) NoSpam (DOT) com> wrote
| Quote: | here's the result for doing 48000000 randoms
on my core 2 duo:
Normal: 204 ms Multithread (2 threads): 1109 ms.
|
That is about 48 random numbers per microsecond.
| Quote: | - Is there any alternative to RTL random that support
better and faster random?
|
John,
What are you doing with these pseudo-random
numbers? If you are doing anything sophisticated with
them, I suspect that it must also be taking some time.
If it is not sophisticated, then I suspect that the relation
ship between adjacent numbers is going expose
problems with their lack of true randomness.
Rgds, JohnH |
|
| Back to top |
|
 |
John Guest
|
Posted: Thu Apr 12, 2007 9:04 pm Post subject: Re: Random and Multithreading |
|
|
| Quote: | here's the result for doing 48000000 randoms
on my core 2 duo:
Normal: 204 ms Multithread (2 threads): 1109 ms.
That is about 48 random numbers per microsecond.
- Is there any alternative to RTL random that support
better and faster random?
John,
What are you doing with these pseudo-random
numbers? If you are doing anything sophisticated with
them, I suspect that it must also be taking some time.
|
non this bench is the result of the test code that i have put on my
first thread...
only this : for i := 0 to FCount - 1 do
j := random(255);
nothing else.... |
|
| Back to top |
|
 |
Bob Gonder Guest
|
Posted: Thu Apr 12, 2007 9:50 pm Post subject: Re: Random and Multithreading |
|
|
John Herbster wrote:
| Quote: | here's the result for doing 48,000,000 randoms
on my core 2 duo:
Normal: 204 ms Multithread (2 threads): 1109 ms.
That is about 48 random numbers per microsecond.
|
Let's see...
48 MOPs at 2GHz is about 40 clocks per OP per second
(2,000M / 48M == 41.7 )
Normal runs in 1/5 second, so 8 instructions(clocks) per loop.
Multithread is running at about 44 instructions(clocks) per loop.
How small is the Rand function, and is the "normal" method optimized
better?
TRandom.Execute should call NormalRandom to eliminate optimization
differences.
He might also run it with One thread in addition to Two, to eliminate
differences.
inherited Create(Suspended);
FCount := Count;
FCount should be set before Create is called.
He is including Thread setup/teardown in his timing.
He might have each thread time itself and report.
Have we established that threads are distributed automatically by
Windows? Or do they remain process/processor bound by default?
See GetProcessAffinityMask()
And SetThreadAffinityMask()
And SetThreadIdealProcessor() |
|
| Back to top |
|
 |
John Guest
|
Posted: Thu Apr 12, 2007 10:08 pm Post subject: Re: Random and Multithreading |
|
|
Any usefull sample ?
| Quote: |
See GetProcessAffinityMask()
And SetThreadAffinityMask()
And SetThreadIdealProcessor()
|
|
|
| Back to top |
|
 |
John Herbster Guest
|
Posted: Fri Apr 13, 2007 12:23 am Post subject: Re: Random and Multithreading |
|
|
"John" <NoSpam (AT) NoSpam (DOT) com> wrote
| Quote: | ... I have to apply a graphic filter on a Bitmap ...
|
John,
I just noticed the above line in your OP. Are you
trying to do dithering to smooth out gradient steps?
If so, I believe that there are better ways to do this
than recomputing the random function each time.
Using a PRNG (pseudo-random number generator)
to do this is often an easy way to find correlations
in the generated random number sequence, which
is usually what you do *not* want when doing image
dithering.
Regards, JohnH |
|
| Back to top |
|
 |
Sven Pran Guest
|
Posted: Fri Apr 13, 2007 1:23 am Post subject: Re: Random and Multithreading |
|
|
"John" <NoSpam (AT) NoSpam (DOT) com> wrote in message
news:461e4f99$1 (AT) newsgroups (DOT) borland.com...
| Quote: | So one solution would be to "clone" the random function and puting it
directly tin the thread class and using RandSeed as a local variable ?
but I don't see any random function in system.pas
|
Search System.pas repeatedly for the word RandSeed
regards Sven |
|
| Back to top |
|
 |
Bob Gonder Guest
|
Posted: Fri Apr 13, 2007 5:49 am Post subject: Re: Random and Multithreading |
|
|
John wrote:
| Quote: | Any usefull sample ?
|
Not from me.
Don't have multi-cpu, nor Delphi to test.
Those functions look pretty easy to understand though. |
|
| Back to top |
|
 |
John Guest
|
Posted: Fri Apr 13, 2007 8:11 am Post subject: Re: Random and Multithreading |
|
|
| I have seen Randseen not Random.... |
|
| Back to top |
|
 |
John Guest
|
Posted: Fri Apr 13, 2007 8:11 am Post subject: Re: Random and Multithreading |
|
|
| Quote: | I just noticed the above line in your OP. Are you
trying to do dithering to smooth out gradient steps?
|
no it's more like an explode filter, for each picel of Destimage you
have (pseudocode) :
Dest.Pixel[x,y]:=scr.Pixel[x + random(A), y + random(b)]; |
|
| Back to top |
|
 |
|