Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.programming.threads > #207
| Path | csiph.com!x330-a1.tempe.blueboxinc.net!usenet.pasdenom.info!news.albasani.net!feeder.erje.net!news-2.dfn.de!news.dfn.de!news.uni-stuttgart.de!news.nask.pl!news.nask.org.pl!newsfeed2.atman.pl!newsfeed.atman.pl!.POSTED!not-for-mail |
|---|---|
| From | Edek <edek.pienkowski@gmail.com> |
| Newsgroups | comp.programming.threads |
| Subject | Re: False sharing |
| Date | Mon, 30 May 2011 22:29:21 +0200 |
| Organization | ATMAN - ATM S.A. |
| Lines | 167 |
| Message-ID | <is0un2$anb$1@node2.news.atman.pl> (permalink) |
| References | <18fa2208-ba1c-42c5-bf1f-280e6cbc41e6@bl1g2000vbb.googlegroups.com> |
| NNTP-Posting-Host | 81.219.115.2 |
| Mime-Version | 1.0 |
| Content-Type | text/plain; charset=ISO-8859-1; format=flowed |
| Content-Transfer-Encoding | 7bit |
| X-Trace | node2.news.atman.pl 1306787362 10987 81.219.115.2 (30 May 2011 20:29:22 GMT) |
| X-Complaints-To | usenet@atman.pl |
| NNTP-Posting-Date | Mon, 30 May 2011 20:29:22 +0000 (UTC) |
| User-Agent | Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.17) Gecko/20110428 Linux/3.1.0-15 Thunderbird/3.1.0 |
| In-Reply-To | <18fa2208-ba1c-42c5-bf1f-280e6cbc41e6@bl1g2000vbb.googlegroups.com> |
| Xref | x330-a1.tempe.blueboxinc.net comp.programming.threads:207 |
Show key headers only | View raw
On 05/30/2011 01:26 PM, curious wrote:
> Hi All,
>
> I wanted to see the effects of false sharing and wrote small test
> program below:
>
False sharing happens when data reaches RAM (or cache at least). Here,
it probably doesn't (at least not for every loop).
>
> #include<pthread.h>
> #include<iostream>
>
> typedef volatile long work_t;
>
Note: volatile, not "atomic". People often misunderstand 'volatile' as
'always reach RAM'. It might not even reach all cache levels.
>
>
> struct WorkArea {
> work_t __attribute__ ((aligned (128))) worker1; // making sure the
> first data item is alligned to cache line
Just as a small warning: older compilers didn't align values on stack,
even if they had the right attributes; silently.
Double check if the address is really aligned.
> //char buffer[128];
> work_t worker2;
> WorkArea() : worker1(0), worker2(0) {}
> };
>
>
> void* worker_thread(void* data);
> volatile bool g_wait = true;
> int main() {
> pthread_t thread1, thread2;
> WorkArea wa;
> int iret1, iret2;
> iret1 = pthread_create(&thread1, NULL, worker_thread,
> (void*)&wa.worker1 );
> iret2 = pthread_create(&thread2, NULL, worker_thread,
> (void*)&wa.worker2);
You can change that even to wa.worker1, wouldn't make a huge difference
(real sharing). On my CPU this adds about 3%,w hen same test varies
by ~2%. Of course, the result is undefined then.
> g_wait = false;
> pthread_join( thread1, NULL);
> pthread_join( thread2, NULL);
> std::cout<< "worker 1 "<< wa.worker1<< " worker2 "<< wa.worker2
> << std::endl;
>
> return 0;
> }
>
> void* worker_thread(void* data)
> {
> while(g_wait){}
Don't...
> work_t&work = *(work_t*)data;
> for(long i =0; i< 10 * 1000L * 1000L * 1000L; ++i) {
> work += i;
What happens here: compiler cannot just compute the result instead
of coding the loop, because of volatile. CPU however knows
nothing about 'volatile'. It only knows that this is regular RAM
(so such things as write-combining are on),
which is different than IO memory - then every write and read
would have to be performed (that's what volatile is for BTW).
The part of the CPU which loads and stores data core <-> cache
will not do anything, because it is told 'wait, I need to
load it back and change again' - why would it store anything?
It maybe stores the value sometimes, maybe it doesn't.
CPUs today are way smarter than microcontrolers. They optimise.
If one writes two values into same memory address, only the second
one will be stored, for example.
However, the CPU still has to do addition. If you just store, the thing
is much simpler. Multiplication takes about 1.5x time for addition
when multiplying zeroes,
(interesting on its own). So: not RAM access takes time.
Division: 7x addition.
> }
At this point the unit responsible for RAM gets told 'nothing more'
and stores for sure. Maybe it did store something before, maybe not.
(Ok: it probably did, but an order of magnitude fewer times than
the loop count). Still, the other thread might not see this immediately.
> return data;
> }
>
> I expected it to run much faster when the char buffer[128] would not
> be commented out. However it seems that it does not affect the
> runtime. For both scenarios I get almost identical results.
>
> Typical results are all very close, here is one example
> real 0m24.405s
> user 0m47.910s
> sys 0m0.020s
>
> I run this on Intel(R) Core(TM)2 Duo CPU P8700 @ 2.53GHz
>
> Could this be because shared L2 cache it does not suffer from the
> false sharing as easily?
>
> Another interesting observation is that if I change
> work += i to work = i ( so that it does not need to read the old work
> value) then it runs much faster:
> real 0m5.840s
> user 0m11.350s
> sys 0m0.020s
>
> Which kind of makes sense, but it would be great if someone could
> explain in terms of MESI how the two scenarios differ and why the huge
> difference in speed.
cmp and jump, plus: 4 ops vs. 2 ops, and no calculation,
maybe also the fact that there is no read-after-write
changes things too:
for (...) {
work = work;
}
also takes about the same time as addition. Probably calculation
is hidden by some bubble in handling the dependencies.
(Q6600, similar to a pair of slower than yours core2's glued together).
if I change the loop to
for (...) {
__sync_fetch_and_add (&work, i);
}
... then there is a huge difference if the padding is there or
not (almost 5x), because of false sharing.
__sync_synchronize() in a loop also has a similar effect, though it
is faster than two threads thrashing the bus with LOCKs. Of course,
still much slower than your version (2x).
for (...) {
work += i;
__sync_synchronize ();
}
They all have a different purpose.
>
> Many Thanks!
HTH
Edek
PS. What I am not saying is that false sharing may never happen when
there is no atomicity or at least a fence. But if data is not stored,
there is no false sharing. Store is forced by a barrier or atomicity,
otherwise will happen sooner or later, with the stress on _later_.
Back to comp.programming.threads | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread
False sharing curious <curious.oskar58@gmail.com> - 2011-05-30 04:26 -0700
Re: False sharing Edek <edek.pienkowski@gmail.com> - 2011-05-30 22:29 +0200
Re: False sharing curious <curious.oskar58@gmail.com> - 2011-05-31 03:21 -0700
Re: False sharing Marcel Müller <news.5.maazl@spamgourmet.com> - 2011-05-31 15:41 +0200
Re: False sharing curious <curious.oskar58@gmail.com> - 2011-05-31 10:18 -0700
Re: False sharing Edek <edek.pienkowski@gmail.com> - 2011-05-31 20:10 +0200
Re: False sharing Edek <edek.pienkowski@gmail.com> - 2011-05-31 20:37 +0200
Re: False sharing Edek <edek.pienkowski@gmail.com> - 2011-05-31 21:18 +0200
Re: False sharing curious <curious.oskar58@gmail.com> - 2011-05-31 14:40 -0700
Re: False sharing "Balog Pal" <pasa@lib.hu> - 2011-06-01 03:17 +0200
Re: False sharing Edek <edek.pienkowski@gmail.com> - 2011-06-01 22:20 +0200
Re: False sharing curious <curious.oskar58@gmail.com> - 2011-05-31 14:29 -0700
Re: False sharing David Schwartz <davids@webmaster.com> - 2011-05-31 14:12 -0700
Re: False sharing "Chris M. Thomasson" <cristom@charter.net> - 2011-06-11 15:34 -0700
Re: False sharing "Chris M. Thomasson" <cristom@charter.net> - 2011-06-11 19:56 -0700
Re: False sharing "Chris M. Thomasson" <cristom@charter.net> - 2011-06-11 21:07 -0700
csiph-web