Skip to content

[wasm][debugger] Improve debugger performance based on JMC #86982

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

Merged

Conversation

thaystg
Copy link
Member

@thaystg thaystg commented May 31, 2023

If JMC is enabled and runtime doesn't have debug symbols of an assembly it means that the assembly being used is not from the customer, otherwise the pdb would be loaded by the runtime.
In this case we don't need to load any information about the assembly avoiding spending a lot of time receiving all the bytes from all the assemblies that will not be used because JMC is disabled.

UPDATE: I'm loading the information by demand, if we need any information from an assembly that is not loaded, like to inspect variables of a specific type that is not in the user code, I'm loading, it's a better approach to avoid any side effect and we are still spending less time because we will not need to load 149 assemblies at the startup even if we will not use them.

Measurement: From 4 seconds to load all the symbols during the app startup to less than 1 second.

I'm not adding any new test because this is already tested.

@ghost
Copy link

ghost commented May 31, 2023

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

Issue Details

If JMC is enabled and runtime doesn't have debug symbols it means that the assembly being used is not from the customer, otherwise the pdb would be loaded by the runtime.
In this case we don't need to load any information about the assembly avoiding spending a lot of time receiving all the bytes from all the assemblies that will not be used because JMC is disabled.

Author: thaystg
Assignees: thaystg
Labels:

area-Debugger-mono

Milestone: -

@thaystg
Copy link
Member Author

thaystg commented May 31, 2023

@lewing do you think this makes sense?
If you agree I'll continue working on it. The customer can "DISABLE" just my code during the debugging session, then I'll need to load all the symbols from runtime at that moment.

@thaystg thaystg added the arch-wasm WebAssembly architecture label May 31, 2023
@ghost
Copy link

ghost commented May 31, 2023

Tagging subscribers to 'arch-wasm': @lewing
See info in area-owners.md if you want to be subscribed.

Issue Details

If JMC is enabled and runtime doesn't have debug symbols it means that the assembly being used is not from the customer, otherwise the pdb would be loaded by the runtime.
In this case we don't need to load any information about the assembly avoiding spending a lot of time receiving all the bytes from all the assemblies that will not be used because JMC is disabled.
From 4 seconds to load all the symbols during the app startup to less than 1 second.

Author: thaystg
Assignees: thaystg
Labels:

arch-wasm, area-Debugger-mono

Milestone: -

@lewing
Copy link
Member

lewing commented May 31, 2023

@lewing do you think this makes sense? If you agree I'll continue working on it. The customer can "DISABLE" just my code during the debugging session, then I'll need to load all the symbols from runtime at that moment.

yeah, I think it makes sense. There is no particular issue with loading them later once the switch changes right?

@thaystg
Copy link
Member Author

thaystg commented Jun 1, 2023

@lewing do you think this makes sense? If you agree I'll continue working on it. The customer can "DISABLE" just my code during the debugging session, then I'll need to load all the symbols from runtime at that moment.

yeah, I think it makes sense. There is no particular issue with loading them later once the switch changes right?

No particular issue. When you disable JMC after the debugger session is started we will need to get the PDB from cache or from symbol server anyway. With this change we will also read the assembly bytes from runtime before try to get the symbols from cache / from symbol server.

@thaystg thaystg marked this pull request as ready for review June 1, 2023 19:11
@thaystg thaystg requested a review from radical as a code owner June 1, 2023 19:11
@thaystg thaystg requested a review from lambdageek June 1, 2023 19:11
@thaystg thaystg marked this pull request as draft June 1, 2023 20:36
…t of time loading information from 149 assemblies if we will probably not need all of them.
@thaystg thaystg marked this pull request as ready for review June 2, 2023 14:08
internal System.Guid PdbGuid { get; set; }
internal bool IsPortableCodeView { get; set; }
internal string PdbName { get; set; }
internal bool CodeViewInformationAvailable { get; set; }
Copy link
Member

Choose a reason for hiding this comment

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

Do we ever make use of these setters? It does not look like a necessary change.

Copy link
Member

Choose a reason for hiding this comment

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

The property seems to be never read at all.

@thaystg thaystg requested a review from marek-safar as a code owner June 28, 2023 16:06
@thaystg thaystg requested a review from ilonatommy June 28, 2023 16:06
Copy link
Member

@ilonatommy ilonatommy left a comment

Choose a reason for hiding this comment

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

The idea with strrchr looks good as we use it in other places. Other than that, looks great.

break;
}
}

Copy link
Member

Choose a reason for hiding this comment

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

Maybe check if the string is empty here?

MonoAssemblyByNameRequest byname_req;
mono_assembly_request_prepare_byname (&byname_req, mono_alc_get_default ());
MonoAssembly *assembly = mono_assembly_request_byname (aname, &byname_req, &status);
g_free (lookup_name);
Copy link
Member

Choose a reason for hiding this comment

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

Can we do this right after the call to mono_assembly_name_new?

g_ptr_array_free (assemblies, TRUE);
if (!assembly) {
PRINT_DEBUG_MSG (1, "Could not resolve assembly %s\n", assembly_name);
mono_assembly_name_free_internal (aname);
Copy link
Member

Choose a reason for hiding this comment

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

Should this jump to 6988, which can free and return assembly (==NULL here)?

{
if (!assemblyName.StartsWith("System.Private.CoreLib") && !ignoreJMC && proxy.JustMyCode && !(await HasDebugInfoLoadedByRuntime(assemblyName, token)))
Copy link
Member

Choose a reason for hiding this comment

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

StringComparison.Ordinal with StartsWith

{
if (!assemblyName.StartsWith("System.Private.CoreLib") && !ignoreJMC && proxy.JustMyCode && !(await HasDebugInfoLoadedByRuntime(assemblyName, token)))
Copy link
Member

Choose a reason for hiding this comment

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

Also, I would suggest maybe splitting this only multiple lines, and comments for why the different parts of the condition are needed.

ret[1] = pdb_buf;
AssemblyAndPdbData ret = new(assembly_buf, pdb_buf);

if (MajorVersion == 2 && MinorVersion >= 64)
Copy link
Member

Choose a reason for hiding this comment

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

Should these checks be using MajorVersion >= 2?
Also, can we (in a followup) convert such version checks into properties named for whatever feature we want to check for. It would essentially document why we are doing the version check. And also, in future if we need to change the versions checks for that feature then we can easily change it.

Comment on lines 2542 to 2544
AssemblyAndPdbData ret = new(assembly_buf, pdb_buf);

if (MajorVersion == 2 && MinorVersion >= 64)
Copy link
Member

Choose a reason for hiding this comment

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

nit:

            if (MajorVersion != 2 || MinorVersion < 64)
                return new(assembly_buf, pdb_buf);

            AssemblyAndPdbData ret = new()

thaystg and others added 2 commits July 10, 2023 11:23
Co-authored-by: Ankit Jain <radical@gmail.com>
Co-authored-by: Ankit Jain <radical@gmail.com>
@@ -1909,7 +1944,7 @@ public async Task<string> InvokeToStringAsync(IEnumerable<int> typeIds, bool isV
foreach (var methodId in methodIds)
{
var methodInfoFromRuntime = await GetMethodInfo(methodId, token);
if (methodInfoFromRuntime.Info.GetParametersInfo().Length > 0)
if (methodInfoFromRuntime?.Info?.GetParametersInfo()?.Length > 0)
Copy link
Member

@radical radical Jul 13, 2023

Choose a reason for hiding this comment

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

Should we also check that the return type is string?
And this method (InvokeTostringAsync) is only looking at instance methods, correct?

@ghost ghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Jul 13, 2023
@ghost ghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Jul 14, 2023
Copy link
Member

@radical radical left a comment

Choose a reason for hiding this comment

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

LGTM! 👍

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
arch-wasm WebAssembly architecture area-Debugger-mono
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants