Atsushi & Gonzalo (and anyone else), Attached are two patches to reduce new object creations.
In Sys.Xml, I cut out string concatenations in XmlElement.Name and XmlAttribute.Name. The (prefix + ":" + localname) concatenation occurred even if the final string was already in the NameTable. To avoid this, I added a method to NameTable (an internal class) to accept a prefix and localname separately for checking if the final concatenated string would be in the name table already. The only performance hits might come from calls to the 'is' operator and two calls to String.CompareOrdinal rather than a single call to Equals. In Sys.Web.HttpWriter, a byte[] is created on each call to Write for strings and char arrays. Instead, I reuse and resize a byte[] array kept by the class. Since HttpWriter isn't thread safe, this seems ok. The downside is that string encoding is done through two calls, once to get the byte count and then to get the bytes. I don't know what kind of performance impact that might have. These changes reduce the two biggest object allocators per request for my ASP.NET site. My hope is that this will cut down on the runaway memory allocation that I'm still facing and hopefully have no significant performance cost. But I don't know about either. I'll try the patches out for a while to make sure I didn't goof anything up. Thanks guys. -- - Joshua Tauberer http://taubz.for.net "Unfortunately, we're having this discussion. It's too bad, because guess who listens to the discussion: the enemy."
Index: ../System.Web/System.Web/ChangeLog =================================================================== --- ../System.Web/System.Web/ChangeLog (revision 58623) +++ ../System.Web/System.Web/ChangeLog (working copy) @@ -1,3 +1,8 @@ +2006-03-27 Joshua Tauberer <[EMAIL PROTECTED]> + + * HttpWriter.cs: Avoid creation of a byte[] on each Write() + by reusing and resizing a private array. + 2006-03-23 Gonzalo Paniagua Javier <[EMAIL PROTECTED]> * HttpResponse.cs: more fixes for CacheControl: MS allows to set it to Index: ../System.Web/System.Web/HttpWriter.cs =================================================================== --- ../System.Web/System.Web/HttpWriter.cs (revision 58623) +++ ../System.Web/System.Web/HttpWriter.cs (working copy) @@ -42,6 +42,8 @@ HttpResponseStream output_stream; HttpResponse response; Encoding encoding; + + byte[] bytebuffer = new byte[2048]; internal HttpWriter (HttpResponse response) { @@ -97,23 +99,20 @@ public override void Write (string s) { - if (s == null) - return; - - byte [] xx = encoding.GetBytes (s); - - output_stream.Write (xx, 0, xx.Length); - - if (response.buffer) - return; - - response.Flush (); + WriteString (s, 0, s.Length); } public override void Write (char [] buffer, int index, int count) { - byte [] xx = encoding.GetBytes (buffer, index, count); - output_stream.Write (xx, 0, xx.Length); + /*byte [] xx = encoding.GetBytes (buffer, index, count); + output_stream.Write (xx, 0, xx.Length);*/ + + int length = encoding.GetByteCount (buffer, index, count); + if (length > bytebuffer.Length) + bytebuffer = new byte[length << 2]; + encoding.GetBytes (buffer, index, count, bytebuffer, 0); + + output_stream.Write (bytebuffer, 0, length); if (response.buffer) return; @@ -135,12 +134,22 @@ public void WriteString (string s, int index, int count) { - char [] a = s.ToCharArray (index, count); + if (s == null) + return; - byte [] xx = encoding.GetBytes (a, 0, count); + int length; + if (index == 0 && count == s.Length) { + length = encoding.GetByteCount (s); + } else { + char [] chars = s.ToCharArray(index, count); + length = encoding.GetByteCount (chars); + } + if (length > bytebuffer.Length) + bytebuffer = new byte[length << 2]; + encoding.GetBytes (s, index, count, bytebuffer, 0); - output_stream.Write (xx, 0, xx.Length); - + output_stream.Write (bytebuffer, 0, length); + if (response.buffer) return;
Index: System.Xml/XmlElement.cs =================================================================== --- System.Xml/XmlElement.cs (revision 58622) +++ System.Xml/XmlElement.cs (working copy) @@ -179,10 +179,7 @@ public override string Name { get { - if (name.Prefix == String.Empty || name.Prefix == null) - return name.LocalName; - else - return OwnerDocument.NameTable.Add (name.Prefix + ":" + name.LocalName); + return name.GetQName (OwnerDocument.NameTable); } } Index: System.Xml/XmlNameEntry.cs =================================================================== --- System.Xml/XmlNameEntry.cs (revision 58622) +++ System.Xml/XmlNameEntry.cs (working copy) @@ -52,6 +52,8 @@ public string LocalName; public string NS; public int Hash; + + string CachedQName; public override bool Equals (object other) { @@ -66,5 +68,17 @@ { return Hash; } + + public string GetQName(XmlNameTable nametable) { + if (CachedQName == null) { + if (Prefix == null || Prefix == String.Empty) + CachedQName = LocalName; + else if (nametable is NameTable) + CachedQName = ((NameTable)nametable).AddQName (Prefix, LocalName); + else + CachedQName = nametable.Add (Prefix + ":" + LocalName); + } + return CachedQName; + } } } Index: System.Xml/ChangeLog =================================================================== --- System.Xml/ChangeLog (revision 58622) +++ System.Xml/ChangeLog (working copy) @@ -1,3 +1,14 @@ +2006-03-27 Joshua Tauberer <[EMAIL PROTECTED]> + + * NameTable.cs: Added a new function AddQName which adds a string + like Add but taking a prefix and localname as arguments, so that + they don't have to be concatenated before the call. AddQName + won't do a concatenation if the string is already in the table. + * XmlElement.cs, XmlAtribute.cs: Avoid string creations in their + Name get accessors for prefix + ":" + localname. + * XmlNameEntry.cs: To create a QName, use NameTable's AddQName method + (if the name table is a NameTable), and cache the result. + 2006-03-23 Atsushi Enomoto <[EMAIL PROTECTED]> * XmlReader.cs : in XmlReader.Create() ValidationType Auto and XDR Index: System.Xml/XmlAttribute.cs =================================================================== --- System.Xml/XmlAttribute.cs (revision 58622) +++ System.Xml/XmlAttribute.cs (working copy) @@ -157,7 +157,7 @@ public override string Name { get { - return name.Prefix != String.Empty ? OwnerDocument.NameTable.Add (name.Prefix + ":" + name.LocalName) : name.LocalName; + return name.GetQName (OwnerDocument.NameTable); } } Index: System.Xml/NameTable.cs =================================================================== --- System.Xml/NameTable.cs (revision 58622) +++ System.Xml/NameTable.cs (working copy) @@ -110,6 +110,36 @@ return AddEntry (key, h); } + internal string AddQName (string prefix, string localname) + { + if (prefix == null || prefix == String.Empty || localname == null || localname == String.Empty) throw new ArgumentNullException (); + + int keyLen = prefix.Length + 1 + localname.Length; + + int h = 0; + // This is from the String.Gethash () icall + int pl = prefix.Length; + int ll = localname.Length; + for (int i = 0; i < pl; i++) + h = (h << 5) - h + prefix [i]; + h = (h << 5) - h + ':'; + for (int i = 0; i < ll; i++) + h = (h << 5) - h + localname [i]; + + // h must be be >= 0 + h &= 0x7FFFFFFF; + + for (Entry e = buckets [h % count]; e != null; e = e.next) { + if (e.hash == h && e.len == keyLen + && String.CompareOrdinal (e.str, 0, prefix, 0, pl) == 0 + && e.str [pl] == ';' + && String.CompareOrdinal (e.str, pl+1, localname, 0, ll) == 0) + return e.str; + } + + return AddEntry (prefix + ":" + localname, h); + } + public override string Get (char [] key, int start, int len) { if (((0 > start) && (start >= key.Length))
_______________________________________________ Mono-devel-list mailing list Mono-devel-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-devel-list