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

System.Xml.NameTable optimizations #49988

Merged
merged 7 commits into from
Mar 24, 2021
Merged

System.Xml.NameTable optimizations #49988

merged 7 commits into from
Mar 24, 2021

Conversation

kronic
Copy link
Contributor

@kronic kronic commented Mar 22, 2021

Slight simplification and acceleration NameTable

dotnet-runtimeinfo **.NET information Version: 5.0.4 FrameworkDescription: .NET 5.0.4 Libraries version: 5.0.4 Libraries hash: f27d337

**Environment information
OSDescription: Microsoft Windows 10.0.19042
OSVersion: Microsoft Windows NT 10.0.19042.0
OSArchitecture: X64
ProcessorCount: 16

Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
AddArrNew 16.256 ns 0.2401 ns 0.2246 ns 0.0048 - - 40 B
AddArrOld 16.313 ns 0.1947 ns 0.1821 ns 0.0048 - - 40 B
AddNew 5.524 ns 0.0376 ns 0.0333 ns - - - -
AddOld 7.823 ns 0.0560 ns 0.0524 ns - - - -
GetArrNew 10.876 ns 0.2736 ns 0.3257 ns 0.0048 - - 40 B
GetArrOld 12.917 ns 0.2528 ns 0.2365 ns 0.0048 - - 40 B
GetNew 3.810 ns 0.0316 ns 0.0281 ns - - - -
GetOld 5.989 ns 0.0177 ns 0.0165 ns - - - -
code benchmark
using System;
using System.IO;
using System.Xml;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

[MemoryDiagnoser]
public class Program
{
	private const string XmlTestData = @"<?xml version=""1.0""?>
<PurchaseOrders xmlns=""www.contoso.com"">
  <PurchaseOrder
      PurchaseOrderNumber=""99503""
      OrderDate=""1999-10-20"">
    <Address Type=""Shipping"">
      <Name>Ellen Adams</Name>
      <Street>123 Maple Street</Street>
      <City>Mill Valley</City>
      <State>CA</State>
      <Zip>10999</Zip>
      <Country>USA</Country>
    </Address>
    <Address Type=""Billing"">
      <Name>Tai Yee</Name>
      <Street>8 Oak Avenue</Street>
      <City>Old Town</City>
      <State>PA</State>
      <Zip>95819</Zip>
      <Country>USA</Country>
    </Address>
    <DeliveryNotes>Please leave packages in shed by driveway.</DeliveryNotes>
    <Items>
      <Item PartNumber=""872-AA"">
        <ProductName>Lawnmower</ProductName>
        <Quantity>1</Quantity>
        <USPrice>148.95</USPrice>
        <Comment>Confirm this is electric</Comment>
      </Item>
      <Item PartNumber=""926-AA"">
        <ProductName>Baby Monitor</ProductName>
        <Quantity>2</Quantity>
        <USPrice>39.98</USPrice>
        <ShipDate>1999-05-21</ShipDate>
      </Item>
    </Items>
  </PurchaseOrder>
  <PurchaseOrder PurchaseOrderNumber=""99505"" OrderDate=""1999-10-22"">
    <Address Type=""Shipping"">
      <Name>Cristian Osorio</Name>
      <Street>456 Main Street</Street>
      <City>Buffalo</City>
      <State>NY</State>
      <Zip>98112</Zip>
      <Country>USA</Country>
    </Address>
    <Address Type=""Billing"">
      <Name>Cristian Osorio</Name>
      <Street>456 Main Street</Street>
      <City>Buffalo</City>
      <State>NY</State>
      <Zip>98112</Zip>
      <Country>USA</Country>
    </Address>
    <DeliveryNotes>Please notify by email before shipping.</DeliveryNotes>
    <Items>
      <Item PartNumber=""456-NM"">
        <ProductName>Power Supply</ProductName>
        <Quantity>1</Quantity>
        <USPrice>45.99</USPrice>
      </Item>
    </Items>
  </PurchaseOrder>
  <PurchaseOrder PurchaseOrderNumber=""99504"" OrderDate=""1999-10-22"">
    <Address Type=""Shipping"">
      <Name>Jessica Arnold</Name>
      <Street>4055 Madison Ave</Street>
      <City>Seattle</City>
      <State>WA</State>
      <Zip>98112</Zip>
      <Country>USA</Country>
    </Address>
    <Address Type=""Billing"">
      <Name>Jessica Arnold</Name>
      <Street>4055 Madison Ave</Street>
      <City>Buffalo</City>
      <State>NY</State>
      <Zip>98112</Zip>
      <Country>USA</Country>
    </Address>
    <DeliveryNotes>Please don't deliver on Saturday.</DeliveryNotes>
    <Items>
      <Item PartNumber=""898-AZ"">
        <ProductName>Computer Keyboard</ProductName>
        <Quantity>1</Quantity>
        <USPrice>29.99</USPrice>
      </Item>
      <Item PartNumber=""898-AM"">
        <ProductName>Wireless Mouse</ProductName>
        <Quantity>1</Quantity>
        <USPrice>14.99</USPrice>
      </Item>
    </Items>
  </PurchaseOrder>
  <aw:PurchaseOrder
    PONumber=""11223""
    Date=""2000-01-15""
    xmlns:aw=""http://www.adventure-works.com"">
    <aw:ShippingAddress>
      <aw:Name>Chris Preston</aw:Name>
      <aw:Street>123 Main St.</aw:Street>
      <aw:City>Seattle</aw:City>
      <aw:State>WA</aw:State>
      <aw:Zip>98113</aw:Zip>
      <aw:Country>USA</aw:Country>
    </aw:ShippingAddress>
    <aw:BillingAddress>
      <aw:Name>Chris Preston</aw:Name>
      <aw:Street>123 Main St.</aw:Street>
      <aw:City>Seattle</aw:City>
      <aw:State>WA</aw:State>
      <aw:Zip>98113</aw:Zip>
      <aw:Country>USA</aw:Country>
    </aw:BillingAddress>
    <aw:DeliveryInstructions>Ship only complete order.</aw:DeliveryInstructions>
    <aw:Item PartNum=""LIT-01"">
      <aw:ProductID>Litware Networking Card</aw:ProductID>
      <aw:Qty>1</aw:Qty>
      <aw:Price>20.99</aw:Price>
    </aw:Item>
    <aw:Item PartNum=""LIT-25"">
      <aw:ProductID>Litware 17in LCD Monitor</aw:ProductID>
      <aw:Qty>1</aw:Qty>
      <aw:Price>199.99</aw:Price>
    </aw:Item>
  </aw:PurchaseOrder>
</PurchaseOrders>";

	private readonly NameTable1 _nameTableNew;
	private readonly NameTable _nameTableOld;
	public Program()
	{
		_nameTableOld = new NameTable();

		using (XmlReader.Create
		(
			new StringReader(XmlTestData),
			new XmlReaderSettings
			{
				NameTable = _nameTableOld, CloseInput = true
			}
		))
		{
		}

		_nameTableNew = new NameTable1();

		using (XmlReader.Create
		(
			new StringReader(XmlTestData),
			new XmlReaderSettings
			{
				NameTable = _nameTableNew, CloseInput = true
			}
		))
		{
		}
	}
	[Benchmark]
	public string AddArrNew() => _nameTableNew.Add("aw:Zip".ToCharArray(), 0, 2);
	[Benchmark]
	public string AddArrOld() => _nameTableNew.Add("aw:Zip".ToCharArray(), 0, 2);
	[Benchmark]
	public string AddNew() => _nameTableNew.Add("Country");
	[Benchmark]
	public string AddOld() => _nameTableOld.Add("Country");
	[Benchmark]
	public string? GetArrNew() => _nameTableNew.Get("aw:Qty".ToCharArray(), 3, 3);
	[Benchmark]
	public string? GetArrOld() => _nameTableOld.Get("aw:Qty".ToCharArray(), 3, 3);
	[Benchmark]
	public string? GetNew() => _nameTableNew.Get("City");
	[Benchmark]
	public string? GetOld() => _nameTableOld.Get("City");
	private static void Main()
	{
		var summary = BenchmarkRunner.Run<Program>();
		Console.WriteLine(summary);
	}
}

@ghost
Copy link

ghost commented Mar 22, 2021

Tagging subscribers to this area: @buyaa-n, @krwq
See info in area-owners.md if you want to be subscribed.

Issue Details

Slight simplification and acceleration NameTable

Author: kronic
Assignees: -
Labels:

area-System.Xml

Milestone: -

@kronic kronic changed the title System.Xml.NameTable System.Xml.NameTable optimizations Mar 22, 2021
}
}
return true;
return str1.AsSpan().Equals(str2.AsSpan(str2Start, str2Length), StringComparison.Ordinal);
Copy link
Member

@stephentoub stephentoub Mar 22, 2021

Choose a reason for hiding this comment

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

Suggested change
return str1.AsSpan().Equals(str2.AsSpan(str2Start, str2Length), StringComparison.Ordinal);
return str1.AsSpan().SequenceEqual(str2.AsSpan(str2Start, str2Length));

Copy link
Contributor Author

@kronic kronic Mar 22, 2021

Choose a reason for hiding this comment

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

Ok @stephentoub

Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
AddArrNew 15.742 ns 0.0879 ns 0.0779 ns 0.0048 - - 40 B
AddArrNewSequenceEqual 12.718 ns 0.1066 ns 0.0945 ns 0.0048 - - 40 B
AddArrOld 15.674 ns 0.0632 ns 0.0591 ns 0.0048 - - 40 B
AddNew 5.866 ns 0.0524 ns 0.0491 ns - - - -
AddNewSequenceEqual 5.448 ns 0.0240 ns 0.0225 ns - - - -
AddOld 8.153 ns 0.0399 ns 0.0374 ns - - - -
GetArrNew 10.552 ns 0.0469 ns 0.0416 ns 0.0048 - - 40 B
GetArrNewSequenceEqual 10.329 ns 0.0571 ns 0.0534 ns 0.0048 - - 40 B
GetArrOld 13.466 ns 0.0654 ns 0.0580 ns 0.0048 - - 40 B
GetNew 3.664 ns 0.0162 ns 0.0143 ns - - - -
GetNewSequenceEqual 3.702 ns 0.0190 ns 0.0178 ns - - - -
GetOld 5.999 ns 0.0330 ns 0.0276 ns - - - -

Copy link
Contributor Author

Choose a reason for hiding this comment

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

using System;
using System.IO;
using System.Xml;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

[MemoryDiagnoser]
public class Program
{
	private const string XmlTestData = @"<?xml version=""1.0""?>
<PurchaseOrders xmlns=""www.contoso.com"">
  <PurchaseOrder
      PurchaseOrderNumber=""99503""
      OrderDate=""1999-10-20"">
    <Address Type=""Shipping"">
      <Name>Ellen Adams</Name>
      <Street>123 Maple Street</Street>
      <City>Mill Valley</City>
      <State>CA</State>
      <Zip>10999</Zip>
      <Country>USA</Country>
    </Address>
    <Address Type=""Billing"">
      <Name>Tai Yee</Name>
      <Street>8 Oak Avenue</Street>
      <City>Old Town</City>
      <State>PA</State>
      <Zip>95819</Zip>
      <Country>USA</Country>
    </Address>
    <DeliveryNotes>Please leave packages in shed by driveway.</DeliveryNotes>
    <Items>
      <Item PartNumber=""872-AA"">
        <ProductName>Lawnmower</ProductName>
        <Quantity>1</Quantity>
        <USPrice>148.95</USPrice>
        <Comment>Confirm this is electric</Comment>
      </Item>
      <Item PartNumber=""926-AA"">
        <ProductName>Baby Monitor</ProductName>
        <Quantity>2</Quantity>
        <USPrice>39.98</USPrice>
        <ShipDate>1999-05-21</ShipDate>
      </Item>
    </Items>
  </PurchaseOrder>
  <PurchaseOrder PurchaseOrderNumber=""99505"" OrderDate=""1999-10-22"">
    <Address Type=""Shipping"">
      <Name>Cristian Osorio</Name>
      <Street>456 Main Street</Street>
      <City>Buffalo</City>
      <State>NY</State>
      <Zip>98112</Zip>
      <Country>USA</Country>
    </Address>
    <Address Type=""Billing"">
      <Name>Cristian Osorio</Name>
      <Street>456 Main Street</Street>
      <City>Buffalo</City>
      <State>NY</State>
      <Zip>98112</Zip>
      <Country>USA</Country>
    </Address>
    <DeliveryNotes>Please notify by email before shipping.</DeliveryNotes>
    <Items>
      <Item PartNumber=""456-NM"">
        <ProductName>Power Supply</ProductName>
        <Quantity>1</Quantity>
        <USPrice>45.99</USPrice>
      </Item>
    </Items>
  </PurchaseOrder>
  <PurchaseOrder PurchaseOrderNumber=""99504"" OrderDate=""1999-10-22"">
    <Address Type=""Shipping"">
      <Name>Jessica Arnold</Name>
      <Street>4055 Madison Ave</Street>
      <City>Seattle</City>
      <State>WA</State>
      <Zip>98112</Zip>
      <Country>USA</Country>
    </Address>
    <Address Type=""Billing"">
      <Name>Jessica Arnold</Name>
      <Street>4055 Madison Ave</Street>
      <City>Buffalo</City>
      <State>NY</State>
      <Zip>98112</Zip>
      <Country>USA</Country>
    </Address>
    <DeliveryNotes>Please don't deliver on Saturday.</DeliveryNotes>
    <Items>
      <Item PartNumber=""898-AZ"">
        <ProductName>Computer Keyboard</ProductName>
        <Quantity>1</Quantity>
        <USPrice>29.99</USPrice>
      </Item>
      <Item PartNumber=""898-AM"">
        <ProductName>Wireless Mouse</ProductName>
        <Quantity>1</Quantity>
        <USPrice>14.99</USPrice>
      </Item>
    </Items>
  </PurchaseOrder>
  <aw:PurchaseOrder
    PONumber=""11223""
    Date=""2000-01-15""
    xmlns:aw=""http://www.adventure-works.com"">
    <aw:ShippingAddress>
      <aw:Name>Chris Preston</aw:Name>
      <aw:Street>123 Main St.</aw:Street>
      <aw:City>Seattle</aw:City>
      <aw:State>WA</aw:State>
      <aw:Zip>98113</aw:Zip>
      <aw:Country>USA</aw:Country>
    </aw:ShippingAddress>
    <aw:BillingAddress>
      <aw:Name>Chris Preston</aw:Name>
      <aw:Street>123 Main St.</aw:Street>
      <aw:City>Seattle</aw:City>
      <aw:State>WA</aw:State>
      <aw:Zip>98113</aw:Zip>
      <aw:Country>USA</aw:Country>
    </aw:BillingAddress>
    <aw:DeliveryInstructions>Ship only complete order.</aw:DeliveryInstructions>
    <aw:Item PartNum=""LIT-01"">
      <aw:ProductID>Litware Networking Card</aw:ProductID>
      <aw:Qty>1</aw:Qty>
      <aw:Price>20.99</aw:Price>
    </aw:Item>
    <aw:Item PartNum=""LIT-25"">
      <aw:ProductID>Litware 17in LCD Monitor</aw:ProductID>
      <aw:Qty>1</aw:Qty>
      <aw:Price>199.99</aw:Price>
    </aw:Item>
  </aw:PurchaseOrder>
</PurchaseOrders>";

	private readonly NameTable1 _nameTableSpanEqual;
	private readonly NameTable _nameTableOld;
	private readonly NameTable2 _nameTableNewSequenceEqual;
	public Program()
	{
		_nameTableOld = new NameTable();

		using (XmlReader.Create
		(
			new StringReader(XmlTestData),
			new XmlReaderSettings
			{
				NameTable = _nameTableOld, CloseInput = true
			}
		))
		{
		}

		_nameTableSpanEqual = new NameTable1();

		using (XmlReader.Create
		(
			new StringReader(XmlTestData),
			new XmlReaderSettings
			{
				NameTable = _nameTableSpanEqual, CloseInput = true
			}
		))
		{
		}

		_nameTableNewSequenceEqual = new NameTable2();

		using (XmlReader.Create
		(
			new StringReader(XmlTestData),
			new XmlReaderSettings
			{
				NameTable = _nameTableNewSequenceEqual, CloseInput = true
			}
		))
		{
		}
	}
	[Benchmark]
	public string AddArrNew() => _nameTableSpanEqual.Add("aw:Zip".ToCharArray(), 0, 2);
	[Benchmark]
	public string AddArrNewSequenceEqual() => _nameTableNewSequenceEqual.Add("aw:Zip".ToCharArray(), 0, 2);
	[Benchmark]
	public string AddArrOld() => _nameTableSpanEqual.Add("aw:Zip".ToCharArray(), 0, 2);
	[Benchmark]
	public string AddNew() => _nameTableSpanEqual.Add("Country");
	[Benchmark]
	public string AddNewSequenceEqual() => _nameTableNewSequenceEqual.Add("Country");
	[Benchmark]
	public string AddOld() => _nameTableOld.Add("Country");
	[Benchmark]
	public string? GetArrNew() => _nameTableSpanEqual.Get("aw:Qty".ToCharArray(), 3, 3);
	[Benchmark]
	public string? GetArrNewSequenceEqual() => _nameTableNewSequenceEqual.Get("aw:Qty".ToCharArray(), 3, 3);
	[Benchmark]
	public string? GetArrOld() => _nameTableOld.Get("aw:Qty".ToCharArray(), 3, 3);
	[Benchmark]
	public string? GetNew() => _nameTableSpanEqual.Get("City");
	[Benchmark]
	public string? GetNewSequenceEqual() => _nameTableNewSequenceEqual.Get("City");
	[Benchmark]
	public string? GetOld() => _nameTableOld.Get("City");
	private static void Main()
	{
		var summary = BenchmarkRunner.Run<Program>();
		Console.WriteLine(summary);
	}
}

@kronic
Copy link
Contributor Author

kronic commented Mar 22, 2021

@stephentoub done

Copy link
Member

@stephentoub stephentoub left a comment

Choose a reason for hiding this comment

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

At this point it probably doesn't need its own method; it could instead be inlined into the two call sites that use it, which would also help to make clear why the str2Start/str2Length will always be in bounds.

@kronic
Copy link
Contributor Author

kronic commented Mar 22, 2021

@stephentoub I will fix it. Is it worth it to also inline the ComputeHash32 method?

@kronic
Copy link
Contributor Author

kronic commented Mar 23, 2021

@stephentoub Ready for review

@krwq
Copy link
Member

krwq commented Mar 23, 2021

/azp help

@azure-pipelines
Copy link

Supported commands
  • help:
    • Get descriptions, examples and documentation about supported commands
    • Example: help "command_name"
  • list:
    • List all pipelines for this repository using a comment.
    • Example: "list"
  • run:
    • Run all pipelines or specific pipelines for this repository using a comment. Use this command by itself to trigger all related pipelines, or specify specific pipelines to run.
    • Example: "run" or "run pipeline_name, pipeline_name, pipeline_name"
  • where:
    • Report back the Azure DevOps orgs that are related to this repository and org
    • Example: "where"

See additional documentation.

@krwq
Copy link
Member

krwq commented Mar 23, 2021

/azp list

@krwq
Copy link
Member

krwq commented Mar 23, 2021

/azp run runtime-libraries-coreclr outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Copy link
Member

@krwq krwq left a comment

Choose a reason for hiding this comment

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

thanks

@stephentoub
Copy link
Member

Thanks.

@stephentoub stephentoub merged commit cc10f27 into dotnet:main Mar 24, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Apr 23, 2021
@karelz karelz added this to the 6.0.0 milestone May 20, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants