Skip to content
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

Remove AA faketypeinfo requirement #20853

Closed
wants to merge 2 commits into from
Closed

Conversation

schveiguy
Copy link
Member

@schveiguy schveiguy commented Feb 11, 2025

Fixes #17503.

  • This needs a test from the issue report
  • I need to run through CI to get the GC profile stats correct for 32-bit platforms.

One "regression"-ish from this: AA elements will no longer be precisely scanned by the precise GC. Explanation: The fake typeinfo used an additional allocation to create a bitmap with pointer data. This too could be collected, and is not worth maintaining.

If in the future we move to an all-template hook system with AAs, the precise scanning data (and even the element typeinfo) will be trivial to use (see how newaa does it). Until then, I think it's worth this mini-regression, since precise scanning is not that useful on modern 64-bit systems and is therefore seldom enabled.

@dlang-bot
Copy link
Contributor

Thanks for your pull request, @schveiguy!

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

⚠️⚠️⚠️ Warnings ⚠️⚠️⚠️

  • In preparation for migrating from Bugzilla to GitHub Issues, the issue reference syntax has changed. Please add the word "Bugzilla" to issue references. For example, Fix Bugzilla Issue 12345 or Fix Bugzilla 12345.(Reminder: the edit needs to be done in the Git commit message, not the GitHub pull request.)

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub run digger -- build "master + dmd#20853"

@schveiguy schveiguy added the Druntime:AA Specific to Associative Arrays label Feb 11, 2025
@schveiguy schveiguy force-pushed the fixaafaketi branch 2 times, most recently from 4b54cda to 716a65a Compare February 11, 2025 21:52
memcpy(res, pkey, aa.keysz); // copy key
memset(res + akeysz, 0, aa.valsz); // zero value
memcpy(res, pkey, akeysz); // copy key
memset(res + akeysz, 0, allocsz - akeysz); // zero everything after
Copy link
Member Author

@schveiguy schveiguy Feb 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, I changed this to memset also the gap between key and value, because I've seen what problems not doing that can cause, and it's probably at most 15 extra bytes to memset with the same call.

…ht be

collected before the element is collected.
}

private bool hasDtor(const TypeInfo ti) pure nothrow
{
import rt.lifetime : unqualify;

if (typeid(ti) is typeid(TypeInfo_Struct))
if ((cast(TypeInfo_Struct) cast(void*) ti).xdtor)
return true;
return (cast(TypeInfo_Struct) cast(void*) ti).xdtor !is null;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: optimization. No need to test for a static array when we know it's a struct.

@schveiguy schveiguy marked this pull request as ready for review February 11, 2025 23:02
// unfortunately, need to recalculate this every time.
auto valoff = talign(ti.key.tsize, ti.value.talign);
ti.value.destroy(p + valoff);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This recalculation on every finalize is unfortunate. If there were a way to store this offset in the TypeInfo_AssociativeArray, that would be ideal. It doesn't even need to be thread-aware, because it's a constant.

But maybe it's not a huge problem, because eventually we will be doing this via templates and just use the Entry structure directly.

@rainers
Copy link
Member

rainers commented Feb 11, 2025

Not a fan of creating the entry typeinfo for each AA, but that info has been pretty important for precise scanning IIRC.

since precise scanning is not that useful on modern 64-bit systems and is therefore seldom enabled.

I never bought that argument: the dmd-based language server running as a 64-bit background process for Visual D eats tons of memory without the precise GC (even with precise scanning it still does eventually, I recently killed it at 56 GB). I never switched to LDC for building the server because LDC does not support precise scanning of the data segment.

Without AAs being templated I think the better solution would be to let the compiler generate the TypeInfo for the (key,value)-pair and put it into TypeInfo_AssociativeArray.

@schveiguy
Copy link
Member Author

Without AAs being templated I think the better solution would be to let the compiler generate the TypeInfo for the (key,value)-pair and put it into TypeInfo_AssociativeArray.

So my other thought on this, but I didn't bring it up, is to also invoke RTInfo for TypeInfo_AssociativeArray instances, and we can do everything needed there. This in fact was my first thought until I realized this only happens for structs :(

@schveiguy
Copy link
Member Author

schveiguy commented Feb 12, 2025

I never bought that argument: the dmd-based language server running as a 64-bit background process for Visual D eats tons of memory without the precise GC (even with precise scanning it still does eventually, I recently killed it at 56 GB).

This points at a memory leak rather than a precise scanning problem. I don't want to dismiss it out of hand, because I don't know the true cause, but I have found problems that have been around for decades recently when focusing on this. Mostly due to having the new GC not fixing what was thought to be a problem with the old GC. As an example, see here: dlang/phobos#9084

I'm trying to fix a case at a work project where I get a segfault very rarely, and this is the cause.

Help me try and figure out how we can solve this problem without allocating memory, and without crippling the precise scanner.

I had considered still passing in the AA typeinfo, and having the precise scanner recognize it should dig into the key/value typeinfos to fetch the bits (or defer to the runtime for populating the info). But this doesn't help for large entries that would store just the pointer to the bit info. A possibility is to store multiple pointers in there? How many pointers do we get, one per page, right? Can we add a second pointer and a pad size? I don't know the precise scanner layout of things.

All this is a lot more complex than just defaulting to conservative scanning, so it would take time to solve.

@schveiguy
Copy link
Member Author

I don't know the precise scanner layout of things.

Oh, I see, it's C-mallocing that. I can work with that, just malloc extra space!

So there is a possibility here that we can keep precise scanning, let me think about this for a while, I think I don't need to change much, just hook AA typeinfos so we either fill in the bits (small allocations) or store both pointers + offsets (large allocations)

@schveiguy schveiguy marked this pull request as draft February 12, 2025 01:51
@schveiguy
Copy link
Member Author

So my other thought on this, but I didn't bring it up, is to also invoke RTInfo for TypeInfo_AssociativeArray instances

@rainers If you know of a good way to make this happen, it would actually be a lot cleaner. I am completely lost when it comes to compiler development.

@rainers
Copy link
Member

rainers commented Feb 12, 2025

I think adding a proper type info for the Entry struct is the cleaner way. It should contain the RTInfo as well as any dtor pointers. I can have a look if it's easy to add, but I'll probably only get to that in a couple of days.

@schveiguy
Copy link
Member Author

I can have a look if it's easy to add, but I'll probably only get to that in a couple of days.

OK, I'll hold off on my other plan (as outlined above, with some adjustments to how large pointer bitmaps are stored) until I hear back from you. If you decide this isn't something you have time for, we can at least go that route.

I took a look myself, and the way the RTInfo is generated is extremely tied to classes and structs (it's in aggregate.d). So just extending this to a builtin type such as AA isn't an easy lift.

@schveiguy
Copy link
Member Author

I think adding a proper type info for the Entry struct is the cleaner way.

If we can simply say, whenever we decide we have a new AA, we instantiate the template core.internal.newaa.Entry!(K, V), or even move it to object.d, and assign it's typeinfo to a field inside AA typeinfo, that solves all the problems!

Man, I wish I was more knowledgeable at compilers...

@@ -559,10 +430,10 @@ extern (C) void* _aaGetX(scope AA* paa, const TypeInfo_AssociativeArray ti,
immutable hash = calcHash(pkey, aa);

// found a value => return it
if (auto p = aa.findSlotLookup(hash, pkey, ti.key))
if (auto q = aa.findSlotLookup(hash, pkey, ti.key))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to undo this. I changed the name because I was having segfaults and gdb was confused about what p was.

schveiguy added a commit to symmetryinvestments/ldc that referenced this pull request Feb 12, 2025
@schveiguy
Copy link
Member Author

Closing in favor of much more straightforward #20863

@schveiguy schveiguy closed this Feb 18, 2025
rainers added a commit to rainers/dmd that referenced this pull request Feb 18, 2025
@schveiguy schveiguy deleted the fixaafaketi branch February 18, 2025 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Druntime:AA Specific to Associative Arrays
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Associative Arrays improperly register a GC-allocated TypeInfo for element cleanup
3 participants