Thread overview
Event struct via registers
Aug 10
IchorDev
Aug 11
claptrap
Aug 10
Basile B.
August 10

Trouble 1

Pass the structure through registers ?

Trouble 2

Wrap the registries in a structure ?

Use case

I need to pass different events: Draw_Event, Mouse_Move_Event, ...
I need to pass an event to many objects: foreach (o; world) o.event (e);
I need speed.
I want to pass the structure in registers: (like __fastcall callin convention): void _event (REG r1, REG r2, REG r3, REG r4);. But it's hard to read.
I want comfortable use: (like a wrap registers in struct):

void
event (Event e) {
    writeln (e.type);
    writeln (e.code);
    writeln (e.value);
    switch (e.type) {
      case Type.REL: _rel_event (e); break;
      case Type.GUI: _gui_event (e); break;
      case Type.APP: _app_event (e); break;
      default:
    }
}

The problem is that the size of the structure is larger than the size of the register.

struct
Event {          //  64 bit
  ushort type;   //  16 bit
  ushort code;   //  16 bit
  uint   value;  //  32 bit
}

But the event size can be > 64 bit. More than register size.

struct
Mouse_Event {    // 128 bit
  ushort type;   //  16 bit
  ushort code;   //  16 bit
  uint   value;  //  32 bit
  float  x;      //  32 bit
  float  y;      //  32 bit
}

struct
Draw_Event {     // 192 bit
  ushort type;   //  16 bit
  ushort code;   //  16 bit
  uint   value;  //  32 bit
  float  x;      //  32 bit
  float  y;      //  32 bit
  float  w;      //  32 bit
  float  h;      //  32 bit
}

How to implement on D?

August 10

On Saturday, 10 August 2024 at 07:46:46 UTC, Vitaliy Fadeev wrote:

>

Trouble 1

Pass the structure through registers ?

Trouble 2

Wrap the registries in a structure ?
How to implement on D?

I try:

import std.stdio;

void
main() {
	Event_1 event_1;
	event (event_1);

	Event_2 event_2;
	event (event_2);
}

struct
Event_1 {
    ushort type  = 1;
    ushort code  = 2;
    uint   value = 3;
}

struct
Event_2 {
    ushort type  = 1;
    ushort code  = 2;
    uint   value = 3;
    float  x = 4.0;
    float  y = 5.0;
}


void
event (EVENT) (/* R this, */ EVENT e) {
    enum REG_SIZE = (void*).sizeof; // Bytes
    pragma (msg, EVENT, " : ", EVENT.sizeof);
    pragma (msg, "REG_SIZE: ", REG_SIZE);
    static if (EVENT.sizeof == 0) {
        //
    }
    else
    static if (EVENT.sizeof <= REG_SIZE) {  //  64 bit
        _event (/* this, */
            * cast (REG*) &e,
            //* cast (REG*) cast (ubyte*) &e,
            //cast (REG) *(
            //  (cast (ubyte*) &e)[0..EVENT.sizeof].ptr
            //),
            0,
            0);
    }
    else
    static if (EVENT.sizeof <= 2*REG_SIZE) {  // 128 bit
        _event (/* this, */
            cast (REG) *(
                (cast (ubyte*) &e)[0..REG_SIZE].ptr
            ),
            cast (REG) *(
                (cast (ubyte*) &e)[REG_SIZE..EVENT.sizeof].ptr
            ),
            0);
    }
    else
        static assert (0, "Event sizeof too much");
}

alias REG = ulong;

void
_event (/* REG this, */ REG type_code_value, REG r3, REG r4) {
    //switch (type_code_value.type) {
    //    case Event.Type.GUI: gui.event (type_code_value, r3, r4); break;
    //    default:
    //}
    writeln ("type_code_value: ", type_code_value);
    writeln ("r3: ", r3);
    writeln ("r4: ", r4);

    Event_1 event_1;
    event_1 = * cast (Event_1*) &type_code_value;

    writeln ("  event_1 :", event_1);

    if (r3 != 0) {
        writeln ("  event_2 :", r3);
    }
}

But i have 0 in r3.
I need help converting the structure Event_2 into 2 ulong parameters type_code_value, r3.

August 10

On Saturday, 10 August 2024 at 07:46:46 UTC, Vitaliy Fadeev wrote:

>

Trouble 1

Pass the structure through registers ?

Trouble 2

Wrap the registries in a structure ?

Use case

I need to pass different events: Draw_Event, Mouse_Move_Event, ...
I need to pass an event to many objects: foreach (o; world) o.event (e);
I need speed.
I want to pass the structure in registers: (like __fastcall callin convention): void _event (REG r1, REG r2, REG r3, REG r4);. But it's hard to read.
I want comfortable use: (like a wrap registers in struct):

void
event (Event e) {
    writeln (e.type);
    writeln (e.code);
    writeln (e.value);
    switch (e.type) {
      case Type.REL: _rel_event (e); break;
      case Type.GUI: _gui_event (e); break;
      case Type.APP: _app_event (e); break;
      default:
    }
}

The problem is that the size of the structure is larger than the size of the register.

struct
Event {          //  64 bit
  ushort type;   //  16 bit
  ushort code;   //  16 bit
  uint   value;  //  32 bit
}

But the event size can be > 64 bit. More than register size.

struct
Mouse_Event {    // 128 bit
  ushort type;   //  16 bit
  ushort code;   //  16 bit
  uint   value;  //  32 bit
  float  x;      //  32 bit
  float  y;      //  32 bit
}

struct
Draw_Event {     // 192 bit
  ushort type;   //  16 bit
  ushort code;   //  16 bit
  uint   value;  //  32 bit
  float  x;      //  32 bit
  float  y;      //  32 bit
  float  w;      //  32 bit
  float  h;      //  32 bit
}

How to implement on D?

This depends on the calling convention used by your compiler and on your CPU architecture. 64 bits is already 2 data registers on a 32-bit CPU. There are also many calling conventions that allow multiple data registers to be used when passing structs around.

Do you really need to avoid them being passed on the stack though? Is your application highly performance critical? (i.e. kernel code) You could also use ref const to avoid the copying, but your data will probably always be on the stack that way.

August 10

On Saturday, 10 August 2024 at 08:04:10 UTC, Vitaliy Fadeev wrote:

>

On Saturday, 10 August 2024 at 07:46:46 UTC, Vitaliy Fadeev wrote:

>

Trouble 1

Pass the structure through registers ?

Trouble 2

Wrap the registries in a structure ?
How to implement on D?

I try:
...

But i have 0 in r3.
I need help converting the structure Event_2 into 2 ulong parameters type_code_value, r3.

D online editor: https://run.dlang.io/gist/vitalfadeev/38ffcd289bb87c7e02a4992f698090d0?compiler=dmd

August 10

On Saturday, 10 August 2024 at 08:06:42 UTC, IchorDev wrote:

>

On Saturday, 10 August 2024 at 07:46:46 UTC, Vitaliy Fadeev wrote:

>

[...]

This depends on the calling convention used by your compiler and on your CPU architecture. 64 bits is already 2 data registers on a 32-bit CPU. There are also many calling conventions that allow multiple data registers to be used when passing structs around.

Do you really need to avoid them being passed on the stack though?

Yes.

>

Is your application highly performance critical?
Many input event + many internal ui events -> many calls * many objects.

Yes, I like the fast, responsive interface on old hardware (as B970 CPU).

August 10

On Saturday, 10 August 2024 at 08:10:10 UTC, Vitaliy Fadeev wrote:

>

On Saturday, 10 August 2024 at 08:04:10 UTC, Vitaliy Fadeev wrote:

>

On Saturday, 10 August 2024 at 07:46:46 UTC, Vitaliy Fadeev wrote:

>

Trouble 1

Pass the structure through registers ?

Trouble 2

Wrap the registries in a structure ?
How to implement on D?

I try:
...

But i have 0 in r3.
I need help converting the structure Event_2 into 2 ulong parameters type_code_value, r3.

D online editor: https://run.dlang.io/gist/vitalfadeev/38ffcd289bb87c7e02a4992f698090d0?compiler=dmd

May be union ?

August 10

On Saturday, 10 August 2024 at 08:29:20 UTC, Vitaliy Fadeev wrote:

>

On Saturday, 10 August 2024 at 08:10:10 UTC, Vitaliy Fadeev wrote:

>

On Saturday, 10 August 2024 at 08:04:10 UTC, Vitaliy Fadeev wrote:

>

On Saturday, 10 August 2024 at 07:46:46 UTC, Vitaliy Fadeev wrote:

>

Trouble 1

Pass the structure through registers ?

Trouble 2

Wrap the registries in a structure ?
How to implement on D?

I try:
...

But i have 0 in r3.
I need help converting the structure Event_2 into 2 ulong parameters type_code_value, r3.

D online editor: https://run.dlang.io/gist/vitalfadeev/38ffcd289bb87c7e02a4992f698090d0?compiler=dmd

May be union ?

Thanks, all, for energy!
I do it with union:

struct
Convertor (T) {
    union {
        T from;
            struct {
                REG r1;
                REG r2;
                REG r3;
                REG r4;
        }
    }
}
    auto convertor = Convertor!(EVENT) (e);
    _event (/* this, */ convertor.r1, convertor.r2, convertor.r3);
August 10

On Saturday, 10 August 2024 at 07:46:46 UTC, Vitaliy Fadeev wrote:

>

Trouble 1

Pass the structure through registers ?

[...]

How to implement on D?

You dont need to pass whole event. The obvious design for this kind of things is that you declare a local event that's an union of all possible things then in the low level event loop you dispatch the members of interest to the high level consumer.

This is for example how this worked in kheops:

  1. low level event loop with the big local union (an XEvent): https://gitlab.com/basile.b/kheops/-/blob/master/src/kheops/control.d?ref_type=heads#L2770

  2. example of dispatching where only the usefull things are passed: https://gitlab.com/basile.b/kheops/-/blob/master/src/kheops/control.d?ref_type=heads#L2863

  3. then the high level consumers just receive the useful parameters: https://gitlab.com/basile.b/kheops/-/blob/master/src/kheops/control.d?ref_type=heads#L752

That's always 3 or 4 parameters, always passed in general purpose registers.

I've never seen these kind of things done differently because it would indeed be slow to pass the whole event.

August 11

On Saturday, 10 August 2024 at 08:18:54 UTC, Vitaliy Fadeev wrote:

>

On Saturday, 10 August 2024 at 08:06:42 UTC, IchorDev wrote:

>

Is your application highly performance critical?
Many input event + many internal ui events -> many calls * many objects.

Yes, I like the fast, responsive interface on old hardware (as B970 CPU).

Lets say you get mouse events 100 times a second and and you have 10 function calls to filter through the gui tree, and your overhead for passing on the stack is 20 cycles.

(1001020) = 20,000

And your CPU is 2Ghz, so...

2,000,000,000 / 20,000 = 100,000

So what you're optimizing for is like 0.001% of your cpu time.

It's utterly irrelevant.