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

Keep using RO metadata after creating IMetaDataImporter for PDB reading #93902

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

hoyosjs
Copy link
Member

@hoyosjs hoyosjs commented Oct 24, 2023

This change allows the runtime to keep using the read-only view of the metadata interfaces for internal use, even after a RW conversion of the metadata has been requested to back the classic PDB parser. Swapping of the cached RW converted view will be deferred until some other path (e.g. profiler, MD emit) requests a RW view of the metadata.

Main version of fix for #90563

@hoyosjs
Copy link
Member Author

hoyosjs commented Oct 24, 2023

Following the repro in the original issue and deleting the PDB I observe on average 9k exceptions per second on my 12 core machine. After this change the rate grows to ~20k, which is in line with the perf of builds using portable PDBs with no PDB available.

src/coreclr/vm/peassembly.cpp Outdated Show resolved Hide resolved
src/coreclr/vm/peassembly.cpp Outdated Show resolved Hide resolved
src/coreclr/vm/peassembly.cpp Outdated Show resolved Hide resolved
src/coreclr/vm/peassembly.cpp Outdated Show resolved Hide resolved
src/coreclr/vm/peassembly.cpp Outdated Show resolved Hide resolved
src/coreclr/vm/peassembly.cpp Outdated Show resolved Hide resolved
IMDInternalImport *pConvertedImport = m_pConvertedMDImport; // Pointer to a RW internal metadata that might not be actively in use.


if (pConvertedImport != NULL)
Copy link
Member

@jkotas jkotas Oct 25, 2023

Choose a reason for hiding this comment

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

Can this be moved to the end of the method and merged with similar code that's there already?

I think the code would be much easier to understand if the method flow is like this:

// Step 1: Create RW MD import if it was not created yet
if (m_pConvertedMDImport == NULL)
{
    create and initialize m_pConvertedMDImport
}

// Step 2: Swap the RW import if the scope is being opened for writing and the RW import was not swapped yet
if (openForWriting && m_pConvertedMDImport != m_pMDImport)
{
...
}

@@ -1027,14 +1027,14 @@ class Module : public ModuleBase
return m_pPEAssembly->GetEmitter();
}

IMetaDataImport2 *GetRWImporter()
IMetaDataImport2 *GetRWImporter(bool openForWriting=true)
Copy link
Member

Choose a reason for hiding this comment

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

Does this API need a default value? Can we update all places with an argument?


IMetaDataImport2 *pIMDImport = NULL;
IfFailThrow(GetMetaDataPublicInterfaceFromInternal((void*)GetMDImport(),
IfFailThrow(GetMetaDataPublicInterfaceFromInternal((void*)m_pConvertedMDImport,
Copy link
Member

Choose a reason for hiding this comment

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

Let's assert m_pConvertedMDImport is non NULL and comment why we need the converted version.

// Additionally, now both m_pMDImport and m_pConvertedMDImport point to
// the same RW MDImport. Up the references such that both have to be freed
// before freeing the RW copy and the RO that hangs off it.
pConvertedImport->AddRef();
Copy link
Member

Choose a reason for hiding this comment

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

I still don't understand this part. I think we only get in here if m_pMDImport and m_pConvertedMDImport are non-null and aren't the same instance. If this is true, then both pConvertedImport and pOld were/are fields on this class. I would assume then that both have correct references counts for being on this class. I do see the pOld being passed into SetUserContextData() and this could be a lifetime transfer, but if that were the case, I would expect pOld to need an AddRef() and not pConvertedImport.

// Additionally, now both m_pMDImport and m_pConvertedMDImport point to
// the RW MDImport. Up the references such that both have to be freed
// before freeing the RW copy and the RO that hangs off it.
pNew->AddRef();
Copy link
Member

Choose a reason for hiding this comment

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

The pNew was returned from above with an AddRef(), see GetMetaDataInternalInterfaceFromPublic(), why is this neded here? I think I get the case if pNew = m_pConvertedMDImport; is done, but in that case I would expect an pNew->AddRef() there as opposed to here.

Copy link
Contributor

Tagging subscribers to this area: @tommcdon
See info in area-owners.md if you want to be subscribed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants