Comments (15)
from disruptor-net.
I'm surprised this doesn't thow an InvalidProgramException
. This changes a &
type on the stack to an O
type, and arithmethic on those is not supported:
from disruptor-net.
It's weird - the distinction between object reference and managed pointer is of little value. Object reference is a manager pointer to a method table. The math should work, only the verifier could complain.
But, .NET itself uses RawArrayData
and supposedly it's as fast as it could be, and safe. They could do that because it's only .NET Core, they do not need to account for different layout because they define it.
Calculating the array data offset and storing it in a static readonly
proves to be difficult, JIT magic with treating it as a constant does not happen, at least reliably. It requires tiered compilation and the value must be initialized in tier 0 to be treated as a constant in tier 1, any long-running loops must be recompiled in tier 1.
However, we could change ArrayDataOffset
to calculate the offset not from the method table, but from the first data byte. Like this:
public static unsafe int ArrayDataOffset2
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => sizeof(IntPtr) == 4
? RuntimeHelpers.OffsetToStringData == 8 ? 4 : 12
: RuntimeHelpers.OffsetToStringData == 12 ? 8 : 24;
}
private class RawData<T>
{
public T Data = default!;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Read1<T>(object array, int index)
where T : class
{
return Unsafe.AddByteOffset(ref Unsafe.As<RawData<T>>(array).Data, (nint)(uint)(ArrayDataOffset2 + index * Unsafe.SizeOf<T>()));
}
On my current noisy machine where lots of stuff running this gives very significant throughput improvement for current master in OneToOneSequencedThroughputTest_ThreadAffinity
bench, both on the same and different cores.
Need to check ArrayDataOffset2
values for cases other than x64 .NET Core.
I will send a PR for that.
from disruptor-net.
Brr, this throughput numbers mean very little with different batching on a noisy machine. Need more precise measurement and some extra work 😄
from disruptor-net.
It's weird - the distinction between object reference and managed pointer is of little value. Object reference is a manager pointer to a method table. The math should work, only the verifier could complain.
Yes, I know about that, but the spec is pretty explicit about it:
Managed pointers are not interchangeable with object references.
Though the current code is storing an O
value in a &
local, and I couldn't find a mention in ECMA-335 which would allow that in the first place...
from disruptor-net.
However, we could change ArrayDataOffset to calculate the offset not from the method table, but from the first data byte.
You should calculate this using an array instead of a regular object (T[]
instead of RawData<T>
) as you should not assume the CLR uses the same layout for objects and for arrays.
from disruptor-net.
@ltrzesniewski Unsafe.As<RawData<T>>(array).Data
points right after the method table. What we do now is pointing to the method table. In array case, the .Data
points to its Length slot. Do you know about differences in the method table size? Or other stuff that could be placed before .Data
on different implementations?
from disruptor-net.
In array case, the
.Data
points to its Length slot.
Exactly. Don't we want the offset between the first element and the method table, thus skipping the length slot?
from disruptor-net.
Don't we want the offset between the first element and the method table, thus skipping the length slot?
We can calculate it, but we cannot make it a JIT constant in easy way.
So now we have on x64: FirstOffset = MT_Ptr + ArrayDataOffset = MT_Ptr + 8 (MT_PtrSize) [.Data is here] + 4 (uint Length) + 4 (Padding)
. What I propose is to just point past MT_Ptr and use existing knowledge about different stuff after .Data on different implementations.
from disruptor-net.
we cannot make it a JIT constant in easy way.
Oh, ok, I see 👍
use existing knowledge about different stuff after .Data on different implementations.
But that's exactly what ArrayDataOffset
does... how would you like to change that more precisely?
from disruptor-net.
But that's exactly what ArrayDataOffset does... how would you like to change that more precisely?
By using Unsafe and not Ldind.Ref
and still avoiding locals.
from disruptor-net.
Oh, ok, sorry, I misunderstood what you were saying earlier 👍
from disruptor-net.
Also this comment about managed pointers to zero: dotnet/coreclr#20386
So I'm confused.
from disruptor-net.
The current implementation is optimal for x-plat.
For .NET Core it works even with simple Ldarg(nameof(array)) + offset
, and I think it should works like that and the O and & separation is artificial both conceptually and implementation-wise. But for this kind of things there is the linked discussion.
from disruptor-net.
I suppose the reason for having both O
and &
types is performance: GC scans should be faster for O
types, as the GC can assume the value is a pointer to a method table. This gets more complicated for &
values, which can point to anywhere inside an object.
But I'm very interested in the answer to your linked question. 🙂
from disruptor-net.
Related Issues (20)
- Strong Naming the Disruptor Assembly? HOT 2
- EventPoller for ValueRingBuffer HOT 5
- Does Disruptor support asynchronous EventHandler? HOT 4
- EventHandlerGroup<T>.And(EventHandlerGroup<T> eventHandlerGroup) usage HOT 4
- Long-running EventHandler causes high CPU consumption HOT 5
- Error: Unknown command 'Build-Assembly'.
- DynamiclyAddHandler can't work HOT 1
- Task-based handlers HOT 4
- Remove cake usage
- Add a wiki page to explain event handler interfaces HOT 1
- Is it safe to use Disruptor with System.IO.Pipelines without extra allocations? HOT 11
- Is there a way to ensure backpressure on producers and not overwrite? HOT 13
- Is it safe/possible to use ByRefLike value types as events for ValueDisruptor? HOT 2
- .NET 6 support HOT 12
- Buffer getting full HOT 3
- Batch rewind HOT 9
- IAsyncBatchEventHandler with CancellationToken HOT 3
- Question about whether to use one ringbuffer with 5 handlers or 5 ringbuffers with one handler each HOT 8
- CPU Friendly IAsyncWaitStrategy? HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from disruptor-net.