Skip to content

Fix XmlSerializer UnknownAttribute perf regression - #131908

Draft
StephenMolloy wants to merge 1 commit into
dotnet:mainfrom
StephenMolloy:131813-XmlSerialzier_UnknownAttribute_Perf_Regression
Draft

Fix XmlSerializer UnknownAttribute perf regression#131908
StephenMolloy wants to merge 1 commit into
dotnet:mainfrom
StephenMolloy:131813-XmlSerialzier_UnknownAttribute_Perf_Regression

Conversation

@StephenMolloy

Copy link
Copy Markdown
Member

This pull request refactors how unknown XML attributes are handled during XML deserialization, specifically for elements mapped to built-in primitive types and arrays in the XmlSerializer. The main change is to avoid enumerating attributes (i.e., calling MoveToNextAttribute) unless there are subscribers to unknown node or attribute events, improving performance and aligning behavior with struct deserialization. The PR also updates related tests to verify the new behavior.

Attribute Handling Logic Updates:

  • Refactored HandleUnknownAttributes in ReflectionXmlSerializationReader and related codegen to only enumerate attributes if there are subscribers to unknown node or attribute events and the element has attributes, instead of always enumerating unless the element is marked xsi:nil. [1] [2] [3] [4] [5]
  • Updated code generation in both C# and IL (XmlSerializationReader.cs and XmlSerializationReaderILGen.cs) to match the new logic, ensuring consistency between runtime and generated serializers. [1] [2] [3] [4] [5] [6] [7] [8]

Test Improvements:

  • Added new tests (XmlBuiltInTypedMembersWithoutAttributesAvoidAttributeEnumeration and XmlBuiltInTypedMembersWithAttributesWithoutSubscribers) to verify that attribute enumeration is avoided when there are no event subscribers, and that attributes are only enumerated when subscribers are present.
  • Enhanced existing tests to use AttributeTrackingXmlReader and assert the number of attribute enumeration operations, confirming the new logic is correctly applied. [1] [2] [3] [4]

Behavioral Consistency:

  • Ensured that elements marked as xsi:nil do not surface their attributes as unknown, maintaining consistency with struct deserialization. [1] [2] [3] [4]

These changes improve performance and correctness by reducing unnecessary attribute enumeration and aligning the handling of unknown attributes across different mapping types.

Fixes #131813

… performance

- Removed redundant calls to HandleUnknownAttributes in ReflectionXmlSerializationReader.
- Consolidated attribute handling logic to avoid unnecessary attribute enumeration for built-in typed members.
- Introduced AttributeTrackingXmlReader to track attribute operations during deserialization.
- Added unit tests to verify that attributes are not enumerated when not needed and to ensure correct behavior with stray attributes.
@StephenMolloy StephenMolloy added this to the 11.0.0 milestone Aug 5, 2026
@StephenMolloy StephenMolloy self-assigned this Aug 5, 2026
Copilot AI review requested due to automatic review settings August 5, 2026 22:13
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adjusts XmlSerializer deserialization for primitive/array/collection-mapped elements to reduce unnecessary attribute walking and to align unknown-attribute surfacing behavior more closely with other mapping paths. It also extends the test suite to validate attribute enumeration behavior (including xsi:nil handling) using a tracking XmlReader.

Changes:

  • Updated reflection-based deserialization to skip unknown-attribute enumeration unless there are unknown-node/attribute subscribers and the element actually has attributes.
  • Updated generated-reader code emission (C# + IL) to avoid MoveToNextAttribute when Reader.HasAttributes is false, and to ensure nil-handling paths don’t surface attributes.
  • Added tests and a tracking XmlReader wrapper to assert attribute enumeration / lookup behavior.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 3 comments.

File Description
src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs Adds attribute-enumeration tracking tests and an XmlReader wrapper to validate the new behavior.
src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReaderILGen.cs Adjusts emitted IL to gate attribute enumeration behind Reader.HasAttributes and reorders calls around ReadNull.
src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs Adds an internal “has subscribers” helper and updates generated-source emission to check Reader.HasAttributes before enumerating.
src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs Refactors unknown-attribute handling to return early when there are no relevant event subscribers and/or no attributes.

Comment on lines 4616 to 4621
private void WriteHandleUnknownAttributes()
{
// When the element is marked xsi:nil, the nil marker (and the element itself) is consumed
// by the following ReadNull() call, so its attributes must not be surfaced as unknown. This
// also matches the struct path, where a nil element returns before its attributes are read.
Writer.WriteLine("if (!GetNullAttr()) {");
Writer.WriteLine("if (Reader.HasAttributes) {");
Writer.Indent++;
Writer.WriteLine("while (Reader.MoveToNextAttribute()) {");
Writer.Indent++;
Comment on lines +2209 to +2211
[Fact]
public static void XmlBuiltInTypedMembersWithAttributesWithoutSubscribers()
{
}
}

public override string? GetAttribute(string name) => _reader.GetAttribute(name);
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.

[Perf] Windows/x64: 5 Regressions on 7/30/2026 6:50:50 PM +00:00

2 participants