#How to switch active field of an union?

1 messages · Page 1 of 1 (latest)

eternal cove
#

I have this (not working code)

pub const EntityRef = union {
    index: hh.SEI,
    ptr: ?*SimEntity,
};
//field
    sword: EntityRef = .{ .index = 0 },

switch to ptr:

if (e.sword.index != 0) {
    const index = e.sword.index;
    e.sword.ptr = null;
    for (0..sr.entityCount) |hri| {
        const refE: *SimEntity = &sr.entities[hri];
        if (refE.storageIndex == index) {
            e.sword.ptr = refE;
            break;
        }
    }
    if (e.sword.ptr == null) {
        const fInf = @import("std").math.inf(f32);
        const inf = math.v2f32{ .x = fInf, .y = fInf };
        const simIndex = add(sr, index, inf, &state.storedEntities[index], false);
        e.sword.ptr = &sr.entities[simIndex];
    }
} else {
    e.sword.ptr = null;
}

switch to index:

if (se.sim.sword.ptr) |ptr| {
    se.sim.sword.index = ptr.storageIndex;
} else {
    se.sim.sword.index = 0;
}

RUNTIME Error

panic: access of union field 'ptr' while field 'index' is active
simRegion.zig:201:24: 0x7ff95abd57ab in begin (HandmadeHeroZig_zcu.obj)
e.sword.ptr = null;
I would like to switch the active field to ptr, instead of "accessing it", I want to assign it.

subtle dome
#

you just do

e.sword = .{.ptr = null};
eternal cove
#

Secondary question, how can I make it more performant?

subtle dome
#

in what regard? setting the active field?

eternal cove
#

I do it in a loop over ~100 entities, and it takes over 10000 CPU cycles, that is over 100 CPU cycles to do: field access, check 0 == 0, increment, loop check

subtle dome
#

debug build?

eternal cove
#

Yes

#

The disassembly looks crazy:

> e.sword = .{ .ptr = null };
  0x00007ff76f2efb07  mov rcx, [rbp+0x2C0]
  0x00007ff76f2efb0e  mov byte ptr [rcx+0x08], 0x01
  0x00007ff76f2efb12  mov qword ptr [rcx], 0x00
> if (index != 0) {
  0x00007ff76f2efb19  test eax, eax
  0x00007ff76f2efb1b  jnz 0x00007FF76F2EFB4F (begin)
  0x00007ff76f2efb1d  jmp 0x00007FF76F2EFB6D (begin)
> const index = e.sword.index;
  0x00007ff76f2efb1f  jmp 0x00007FF76F2EFAE5 (begin)
  0x00007ff76f2efb21  mov dl, [rbp+0x33]
  0x00007ff76f2efb24  mov rcx, [rbp+0x100]
  0x00007ff76f2efb2b  xor eax, eax
  0x00007ff76f2efb2d  mov r8b, al
  0x00007ff76f2efb30  call 0x00007FF76F2F0090 (inactiveUnionField__anon_58156)
> hi += 1;
  0x00007ff76f2efb35  mov eax, [rbp+0x2BC]
> hi += 1;
  0x00007ff76f2efb3b  add eax, 0x01
  0x00007ff76f2efb3e  mov [rbp+0x20], eax
  0x00007ff76f2efb41  setb al
  0x00007ff76f2efb44  jb 0x00007FF76F2EFD85 (begin)
  0x00007ff76f2efb4a  jmp 0x00007FF76F2EFD91 (begin)
> if (index != 0) {
  0x00007ff76f2efb4f  mov qwo
subtle dome
#

yeah, zig embeds a hidden tag for unions in safe mode

#

that's how it checks that you're accessing an inactive field

eternal cove
#

Compared to C++ (which does not need reassignment)

> if (e->sword.index) {
  0x00007ff9a1f53a43  mov rax, [rsp+0x50]
  0x00007ff9a1f53a48  cmp dword ptr [rax+0x48], 0x00
  0x00007ff9a1f53a4c  jz 0x00007FF9A1F53B4B (beginSim)
subtle dome
#

if you compile in ReleaseFast, it should be the same

eternal cove
#

I do not want to disable them globally, so I guess I do:

pub const EntityRef = blck: {
    @setRuntimeSafety(false);
    break :blck union {
        index: hh.SEI,
        ptr: ?*SimEntity,
    };
};

Or do I have any better option?

subtle dome
#

i don't think that's how you do it, you set the runtime safety in the function, the hidden tag will still be there but won't be used

#

you can also use extern union if you really want to eliminate the hidden tag

quick shard
#

why are u trying to optimize debug mode performance?

subtle dome
#

but then you can't use zig's auto layout structs

eternal cove
eternal cove
quick shard
#

okay but I'm asking why the performance is an issue in ur case specifically

#

10k CPU cycles is basically nothing, so what performance issues are u actually seeing in practice?

eternal cove
#

Do you know HandmadeHero?
I am trying to loosely follow that tutorial to make a game.

quick shard
#

okay, and is this union causing frame drops in debug mode?

eternal cove
quick shard
#

and without?

eternal cove
#

It stutters like crazy

quick shard
#

interesting, that surprises me

subtle dome
#

do try to run with ReleaseSafe and see how it performs

#

with the @setRuntimeSafety(false) commented out of course

quick shard
#

cuz 10k clock cycles is like, 3 microseconds

subtle dome
#

1000 loops = 3 milliseconds

quick shard
#

they said they're looping over 100 entities tho

#

not 100k entities

eternal cove
#

🤔 it is over a milion on whole frame, but I do touch that field only 2 more times per frame 🤔

quick shard
#

it should not be causing frame drops unless it's just the final straw that pushes it past being able to keep up with syncs

#

wait u said 30fps? that seems sus, are u not able to keep a stable 60 normally?

#

i would recommend doing some profiling to see what's actually taking up the most time

#

i would be very surprised if it's actually this union that's causing the main problem

eternal cove
#

I use RDTS for measuring which should be roughly CPU cycles, but now I am confused, where are the cycles lost, when the only difference is @setRuntimeSafety(false) on that union 🤔

The Time Stamp Counter (TSC) is a 64-bit register present on all x86 processors since the Pentium. It counts the number of CPU cycles since its reset. The instruction RDTSC returns the TSC in EDX:EAX. In x86-64 mode, RDTSC also clears the upper 32 bits of RAX and RDX. Its opcode is 0F 31. Pentium competitors such as the Cyrix 6x86 did not always...

eternal cove
eternal cove
quick shard
quick shard
#

yeah that sounds like the issue lmao

#

maybe disable runtime safety in the software renderer

quick shard
eternal cove
quick shard
#

oh, yea that's prolly fine

eternal cove
#

I do not know, how I would go about profiling, "what makes 1% difference", that pushes it over frame boundary...
Binary diffing 1.8 MB also does not seems like good idea

quick shard
#

run it in a sampling profiler to get a basic idea of what's taking time, then use instrumentation to narrow it down

#

Tracy is decent at both

eternal cove
trim arch
quick shard
eternal cove
#

🤔 neither of them showed in first 10 results