-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
re-order struct fields for better performance and memory usage #168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Don't you think it would be better to let the programmer decide the packing order of the fields? If the compiler decides how to pack stuff, working programs may break from one compiler version to another. I don't think the complexity and risk this optimization adds is worth it. If you still want to add it, you can provide a special annotation to indicate that the compiler should decide how to pack the struct. |
The programmer has a choice: leave the field order undefined and give the power to the compiler, or use a packed struct and specify the order themselves. Packed structs are not done yet. See #183 |
So if I need a guarantee on the order of a structure it has to be packed, If so you'd probably need a chapter of documentation describing how to On Mon, Sep 5, 2016, 07:29 Andrew Kelley [email protected] wrote:
|
Yeah. But don't make undefined the default behavior. You still going to have padding of course, but the order of fields will be guaranteed. |
Correct. There is also the concept of
Can you explain a situation that would result in a segfault because of code relying on field order? |
Can you explain the use case where you want to rely on field order? |
x86 will segfault upon doing an unaligned memory access (typically aligned to data size). Imagine a structure like this: struct Gizmo {
tag: u8,
thingy: u16
} Assuming allocated memory is aligned, dereferencing the field There's a few details with regard to the load/store instructions used, SSE load/store segfault, whereas (iirc) the normal mov "just" suffers performace wise due to splitting into several aligned loads/stores. |
Most of the use cases can be considered hacks. Considering that we're talking about a low-level language, these hacks are use cases. If the compiler defines the order of the the fields it becomes hard to analyze memory dumps (there may be many situations where raw memory is the only thing you have to debug something), appending a field to a struct can lead to a reordering of the fields that existed before. This gives up the ability to write code that deals with data that was generated based on the previous struct specification. Maybe I'm being too pessimistic here, but my impression is that this complexity would backfire in unpredictable ways if you have it by default. |
If that happens we can always change the decision. And code that does not assume field order will continue to work correctly if it can then start assuming field order. Also there will be a builtin function for getting the address of a field based on its name. Example: |
Is this something where the field enumeration in #383 would help? Note for the last part, is this not the same as getting the address of the field in the strut via &? |
See http://ziglang.org/documentation/#builtin-fieldParentPtr |
This issue will now have a meaningful impact on async functions since it applies to all local variables. |
This is a simple starting version of the optimization described in ziglang#168 where the fields are just sorted by order of descending alignment.
I mentioned in discord but it would be useful if you could tag certain fields to be omit from reordering but let zig do whatever it wants with rest. At top of the struct I'm storing small tags which I take the address of, the tags contain the runtime information about the type of the struct the tag is part of and offset to the struct's base. I want to keep this tag small so u8 for offsets would've been fine if not struct reordering. I ended up storing field index instead and use inline for to find the offset of the field, which also is fine but adds at least small cost of switch. Extern struct is not applicable here because I actually do want the zig struct semantics for rest of the fields and also not have the extern struct must only contain extern struct restriction. |
One reason for having the option of known ordering of a struct without much overhead is being able to use guard integrity fields of known bytes surrounding the struct that you can see in the memory dump. This is especially important when debugging embedded systems with very little resources. This helps detect faults that overwrite portions of memory. It is also very useful to read the structs out of memory of a running system. But with unknown ordering, it makes that impossible. If there was an easy option to turn the reordering off without having to define all the alignment with a packed struct, that would be helpful. It might not even need to be per struct but a compile time option. |
But automatic ordering is also nice in a few cases where I don't care about it that much. |
In Zig, you have no guarantee about the memory layout of a struct unless you make a struct packed or
export
.Take advantage of this:
Provide safety against incorrect assumptions about field order:
@container_base(inline T: type, field_name_symbol, field_pointer) -> &T
(better name suggestion welcome @thejoshwolfe). This function takes a pointer to a container field, the container type, and a symbol which is the name of the field, and returns a pointer to the struct. Programmers should use this builtin instead of futzing around with pointers to go from a field pointer to the container base pointer.The text was updated successfully, but these errors were encountered: