On 6/2/2026 12:36 PM, MitchAlsup wrote:
Paul Clayton <paaronclayton@gmail.com> posted:
On 6/1/26 9:27 PM, MitchAlsup wrote:
[snip]
But note: XADD [...] never causes more than necessary bus traffic
I am skeptical that this is Architecturally guaranteed. It may
fall out of any even semi-sane implementation, in which case
programmers might be willing to take it as guaranteed. Yet I
suspect "sanity" may not be reliable with changing tradeoffs
(including whether protecting a company's reputation has value).
The core is going to package this instruction up and ship it
across the interconnect as a fire-and-forget transaction.
The interconnect is going to route the package towards either a
cache having write permission or a control register.
The cache or control register will perform the packaged calculation
and optionally send back the previous value.
The core receives the optional previous value and the memory-atomic
is complete:: 2 interconnect messages, both smaller than a cache line,
not cache lines are moved, and the calculation cannot fail. The only
failure mode is if the interconnect message fails ECC check in either
directions.
and as an atomic event, never fails, never needs retry, ...
I believe an optimistic concurrency interface (LL/SC, ASF, ESM,
etc.) could provide such guarantees,
If so, you will be surprised when you implement one.
even extending to multiple
contiguous instructions operating on data within an aligned
64-byte region.
Where it becomes cubically harder.
Interestingly, it seems that IBM's z17 is the last
implementation to support constrained transactions. I do wonder
why this feature has been removed from the Architecture.
SW TM wants the TM model to support an unbounded number of memory
elements in the single transaction. HW does not do unbounded.
Constrained transactions had these restrictions (fromI used a timer--to the same ends.
https://www.ibm.com/docs/en/zos/3.1.0?topic=execution-constrained-
transactions):
| - The transaction executes no more than 32 instructions.
| - All instructions within the transaction must be within 256I allow calls to subroutines in the event.
| contiguous bytes of storage.
| - The only branches you may use are relative branches thatLoops are OK as long as the timer does not go off.
| branch forward (so there can be no loops).
| - All SS and SSE-format instructions may not be used.Agreed.
| - Additional general instructions may not be used.I see no reason to limit general calculations and memory access.
| - The transaction's storage operands may not access more than8 cache lines participate, an unbounded number of cache lines
| four octowords.
can be accessed as long as participants is no larger than 8.
| - The transaction may not access storage operands in any 4 |K-interdesting.
| byte blocks that contain the 256 bytes of storage beginning
| with the TBEGINC instruction.
| - Operand references must be within a single doubleword,Any normal memory references to the participating lines.
| except for some of the "multiple" instructions for which the
| limitation is a single octoword.
I think I read that the first implementation made an optimistic
attempt and later — I do not remember if multiple optimistic
attempts were made — a hardware lock was used. Perhaps four
addresses cause too much of a slowdown when there is conflict???
I believe that guaranteeing completion would be substantially
easier with only one aligned 64-byte region. (As I think I
wrote before, adding a single "word" exportable atomic operation
in a different "cache block" _might_ be practical to implement
though I did not have an idea for software would express such.
I may be wrong that appending such an exportable operation would
not make ensuring completion significantly more difficult.)
If you take the necessary 6 months to slug through all issues
you can find solutions for the disjoint participants to be at
least as large as the outstanding Miss Buffer size (or MB-1).
I think such guaranteed atomic sequences would require a
distinct instruction not only to allow what IBM did (making such
an illegal/faulting instruction) but also to fault when the
instruction is misused since no fallback path is provided.
If you do it right, your architecture sets up failure paths,
so that if failure happens, IP reverts to the failure point
without executing a branch instruction. I have an instruction
that samples 'interference' and changes the failure point as
a necessary addition. Any interrupt or exception transfers
control to failure point before performing exception control
transfer.
There also seem to be other operations that would not (I think)
be exceptionally difficult to guarantee. E.g., swapping cache
blocks might not be much more difficult to guarantee than quick
operations within a single cache block, though I do not know
how useful such an unconditional swap would be. Atomic cache
block copy would seem to be easier (it is similar to a block
zeroing instruction except that the value is taken from a block
that is not writeable by other agents being in exclusive or
shared state). Guaranteeing atomicity for a copy into a cache
block (where two contiguous cache blocks might be in the read
set and the write is only to part of a cache block) seems a
little more complicated.
The thing that makes this so difficult is that most µArchitectures
cannot guarantee that 2 cache lines are ever simultaneously present
in the cache. ASF and ESM have means to do this which greatly
strengthens the guarantee of forward progress.
My 66000 includes priority in memory transactions, and this enables
the cache with write permission to determine to allow the request
or to fail the request (request is at equal or lower priority) thus
allowing the higher priority ATOMIC event to make forward progress
at the expense of the lower priority event.
At certain times the core may be in a position where it can finish
an event if the cache lines can e guaranteed. During this period,
a core can NaK a request so that the event is guaranteed to finish.
With conventional cache coherence, partial writes seem likely to
be complex. If masked cache block updates were possible as an
exportable atomic operation, it might be practical to lock (NAK-
guard) a limited read set and push the update to the owner. I do
not know if such an update independent of previous values in the
written cache block would be useful.
It is much worse than that in practice. The interconnect protocol and
the cache coherence model HAVE to HAVE ATOMIC event forward progress
fully integrated. MESI and MOESI are insufficient here; most directory
coherence protocols are also insufficient.
I am certainly not comfortable thinking about the visibility/
ordering constraints, so my guesses are very wrong about what is
practical to guarantee as atomic.
See Lamport...
Even if an operation can practically be guaranteed, it may not
be worthwhile to provide an interface that allows requesting
such a guaranteed atomic operation.
...
Well, we can do something... we know that lock cmpxchg8b on a 32 bit
system can handle two adjacent cache lines. So, we can try to hold more
than that, but! its not ideal. For instance my multex can do it and
emulate it. Read all https://groups.google.com/g/comp.lang.c++/c/ sV4WC_cBb9Q/m/SkSqpSxGCAAJ
I do not think it is impossible for an architecture to make
guarantees about LL/SC operations.
I seem to recall reading that x86's LOCK instructions take
hundreds of cycles. While some of this is probably from stronger
memory ordering guarantees, I get the impression that the
operation itself is not aggressively optimized.
Paul Clayton <paaronclayton@gmail.com> writes:
I seem to recall reading that x86's LOCK instructions take
hundreds of cycles. While some of this is probably from stronger
memory ordering guarantees, I get the impression that the
operation itself is not aggressively optimized.
Let's see:
variable x 1 x !
variable y -1 y !
: bench-!@
1 5000000 0 do x !@ y !@ loop drop ;
: bench-atomic!@
1 5000000 0 do x atomic!@ y atomic!@ loop drop ;
: bench-+!@
1 5000000 0 do x +!@ y +!@ loop drop ;
: bench-atomic+!@
1 5000000 0 do x atomic+!@ y atomic+!@ loop drop ;
On a Ryzen 8700G (Zen4) each execution of a !@ (exchange) or +!@ (fetch-and-add) costs the following numbers of cycles (including
overhead):
!@ +!@
7.5 7.3 not atomic
14.2 13.2 atomic
On a Xeon E-2388G (Rocket Lake):
!@ +!@
8.5 7.1 not atomic
25.8 26.6 atomic
On 6/3/2026 11:19 AM, Anton Ertl wrote:
variable x 1 x !
variable y -1 y !
: bench-!@
1 5000000 0 do x !@ y !@ loop drop ;
: bench-atomic!@
1 5000000 0 do x atomic!@ y atomic!@ loop drop ;
: bench-+!@
1 5000000 0 do x +!@ y +!@ loop drop ;
: bench-atomic+!@
1 5000000 0 do x atomic+!@ y atomic+!@ loop drop ;
On a Ryzen 8700G (Zen4) each execution of a !@ (exchange) or +!@
(fetch-and-add) costs the following numbers of cycles (including
overhead):
!@ +!@
7.5 7.3 not atomic
14.2 13.2 atomic
On a Xeon E-2388G (Rocket Lake):
!@ +!@
8.5 7.1 not atomic
25.8 26.6 atomic
Hammering a single location is going to be bad for LL/SC or LOCK RMW, >regardless of the ins and outs of LL/SC vs LOCK RMW.
Its up to the
programmer to make sure that is amortized, distributed in clever ways.
For instance, why use a single atomic counter, vs say using a per thread >counter and summing them when we need to observe the actual count?
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 6/3/2026 11:19 AM, Anton Ertl wrote:
variable x 1 x !
variable y -1 y !
: bench-!@
1 5000000 0 do x !@ y !@ loop drop ;
: bench-atomic!@
1 5000000 0 do x atomic!@ y atomic!@ loop drop ;
: bench-+!@
1 5000000 0 do x +!@ y +!@ loop drop ;
: bench-atomic+!@
1 5000000 0 do x atomic+!@ y atomic+!@ loop drop ;
On a Ryzen 8700G (Zen4) each execution of a !@ (exchange) or +!@
(fetch-and-add) costs the following numbers of cycles (including
overhead):
!@ +!@
7.5 7.3 not atomic
14.2 13.2 atomic
On a Xeon E-2388G (Rocket Lake):
!@ +!@
8.5 7.1 not atomic
25.8 26.6 atomic
Hammering a single location is going to be bad for LL/SC or LOCK RMW,
regardless of the ins and outs of LL/SC vs LOCK RMW.
It's two locations in these benchmarks: X and Y.
Its up to the
programmer to make sure that is amortized, distributed in clever ways.
For instance, why use a single atomic counter, vs say using a per thread
counter and summing them when we need to observe the actual count?
These benchmarks use per-thread storage: They are single-threaded.
On 6/3/2026 1:53 PM, Anton Ertl wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 6/3/2026 11:19 AM, Anton Ertl wrote:
variable x 1 x !
variable y -1 y !
: bench-!@
1 5000000 0 do x !@ y !@ loop drop ;
: bench-atomic!@
1 5000000 0 do x atomic!@ y atomic!@ loop drop ;
: bench-+!@
1 5000000 0 do x +!@ y +!@ loop drop ;
: bench-atomic+!@
1 5000000 0 do x atomic+!@ y atomic+!@ loop drop ;
On a Ryzen 8700G (Zen4) each execution of a !@ (exchange) or +!@
(fetch-and-add) costs the following numbers of cycles (including
overhead):
!@ +!@
7.5 7.3 not atomic
14.2 13.2 atomic
On a Xeon E-2388G (Rocket Lake):
!@ +!@
8.5 7.1 not atomic
25.8 26.6 atomic
Hammering a single location is going to be bad for LL/SC or LOCK RMW,
regardless of the ins and outs of LL/SC vs LOCK RMW.
It's two locations in these benchmarks: X and Y.
Its up to the
programmer to make sure that is amortized, distributed in clever ways.
For instance, why use a single atomic counter, vs say using a per thread >>> counter and summing them when we need to observe the actual count?
These benchmarks use per-thread storage: They are single-threaded.
Humm... I missed that. Anyway, you need to test them multi threaded...
Say our counters are per thread so an increment adds to its per-thread counter instead of using a LOCK RMW. Then when the counter needs to be sampled we can start summing up the per thread counts...
I do not think it is impossible for an architecture to make
guarantees about LL/SC operations.
I was at Sequent when we were really serious about moving off Intel
onto MIPS. We looked at LL/SC really, really hard. Lock traces
from current systems, SW simulations, down to gate-level simulations.
We ended up being sufficiently confident (as in, bet the program,
by implication bet the company) that it would work as efficiently
as our current Intel atomics at up to 8-way 64-bit MIPS CPU's. And
that it was very likely to scale without undue incremental design
work to ~32 CPU's.
Paul Clayton <paaronclayton@gmail.com> writes:
I seem to recall reading that x86's LOCK instructions take
hundreds of cycles. While some of this is probably from stronger
memory ordering guarantees, I get the impression that the
operation itself is not aggressively optimized.
Let's see:
variable x 1 x !
variable y -1 y !
: bench-!@
1 5000000 0 do x !@ y !@ loop drop ;
: bench-atomic!@
1 5000000 0 do x atomic!@ y atomic!@ loop drop ;
: bench-+!@
1 5000000 0 do x +!@ y +!@ loop drop ;
: bench-atomic+!@
1 5000000 0 do x atomic+!@ y atomic+!@ loop drop ;
On a Ryzen 8700G (Zen4) each execution of a !@ (exchange) or +!@ (fetch-and-add) costs the following numbers of cycles (including
overhead):
!@ +!@
7.5 7.3 not atomic
14.2 13.2 atomic
On a Xeon E-2388G (Rocket Lake):
!@ +!@
8.5 7.1 not atomic
25.8 26.6 atomic
- anton
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 6/3/2026 11:19 AM, Anton Ertl wrote:
variable x 1 x !
variable y -1 y !
: bench-!@
1 5000000 0 do x !@ y !@ loop drop ;
: bench-atomic!@
1 5000000 0 do x atomic!@ y atomic!@ loop drop ;
: bench-+!@
1 5000000 0 do x +!@ y +!@ loop drop ;
: bench-atomic+!@
1 5000000 0 do x atomic+!@ y atomic+!@ loop drop ;
On a Ryzen 8700G (Zen4) each execution of a !@ (exchange) or +!@
(fetch-and-add) costs the following numbers of cycles (including
overhead):
!@ +!@
7.5 7.3 not atomic
14.2 13.2 atomic
On a Xeon E-2388G (Rocket Lake):
!@ +!@
8.5 7.1 not atomic
25.8 26.6 atomic
Hammering a single location is going to be bad for LL/SC or LOCK RMW,
regardless of the ins and outs of LL/SC vs LOCK RMW.
It's two locations in these benchmarks: X and Y.
Its up to the
programmer to make sure that is amortized, distributed in clever ways.
For instance, why use a single atomic counter, vs say using a per thread
counter and summing them when we need to observe the actual count?
These benchmarks use per-thread storage: They are single-threaded.
- anton
On 2026-Jun-03 14:19, Anton Ertl wrote:...
variable x 1 x !
variable y -1 y !
: bench-!@
1 5000000 0 do x !@ y !@ loop drop ;
: bench-atomic!@
1 5000000 0 do x atomic!@ y atomic!@ loop drop ;
On x86/x64 the exchange instruction XCHG has inplied LOCK prefix
whether it is specified or not. In your example both are atomic.
Andy Valencia <vandys@vsta.org> writes:
I do not think it is impossible for an architecture to make
guarantees about LL/SC operations.
I was at Sequent when we were really serious about moving off Intel
onto MIPS. We looked at LL/SC really, really hard. Lock traces
from current systems, SW simulations, down to gate-level simulations.
We ended up being sufficiently confident (as in, bet the program,
by implication bet the company) that it would work as efficiently
as our current Intel atomics at up to 8-way 64-bit MIPS CPU's. And
that it was very likely to scale without undue incremental design
work to ~32 CPU's.
I was at Unisys in that same timeframe; we had planned on building
the SPP (scalable parallel processor aka OPUS) using motorola 88110
CPUs, until Apple went PPC and Moto canceled 88110. So we investigated MIPS, SPARC and Pentium Pro. Our target was for a 64+ processor
SPP. After evaluation, we chose Pentium Pro to build the system
(using the Intel Paragon backplane).
I don't recall the details of the MIPS evaluation, but we were concerned
at the time about the scalability of LL/SC. SPARC never made it out
of the first evaluation round.
EricP <ThatWouldBeTelling@thevillage.com> writes:
On 2026-Jun-03 14:19, Anton Ertl wrote:...
variable x 1 x !
variable y -1 y !
: bench-!@
1 5000000 0 do x !@ y !@ loop drop ;
: bench-atomic!@
1 5000000 0 do x atomic!@ y atomic!@ loop drop ;
On x86/x64 the exchange instruction XCHG has inplied LOCK prefix
whether it is specified or not. In your example both are atomic.
The code for "x !@" is:
mov 0x8(%rbx),%r15
mov %r13,%rax
mov (%r15),%r13
mov %rax,(%r15)
while the code for "x atomic!@" is:
mov %r13,(%r10)
sub $0x8,%r10
mov 0x8(%rbx),%r13
mov 0x8(%r10),%rax
add $0x8,%r10
xchg %rax,0x0(%r13)
mov %rax,%r13
As you can see, there is no XCHG in the !@ code.
EricP <ThatWouldBeTelling@thevillage.com> writes:
On 2026-Jun-03 14:19, Anton Ertl wrote:...
variable x 1 x !
variable y -1 y !
: bench-!@
1 5000000 0 do x !@ y !@ loop drop ;
: bench-atomic!@
1 5000000 0 do x atomic!@ y atomic!@ loop drop ;
On x86/x64 the exchange instruction XCHG has inplied LOCK prefix
whether it is specified or not. In your example both are atomic.
The code for "x !@" is:
mov 0x8(%rbx),%r15
mov %r13,%rax
mov (%r15),%r13
mov %rax,(%r15)
while the code for "x atomic!@" is:
mov %r13,(%r10)
sub $0x8,%r10
mov 0x8(%rbx),%r13
mov 0x8(%r10),%rax
add $0x8,%r10
xchg %rax,0x0(%r13)
mov %rax,%r13
As you can see, there is no XCHG in the !@ code.
On 6/4/2026 2:04 PM, Anton Ertl wrote:
EricP <ThatWouldBeTelling@thevillage.com> writes:
On 2026-Jun-03 14:19, Anton Ertl wrote:...
variable x 1 x !
variable y -1 y !
: bench-!@
1 5000000 0 do x !@ y !@ loop drop ;
: bench-atomic!@
1 5000000 0 do x atomic!@ y atomic!@ loop drop ;
On x86/x64 the exchange instruction XCHG has inplied LOCK prefix
whether it is specified or not. In your example both are atomic.
The code for "x !@" is:
mov 0x8(%rbx),%r15
mov %r13,%rax
mov (%r15),%r13
mov %rax,(%r15)
while the code for "x atomic!@" is:
mov %r13,(%r10)
sub $0x8,%r10
mov 0x8(%rbx),%r13
mov 0x8(%r10),%rax
add $0x8,%r10
xchg %rax,0x0(%r13)
mov %rax,%r13
As you can see, there is no XCHG in the !@ code.
How is your data organized? Show me the structure?
Paul Clayton <paaronclayton@gmail.com> writes:
I seem to recall reading that x86's LOCK instructions take
hundreds of cycles. While some of this is probably from stronger
memory ordering guarantees, I get the impression that the
operation itself is not aggressively optimized.
On a Ryzen 8700G (Zen4) each execution of a !@ (exchange) or +!@ >(fetch-and-add) costs the following numbers of cycles (including--
overhead):
!@ +!@
7.5 7.3 not atomic
14.2 13.2 atomic
On a Xeon E-2388G (Rocket Lake):
!@ +!@
8.5 7.1 not atomic
25.8 26.6 atomic
- anton
--
'Anyone trying for "industrial quality" ISA should avoid undefined behavior.'
Mitch Alsup, <c17fcd89-f024-40e7-a594-88a85ac10d20o@googlegroups.com>
I don't recall the details of the MIPS evaluation, but we were concerned
at the time about the scalability of LL/SC.
...These benchmarks use per-thread storage: They are single-threaded.
They might be allocated in the same cache line.
On 6/4/2026 2:04 PM, Anton Ertl wrote:...
EricP <ThatWouldBeTelling@thevillage.com> writes:
On 2026-Jun-03 14:19, Anton Ertl wrote:
variable x 1 x !
variable y -1 y !
How is your data organized? Show me the structure?
// padded to a l2 cache line
struct A
{
unsigned word m_data;
char padding[...];
};
// padded to a l2 cache line
struct B
{
unsigned word m_data;
char padding[...];
};
Where A and B are both aligned up to a l2 cache line boundary? We need
to pad _and_ align...
On 6/4/2026 7:21 AM, Scott Lurndal wrote:
Andy Valencia <vandys@vsta.org> writes:
I do not think it is impossible for an architecture to make
guarantees about LL/SC operations.
I was at Sequent when we were really serious about moving off Intel
onto MIPS. We looked at LL/SC really, really hard. Lock traces
from current systems, SW simulations, down to gate-level simulations.
We ended up being sufficiently confident (as in, bet the program,
by implication bet the company) that it would work as efficiently
as our current Intel atomics at up to 8-way 64-bit MIPS CPU's. And
that it was very likely to scale without undue incremental design
work to ~32 CPU's.
I was at Unisys in that same timeframe; we had planned on building
the SPP (scalable parallel processor aka OPUS) using motorola 88110
CPUs, until Apple went PPC and Moto canceled 88110. So we investigated
MIPS, SPARC and Pentium Pro. Our target was for a 64+ processor
SPP. After evaluation, we chose Pentium Pro to build the system
(using the Intel Paragon backplane).
I don't recall the details of the MIPS evaluation, but we were concerned
at the time about the scalability of LL/SC. SPARC never made it out
of the first evaluation round.
Why? I had a SunFire T2000 that, when programmed correctly, was pretty
fast for certain worksets and algorithms. RMO mode.
On 6/4/2026 7:21 AM, Scott Lurndal wrote:
Andy Valencia <vandys@vsta.org> writes:
I do not think it is impossible for an architecture to make
guarantees about LL/SC operations.
I was at Sequent when we were really serious about moving off Intel
onto MIPS. We looked at LL/SC really, really hard. Lock traces
from current systems, SW simulations, down to gate-level
simulations.
We ended up being sufficiently confident (as in, bet the program,
by implication bet the company) that it would work as efficiently
as our current Intel atomics at up to 8-way 64-bit MIPS CPU's. And
that it was very likely to scale without undue incremental design
work to ~32 CPU's.
I was at Unisys in that same timeframe; we had planned on building
the SPP (scalable parallel processor aka OPUS) using motorola 88110
CPUs, until Apple went PPC and Moto canceled 88110. So we
investigated MIPS, SPARC and Pentium Pro. Our target was for a 64+ processor SPP. After evaluation, we chose Pentium Pro to build the
system (using the Intel Paragon backplane).
I don't recall the details of the MIPS evaluation, but we were
concerned at the time about the scalability of LL/SC. SPARC never
made it out of the first evaluation round.
Why? I had a SunFire T2000 that, when programmed correctly, was
pretty fast for certain worksets and algorithms. RMO mode.
On 6/4/2026 7:21 AM, Scott Lurndal wrote:
I don't recall the details of the MIPS evaluation, but we were concerned
at the time about the scalability of LL/SC. SPARC never made it out
of the first evaluation round.
Why? I had a SunFire T2000 that, when programmed correctly, was pretty
fast for certain worksets and algorithms. RMO mode.
EricP <ThatWouldBeTelling@thevillage.com> writes:
...These benchmarks use per-thread storage: They are single-threaded.
They might be allocated in the same cache line.
Given that they are accessed by the same thread, I don't expect that
to hurt, but I did separate the variables by at least 64 bytes in my
recent runs just in case.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
// padded to a l2 cache line
struct A
{
unsigned word m_data;
char padding[...];
};
// padded to a l2 cache line
struct B
{
unsigned word m_data;
char padding[...];
};
Where A and B are both aligned up to a l2 cache line boundary? We need
to pad _and_ align...
Why would alignment to cache-line boundaries be necessary?
Anyway, let's see if it makes a difference.
A) Word-aligned variable, 64 byte padding, another word-aligned
variable (what I measured and posted today). A variable takes space
not just for the data (one word), but also for the metadata (and the
metadata is adjacent to the data).
B) Word-aligned variables, no padding, word-aligned variable, with the
two data words maybe in the same cache line, maybe not (measured
yesterday).
C) Cache-line-aligned word, no padding, another cache-line-aligned
word (i.e., both words in the same cache line).
D) Cache-line-aligned word, (56 bytes of) padding, another
cache-line-aligned word.
E) Cache-line-aligned word, 64 bytes padding, another word (i.e., the
second word is aligned like in C).
F) Word at offset 8 from a cache-line start, 48 bytes padding, another
word (cache-line-aligned).
And here are the results (on a Ryzen 8700G):
The cycles per execution of the relevant word for the
no-atomic/no-barrier variants are:
!@ +!@ barr
2.4 2.4 1.8 A B C
2.4 2.4 1.9 D E
For the atomic/barrier variants the cycles are:
!@ +!@ barr
9.3 8.3 7.2 A
9.2 8.3 7.1 B
9.2 8.3 8.5-11.2 C
9.3 8.3 9.1-11 D
9.1 8.3 7.3-11 E
The variatons for the barrier column are small for A and B (in the
range 6.9-7.2), and quite a bit larger for C-E, and I have no
explanation for that. The other columns show only small variations.
In any case the aligning and padding recommended by you is not
superior to the original code, which just uses two variables.
Here's the code:
1 [if]
variable x 1 x !
64 allot \ make sure the variables are in different cache lines
variable y -1 y !
[else]
: cache-align here dup 64 naligned >align ;
cache-align
here 1 , cache-align here -1 , constant y constant x
[endif]
The part before the [else] is A, comment out "64 allot" for B.
The part after the [else] is D, delete the second CACHE-ALIGN for C,
and replace it with "64 allot" for E.
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
Paul Clayton <paaronclayton@gmail.com> writes:
I seem to recall reading that x86's LOCK instructions take
hundreds of cycles. While some of this is probably from stronger
memory ordering guarantees, I get the impression that the
operation itself is not aggressively optimized.
I have revised the benchmarks as follows: I have added a test of a
memory barrier, which is implemented in GNU C as
__atomic_thread_fence(__ATOMIC_SEQ_CST);
The barriers separate loads.
I have increased the loop count by a factor of 10, because I did not
subtract the startup overhead of Gforth; as a result, the startup
overhead is reduced from 3.3 cycles per execution of the relevant word
to 0.33 cycles.
I have also inserted 64 bytes between the variables, so that they are
in different cache lines. This should not make a difference, because
all accesses are in the same thread (i.e., no cache-ping-pong from
possible false sharing), but just in case.
What I did not do is to use several threads. The idea here is that programmers will take measures that ensure that contention is rare,
but you still need to use atomic instructions and barriers to ensure correctness. Ideally in this case the atomic instructions and
barriers have no extra cost, but in reality, they do have extra cost.
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:[...]
Paul Clayton <paaronclayton@gmail.com> writes:
I seem to recall reading that x86's LOCK instructions take
hundreds of cycles. While some of this is probably from stronger
memory ordering guarantees, I get the impression that the
operation itself is not aggressively optimized.
I have revised the benchmarks as follows: I have added a test of a
memory barrier, which is implemented in GNU C as
__atomic_thread_fence(__ATOMIC_SEQ_CST);
The barriers separate loads.
On 6/5/2026 3:20 AM, Anton Ertl wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
// padded to a l2 cache line
struct A
{
unsigned word m_data;
char padding[...];
};
// padded to a l2 cache line
struct B
{
unsigned word m_data;
char padding[...];
};
Where A and B are both aligned up to a l2 cache line boundary? We need
to pad _and_ align...
Why would alignment to cache-line boundaries be necessary?
Anyway, let's see if it makes a difference.
A) Word-aligned variable, 64 byte padding, another word-aligned
variable (what I measured and posted today). A variable takes space
not just for the data (one word), but also for the metadata (and the
metadata is adjacent to the data).
B) Word-aligned variables, no padding, word-aligned variable, with the
two data words maybe in the same cache line, maybe not (measured
yesterday).
C) Cache-line-aligned word, no padding, another cache-line-aligned
word (i.e., both words in the same cache line).
D) Cache-line-aligned word, (56 bytes of) padding, another
cache-line-aligned word.
E) Cache-line-aligned word, 64 bytes padding, another word (i.e., the
second word is aligned like in C).
F) Word at offset 8 from a cache-line start, 48 bytes padding, another
word (cache-line-aligned).
And here are the results (on a Ryzen 8700G):
The cycles per execution of the relevant word for the
no-atomic/no-barrier variants are:
!@ +!@ barr
2.4 2.4 1.8 A B C
2.4 2.4 1.9 D E
For the atomic/barrier variants the cycles are:
!@ +!@ barr
9.3 8.3 7.2 A
9.2 8.3 7.1 B
9.2 8.3 8.5-11.2 C
9.3 8.3 9.1-11 D
9.1 8.3 7.3-11 E
The variatons for the barrier column are small for A and B (in the
range 6.9-7.2), and quite a bit larger for C-E, and I have no
explanation for that. The other columns show only small variations.
In any case the aligning and padding recommended by you is not
superior to the original code, which just uses two variables.
Well, its mainly for false sharing in a multi threading environment. But
it does matter a bit. If your variables straddle a cache line then it
will trigger a bus lock. Single-threaded avoid straddling cache line boundaries to prevent bus locks on LOCK prefixed instructions
Multi-threaded pad and align to prevent false sharing between
independently accessed variables.
For instance you don't want a mutex word to false share with say an
atomic counter that has nothing to do with the mutex. They need to be
padded and aligned...
Here's the code:
1 [if]
variable x 1 x !
64 allot \ make sure the variables are in different cache lines
variable y -1 y !
[else]
: cache-align here dup 64 naligned >align ;
cache-align
here 1 , cache-align here -1 , constant y constant x
[endif]
The part before the [else] is A, comment out "64 allot" for B.
The part after the [else] is D, delete the second CACHE-ALIGN for C,
and replace it with "64 allot" for E.
On Thu, 4 Jun 2026 18:28:43 -0700
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wrote:
On 6/4/2026 7:21 AM, Scott Lurndal wrote:
Andy Valencia <vandys@vsta.org> writes:
I do not think it is impossible for an architecture to make
guarantees about LL/SC operations.
I was at Sequent when we were really serious about moving off Intel
onto MIPS. We looked at LL/SC really, really hard. Lock traces
from current systems, SW simulations, down to gate-level
simulations.
We ended up being sufficiently confident (as in, bet the program,
by implication bet the company) that it would work as efficiently
as our current Intel atomics at up to 8-way 64-bit MIPS CPU's. And
that it was very likely to scale without undue incremental design
work to ~32 CPU's.
I was at Unisys in that same timeframe; we had planned on building
the SPP (scalable parallel processor aka OPUS) using motorola 88110
CPUs, until Apple went PPC and Moto canceled 88110. So we
investigated MIPS, SPARC and Pentium Pro. Our target was for a 64+
processor SPP. After evaluation, we chose Pentium Pro to build the
system (using the Intel Paragon backplane).
I don't recall the details of the MIPS evaluation, but we were
concerned at the time about the scalability of LL/SC. SPARC never
made it out of the first evaluation round.
Why? I had a SunFire T2000 that, when programmed correctly, was
pretty fast for certain worksets and algorithms. RMO mode.
RMO mode?
I am pretty sure that T2000 had no RMO mode.
If I am not mistaken, the only Sun SPARC CPUs that had RMO in hardware
were UrtraSPARC and UrtraSPARC II.
Starting from UrtraSPARC III Cu, all Sun SPARC processors are documented
to be TSO-only. The processor, for which I didn't find a definite
statement is an original UrtraSPARC III (Chitah), but I would be very surprised if it is not the same as UrtraSPARC III Cu.
SPARC-T line (originaaly named Niagara) was TSO-only from the very
start.
The only remnant of RMO in these processors are Block load and store operations operations - they behave as RMO regardles of processor's
global memory mode.
On 6/5/2026 7:02 AM, Michael S wrote:
On Thu, 4 Jun 2026 18:28:43 -0700
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wrote:
On 6/4/2026 7:21 AM, Scott Lurndal wrote:
Andy Valencia <vandys@vsta.org> writes:
I do not think it is impossible for an architecture to make
guarantees about LL/SC operations.
I was at Sequent when we were really serious about moving off Intel
onto MIPS. We looked at LL/SC really, really hard. Lock traces
from current systems, SW simulations, down to gate-level
simulations.
We ended up being sufficiently confident (as in, bet the program,
by implication bet the company) that it would work as efficiently
as our current Intel atomics at up to 8-way 64-bit MIPS CPU's. And >>>>> that it was very likely to scale without undue incremental design
work to ~32 CPU's.
I was at Unisys in that same timeframe; we had planned on building
the SPP (scalable parallel processor aka OPUS) using motorola 88110
CPUs, until Apple went PPC and Moto canceled 88110. So we
investigated MIPS, SPARC and Pentium Pro. Our target was for a 64+
processor SPP. After evaluation, we chose Pentium Pro to build the
system (using the Intel Paragon backplane).
I don't recall the details of the MIPS evaluation, but we were
concerned at the time about the scalability of LL/SC. SPARC never
made it out of the first evaluation round.
Why? I had a SunFire T2000 that, when programmed correctly, was
pretty fast for certain worksets and algorithms. RMO mode.
RMO mode?
I am pretty sure that T2000 had no RMO mode.
If I am not mistaken, the only Sun SPARC CPUs that had RMO in hardware
were UrtraSPARC and UrtraSPARC II.
Oh shit, I think you are right! I sometimes get my old SPARC boxes mixed
up.
Iirc, UltraSPARC T1 was a full SPARC V9 implementation, and SPARC V9
defines three memory models: TSO, PSO, and RMO.
It still needed an explicit membar for a store followed by a load to
another location, even in TSO.
Actually, I forgot how I go some sparcs in RMO mode. PSTATE?
Starting from UrtraSPARC III Cu, all Sun SPARC processors are documented
to be TSO-only. The processor, for which I didn't find a definite
statement is an original UrtraSPARC III (Chitah), but I would be very
surprised if it is not the same as UrtraSPARC III Cu.
SPARC-T line (originaaly named Niagara) was TSO-only from the very
start.
The only remnant of RMO in these processors are Block load and store
operations operations - they behave as RMO regardles of processor's
global memory mode.
Remember that old thing in one of the SPARC docs that explicitly
mentioned to NEVER put a MEMBAR instruction in the branch delay slot?
On 6/5/2026 7:02 AM, Michael S wrote:
On Thu, 4 Jun 2026 18:28:43 -0700
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wrote:
On 6/4/2026 7:21 AM, Scott Lurndal wrote:
Andy Valencia <vandys@vsta.org> writes:
I do not think it is impossible for an architecture to make
guarantees about LL/SC operations.
I was at Sequent when we were really serious about moving off Intel
onto MIPS. We looked at LL/SC really, really hard. Lock traces
from current systems, SW simulations, down to gate-level
simulations.
We ended up being sufficiently confident (as in, bet the program,
by implication bet the company) that it would work as efficiently
as our current Intel atomics at up to 8-way 64-bit MIPS CPU's. And
that it was very likely to scale without undue incremental design
work to ~32 CPU's.
I was at Unisys in that same timeframe; we had planned on building
the SPP (scalable parallel processor aka OPUS) using motorola 88110
CPUs, until Apple went PPC and Moto canceled 88110. So we
investigated MIPS, SPARC and Pentium Pro. Our target was for a 64+
processor SPP. After evaluation, we chose Pentium Pro to build the
system (using the Intel Paragon backplane).
I don't recall the details of the MIPS evaluation, but we were
concerned at the time about the scalability of LL/SC. SPARC never
made it out of the first evaluation round.
Why? I had a SunFire T2000 that, when programmed correctly, was
pretty fast for certain worksets and algorithms. RMO mode.
RMO mode?
I am pretty sure that T2000 had no RMO mode.
If I am not mistaken, the only Sun SPARC CPUs that had RMO in hardware
were UrtraSPARC and UrtraSPARC II.
Oh shit, I think you are right! I sometimes get my old SPARC boxes mixed up.
Iirc, UltraSPARC T1 was a full SPARC V9 implementation, and SPARC V9
defines three memory models: TSO, PSO, and RMO.
It still needed an explicit membar for a store followed by a load to
another location, even in TSO.
Actually, I forgot how I go some sparcs in RMO mode. PSTATE?
Starting from UrtraSPARC III Cu, all Sun SPARC processors are documented
to be TSO-only. The processor, for which I didn't find a definite
statement is an original UrtraSPARC III (Chitah), but I would be very surprised if it is not the same as UrtraSPARC III Cu.
SPARC-T line (originaaly named Niagara) was TSO-only from the very
start.
The only remnant of RMO in these processors are Block load and store operations operations - they behave as RMO regardles of processor's
global memory mode.
Remember that old thing in one of the SPARC docs that explicitly
mentioned to NEVER put a MEMBAR instruction in the branch delay slot?
On 6/5/2026 12:04 AM, Anton Ertl wrote:
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:[...]
I have revised the benchmarks as follows: I have added a test of a
memory barrier, which is implemented in GNU C as
__atomic_thread_fence(__ATOMIC_SEQ_CST);
The barriers separate loads.
On x86, well, did it fall back to MFENCE? Or use a dummy LOCK RMW on a
per thread stack location?
Anyway, let's see if it makes a difference.[...]
A) Word-aligned variable, 64 byte padding, another word-aligned
variable (what I measured and posted today). A variable takes space
not just for the data (one word), but also for the metadata (and the
metadata is adjacent to the data).
B) Word-aligned variables, no padding, word-aligned variable, with the
two data words maybe in the same cache line, maybe not (measured
yesterday).
C) Cache-line-aligned word, no padding, another cache-line-aligned
word (i.e., both words in the same cache line).
D) Cache-line-aligned word, (56 bytes of) padding, another
cache-line-aligned word.
E) Cache-line-aligned word, 64 bytes padding, another word (i.e., the
second word is aligned like in C).
And here are the results (on a Ryzen 8700G):
The cycles per execution of the relevant word for the
no-atomic/no-barrier variants are:
!@ +!@ barr
2.4 2.4 1.8 A B C
2.4 2.4 1.9 D E
For the atomic/barrier variants the cycles are:
!@ +!@ barr
9.3 8.3 7.2 A
9.2 8.3 7.1 B
9.2 8.3 8.5-11.2 C
9.3 8.3 9.1-11 D
9.1 8.3 7.3-11 E
The variatons for the barrier column are small for A and B (in the
range 6.9-7.2), and quite a bit larger for C-E, and I have no
explanation for that.
On 6/5/2026 3:20 AM, Anton Ertl wrote:[...]
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
// padded to a l2 cache line
struct A
{
unsigned word m_data;
char padding[...];
};
// padded to a l2 cache line
struct B
{
unsigned word m_data;
char padding[...];
};
Where A and B are both aligned up to a l2 cache line boundary? We need
to pad _and_ align...
Why would alignment to cache-line boundaries be necessary?
...A) Word-aligned variable, 64 byte padding, another word-aligned
variable (what I measured and posted today). A variable takes space
not just for the data (one word), but also for the metadata (and the
metadata is adjacent to the data).
B) Word-aligned variables, no padding, word-aligned variable, with the
two data words maybe in the same cache line, maybe not (measured
yesterday).
C) Cache-line-aligned word, no padding, another cache-line-aligned
word (i.e., both words in the same cache line).
D) Cache-line-aligned word, (56 bytes of) padding, another
cache-line-aligned word.
E) Cache-line-aligned word, 64 bytes padding, another word (i.e., the
second word is aligned like in C).
F) Word at offset 8 from a cache-line start, 48 bytes padding, another
word (cache-line-aligned).
Well, its mainly for false sharing in a multi threading environment. But
it does matter a bit. If your variables straddle a cache line then it
will trigger a bus lock.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> posted:
On 6/5/2026 7:02 AM, Michael S wrote:SPARC used nullification in delay slots.
On Thu, 4 Jun 2026 18:28:43 -0700
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wrote:
On 6/4/2026 7:21 AM, Scott Lurndal wrote:
Andy Valencia <vandys@vsta.org> writes:
I do not think it is impossible for an architecture to make
guarantees about LL/SC operations.
I was at Sequent when we were really serious about moving off Intel >>>>>> onto MIPS. We looked at LL/SC really, really hard. Lock traces
from current systems, SW simulations, down to gate-level
simulations.
We ended up being sufficiently confident (as in, bet the program,
by implication bet the company) that it would work as efficiently
as our current Intel atomics at up to 8-way 64-bit MIPS CPU's. And >>>>>> that it was very likely to scale without undue incremental design
work to ~32 CPU's.
I was at Unisys in that same timeframe; we had planned on building
the SPP (scalable parallel processor aka OPUS) using motorola 88110
CPUs, until Apple went PPC and Moto canceled 88110. So we
investigated MIPS, SPARC and Pentium Pro. Our target was for a 64+
processor SPP. After evaluation, we chose Pentium Pro to build the
system (using the Intel Paragon backplane).
I don't recall the details of the MIPS evaluation, but we were
concerned at the time about the scalability of LL/SC. SPARC never
made it out of the first evaluation round.
Why? I had a SunFire T2000 that, when programmed correctly, was
pretty fast for certain worksets and algorithms. RMO mode.
RMO mode?
I am pretty sure that T2000 had no RMO mode.
If I am not mistaken, the only Sun SPARC CPUs that had RMO in hardware
were UrtraSPARC and UrtraSPARC II.
Oh shit, I think you are right! I sometimes get my old SPARC boxes mixed up. >>
Iirc, UltraSPARC T1 was a full SPARC V9 implementation, and SPARC V9
defines three memory models: TSO, PSO, and RMO.
It still needed an explicit membar for a store followed by a load to
another location, even in TSO.
Actually, I forgot how I go some sparcs in RMO mode. PSTATE?
Starting from UrtraSPARC III Cu, all Sun SPARC processors are documented >>> to be TSO-only. The processor, for which I didn't find a definite
statement is an original UrtraSPARC III (Chitah), but I would be very
surprised if it is not the same as UrtraSPARC III Cu.
SPARC-T line (originaaly named Niagara) was TSO-only from the very
start.
The only remnant of RMO in these processors are Block load and store
operations operations - they behave as RMO regardles of processor's
global memory mode.
Remember that old thing in one of the SPARC docs that explicitly
mentioned to NEVER put a MEMBAR instruction in the branch delay slot?
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 6/5/2026 3:20 AM, Anton Ertl wrote:[...]
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
// padded to a l2 cache line
struct A
{
unsigned word m_data;
char padding[...];
};
// padded to a l2 cache line
struct B
{
unsigned word m_data;
char padding[...];
};
Where A and B are both aligned up to a l2 cache line boundary? We need >>>> to pad _and_ align...
Why would alignment to cache-line boundaries be necessary?
...A) Word-aligned variable, 64 byte padding, another word-aligned
variable (what I measured and posted today). A variable takes space
not just for the data (one word), but also for the metadata (and the
metadata is adjacent to the data).
B) Word-aligned variables, no padding, word-aligned variable, with the
two data words maybe in the same cache line, maybe not (measured
yesterday).
C) Cache-line-aligned word, no padding, another cache-line-aligned
word (i.e., both words in the same cache line).
D) Cache-line-aligned word, (56 bytes of) padding, another
cache-line-aligned word.
E) Cache-line-aligned word, 64 bytes padding, another word (i.e., the
second word is aligned like in C).
F) Word at offset 8 from a cache-line start, 48 bytes padding, another
word (cache-line-aligned).
Well, its mainly for false sharing in a multi threading environment. But
it does matter a bit. If your variables straddle a cache line then it
will trigger a bus lock.
All of the data placement variants use word-aligned words and thus do
not straddle cache lines. But your claim was that one should use only
the first word in a cache line. Avoiding false sharing is important,
if there is any sharing, but that's not the case for this benchmark.
On 6/5/2026 6:44 PM, MitchAlsup wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> posted:
On 6/5/2026 7:02 AM, Michael S wrote:SPARC used nullification in delay slots.
On Thu, 4 Jun 2026 18:28:43 -0700
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wrote:
On 6/4/2026 7:21 AM, Scott Lurndal wrote:
Andy Valencia <vandys@vsta.org> writes:
I do not think it is impossible for an architecture to make
guarantees about LL/SC operations.
I was at Sequent when we were really serious about moving off Intel >>>>>>> onto MIPS. We looked at LL/SC really, really hard. Lock traces >>>>>> >from current systems, SW simulations, down to gate-level
simulations.
We ended up being sufficiently confident (as in, bet the program, >>>>>>> by implication bet the company) that it would work as efficiently >>>>>>> as our current Intel atomics at up to 8-way 64-bit MIPS CPU's. And >>>>>>> that it was very likely to scale without undue incremental design >>>>>>> work to ~32 CPU's.
I was at Unisys in that same timeframe; we had planned on building >>>>>> the SPP (scalable parallel processor aka OPUS) using motorola 88110 >>>>>> CPUs, until Apple went PPC and Moto canceled 88110. So we
investigated MIPS, SPARC and Pentium Pro. Our target was for a 64+ >>>>>> processor SPP. After evaluation, we chose Pentium Pro to build the >>>>>> system (using the Intel Paragon backplane).
I don't recall the details of the MIPS evaluation, but we were
concerned at the time about the scalability of LL/SC. SPARC never >>>>>> made it out of the first evaluation round.
Why? I had a SunFire T2000 that, when programmed correctly, was
pretty fast for certain worksets and algorithms. RMO mode.
RMO mode?
I am pretty sure that T2000 had no RMO mode.
If I am not mistaken, the only Sun SPARC CPUs that had RMO in hardware >>>> were UrtraSPARC and UrtraSPARC II.
Oh shit, I think you are right! I sometimes get my old SPARC boxes
mixed up.
Iirc, UltraSPARC T1 was a full SPARC V9 implementation, and SPARC V9
defines three memory models: TSO, PSO, and RMO.
It still needed an explicit membar for a store followed by a load to
another location, even in TSO.
Actually, I forgot how I go some sparcs in RMO mode. PSTATE?
Starting from UrtraSPARC III Cu, all Sun SPARC processors are
documented
to be TSO-only. The processor, for which I didn't find a definite
statement is an original UrtraSPARC III (Chitah), but I would be very
surprised if it is not the same as UrtraSPARC III Cu.
SPARC-T line (originaaly named Niagara) was TSO-only from the very
start.
The only remnant of RMO in these processors are Block load and store
operations operations - they behave as RMO regardles of processor's
global memory mode.
Remember that old thing in one of the SPARC docs that explicitly
mentioned to NEVER put a MEMBAR instruction in the branch delay slot?
Iirc, might be wrong here, a MEMBAR can force processor serialization or stall the pipeline until the store buffers drain, executing it right
when the processor is updating the PC and nPC for a branch created nasty timing hazards? God its been a long time since I read the docs...
On 6/6/2026 11:25 AM, Chris M. Thomasson wrote:
On 6/5/2026 6:44 PM, MitchAlsup wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> posted:
On 6/5/2026 7:02 AM, Michael S wrote:SPARC used nullification in delay slots.
On Thu, 4 Jun 2026 18:28:43 -0700
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wrote:
On 6/4/2026 7:21 AM, Scott Lurndal wrote:
Andy Valencia <vandys@vsta.org> writes:
I do not think it is impossible for an architecture to make
guarantees about LL/SC operations.
I was at Sequent when we were really serious about moving off Intel >>>>>>>> onto MIPS. We looked at LL/SC really, really hard. Lock traces >>>>>>> >from current systems, SW simulations, down to gate-level
simulations.
We ended up being sufficiently confident (as in, bet the program, >>>>>>>> by implication bet the company) that it would work as efficiently >>>>>>>> as our current Intel atomics at up to 8-way 64-bit MIPS CPU's. And >>>>>>>> that it was very likely to scale without undue incremental design >>>>>>>> work to ~32 CPU's.
I was at Unisys in that same timeframe; we had planned on building >>>>>>> the SPP (scalable parallel processor aka OPUS) using motorola 88110 >>>>>>> CPUs, until Apple went PPC and Moto canceled 88110. So we
investigated MIPS, SPARC and Pentium Pro. Our target was for a 64+ >>>>>>> processor SPP. After evaluation, we chose Pentium Pro to build the >>>>>>> system (using the Intel Paragon backplane).
I don't recall the details of the MIPS evaluation, but we were
concerned at the time about the scalability of LL/SC. SPARC never >>>>>>> made it out of the first evaluation round.
Why? I had a SunFire T2000 that, when programmed correctly, was
pretty fast for certain worksets and algorithms. RMO mode.
RMO mode?
I am pretty sure that T2000 had no RMO mode.
If I am not mistaken, the only Sun SPARC CPUs that had RMO in hardware >>>>> were UrtraSPARC and UrtraSPARC II.
Oh shit, I think you are right! I sometimes get my old SPARC boxes
mixed up.
Iirc, UltraSPARC T1 was a full SPARC V9 implementation, and SPARC V9
defines three memory models: TSO, PSO, and RMO.
It still needed an explicit membar for a store followed by a load to
another location, even in TSO.
Actually, I forgot how I go some sparcs in RMO mode. PSTATE?
Starting from UrtraSPARC III Cu, all Sun SPARC processors are
documented
to be TSO-only. The processor, for which I didn't find a definite
statement is an original UrtraSPARC III (Chitah), but I would be very >>>>> surprised if it is not the same as UrtraSPARC III Cu.
SPARC-T line (originaaly named Niagara) was TSO-only from the very
start.
The only remnant of RMO in these processors are Block load and store >>>>> operations operations - they behave as RMO regardles of processor's
global memory mode.
Remember that old thing in one of the SPARC docs that explicitly
mentioned to NEVER put a MEMBAR instruction in the branch delay slot?
Iirc, might be wrong here, a MEMBAR can force processor serialization
or stall the pipeline until the store buffers drain, executing it
right when the processor is updating the PC and nPC for a branch
created nasty timing hazards? God its been a long time since I read
the docs...
Or iirc, sometimes in certain use cases, the branch delay slot might not
be executed? Even with programming it directly in ASM and using GAS to assemble it?
| Sysop: | DaiTengu |
|---|---|
| Location: | Appleton, WI |
| Users: | 1,127 |
| Nodes: | 10 (0 / 10) |
| Uptime: | 36:58:05 |
| Calls: | 14,430 |
| Files: | 186,410 |
| D/L today: |
455 files (130M bytes) |
| Messages: | 2,552,605 |