[Mono-docs-list] Monodoc Assembler Performance patch

Ben Maurer bmaurer@users.sourceforge.net
19 Jun 2003 16:07:10 -0400


--=-GcfogFs7X2qnu6bT/tli
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

Hello all,

If my previous 12% speed improvement patch wasn't enough for you, you
are in good company ;-), it was not enough for me either. So I went in
and ripped out all the XPath and XmlDocument stuff from the guts of
ecma-provider and replaced it with cool, clean XmlTextReader.

As a result, I was able to half both the amount of time it takes to
assemble the class libraries and the amount of memory that the assembler
takes up.

May I commit?

-- Ben

--=-GcfogFs7X2qnu6bT/tli
Content-Disposition: attachment; filename=monodocperf.patch
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-patch; name=monodocperf.patch; charset=UTF-8

Index: ChangeLog
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvs/public/monodoc/browser/ChangeLog,v
retrieving revision 1.35
diff -u -r1.35 ChangeLog
--- ChangeLog	6 Jun 2003 04:22:30 -0000	1.35
+++ ChangeLog	19 Jun 2003 20:14:14 -0000
@@ -1,3 +1,7 @@
+2003-06-19  Ben Maurer <bmaurer@users.sourceforge.net>
+	* ecma-provider.cs, provider.cs: Added tons of performance
+	related stuff. Doubles speed, halfs memory allocation!
+
 2003-06-02  Miguel de Icaza  <miguel@ximian.com>
=20
 	* ecma-provider.cs (PopulateIndex): Add full type names.
Index: ecma-provider.cs
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvs/public/monodoc/browser/ecma-provider.cs,v
retrieving revision 1.49
diff -u -r1.49 ecma-provider.cs
--- ecma-provider.cs	15 Jun 2003 18:53:27 -0000	1.49
+++ ecma-provider.cs	19 Jun 2003 20:14:14 -0000
@@ -4,9 +4,11 @@
 // Authors:
 //   Miguel de Icaza (miguel@ximian.com)
 //   Joshua Tauberer (tauberer@for.net)
+//   Ben Maurer (bmaurer@users.sourceforge.net)
 //
 // (C) 2002, 2003 Ximian, Inc.
 // (C) 2003 Joshua Tauberer.
+// (C) 2003 Ben Maurer
 //
 // TODO:
 //   Should cluster together constructors
@@ -27,58 +29,8 @@
=20
 using BF =3D System.Reflection.BindingFlags;
=20
-//
-// Helper routines to extract information from an Ecma XML document
-//
 public class EcmaDoc {
-	public static string GetFullClassName (XmlDocument doc)
-	{
-		return doc.SelectSingleNode ("/Type").Attributes ["FullName"].InnerText;
-	}
-=09
-	public static string GetClassName (XmlDocument doc)
-	{
-		return doc.SelectSingleNode ("/Type").Attributes ["Name"].InnerText;
-	}
-
-	public static string GetClassAssembly (XmlDocument doc)
-	{
-		return doc.SelectSingleNode ("/Type/AssemblyInfo/AssemblyName").InnerTex=
t;
-	}
-
-	public static string GetClassNamespace (XmlDocument doc)
-	{
-		string s =3D doc.SelectSingleNode ("/Type").Attributes ["FullName"].Inne=
rText;
-
-		return s.Substring (0, s.LastIndexOf ("."));
-	}
-=09
-	public static string GetTypeKind (XmlDocument doc)
-	{
-		XmlNode node =3D doc.SelectSingleNode ("/Type/Base/BaseTypeName");
-
-		if (node =3D=3D null){
-			if (GetFullClassName (doc) =3D=3D "System.Object")
-				return "Class";
-			return "Interface";
-		}
-
-		switch (node.InnerText){
-
-		case "System.Delegate":
-			return "Delegate";
-		case "System.ValueType":
-			return "Structure";
-		case "System.Enum":
-			return "Enumeration";
-		default:
-			return "Class";
-		}
-	}
-
-	//
-	// Utility function: converts a fully .NET qualified type name into a C#-=
looking one
-	//
+	=09
 	public static string ConvertCTSName (string type)
 	{
 		if (!type.StartsWith ("System."))
@@ -115,7 +67,6 @@
 		return type;
 	}
 }
-
 //
 // The Ecma documentation provider:
 //
@@ -160,125 +111,381 @@
 		}
 	}
=20
-	struct TypeInfo : IComparable {
-		public string type_assembly;
-		public string type_name;
-		public string type_full;
-		public string type_kind;
-		public XmlNode type_doc;
-
-		public TypeInfo (string k, string a, string f, string s, XmlNode n)
-		{
-			type_assembly =3D a;
-			type_name =3D s;
-			type_doc =3D n;
-			type_kind =3D k;
-			type_full =3D f;
+=09
+	public class TypeInfo : IComparable {
+		public string name, assembly, kind, fullclassname, baseType;
+		public string summary;
+	=09
+		public ArrayList constructors, methods, properties, fields, events;
+	=09
+		TypeInfo (XmlTextReader r)=20
+		{
+			constructors =3D new ArrayList ();
+			methods =3D new ArrayList ();
+			properties =3D new ArrayList ();
+			fields =3D new ArrayList ();
+			events =3D new ArrayList ();
+		=09
+			r.MoveToContent ();
+			ReadAttributes (r);
+			r.ReadStartElement ("Type");
+		=09
+			ReadElements (r);
+			kind =3D GetTypeKind ();
 		}
-
+	=09
 		public int CompareTo (object b)
 		{
 			TypeInfo na =3D this;
 			TypeInfo nb =3D (TypeInfo) b;
+=09
+			return String.Compare (na.fullclassname, nb.fullclassname);
+		}
+		=09
+		public static TypeInfo Parse (string file)
+		{
+			XmlTextReader r =3D new XmlTextReader (file);
+			r.WhitespaceHandling =3D WhitespaceHandling.Significant;
+=09
+			return new TypeInfo (r);
+		}
+	=09
+	=09
+		string GetTypeKind ()
+		{
+=09
+			switch (baseType) {
+				case null:
+					if (fullclassname =3D=3D "System.Object")
+						return "Class";
+					else
+						return "Interface";
+			=09
+				case "System.Delegate":
+					return "Delegate";
+				case "System.ValueType":
+					return "Structure";
+				case "System.Enum":
+					return "Enumeration";
+				default:
+					return "Class";
+			=09
+			}
+		}
+	=09
+		void ReadAttributes (XmlTextReader r)
+		{
+			name =3D r.GetAttribute ("Name");
+			fullclassname =3D r.GetAttribute ("FullName");
+		}
+	=09
+		void ReadElements (XmlTextReader r)
+		{
+			while (r.MoveToContent () =3D=3D XmlNodeType.Element) {
+			=09
+				switch (r.LocalName) {
=20
-			return String.Compare (na.type_full, nb.type_full);
+				=09
+					case "AssemblyInfo":
+						ReadAssemblyInfo (r);
+						break;
+				=09
+					case "Docs":
+						ReadDocs (r);
+						break;
+					case "Base":
+						ReadBase (r);
+						break;
+					=09
+					case "Members":
+						ReadMembers (r);
+						break;
+					/*
+					case "TypeSignature":
+					case "MemberOfLibrary":
+					case "ThreadingSafetyStatement":
+					case "ThreadSafetyStatement":
+					case "Interfaces":
+					case "TypeExcluded":
+					case "Attributes":
+					*/
+					default:
+						r.Skip ();
+						r.MoveToContent ();
+						break;
+					=09
+				}
+			}
+		}
+	=09
+		void ReadAssemblyInfo (XmlTextReader r)
+		{
+			if (r.IsEmptyElement) {
+				r.Skip ();
+				return;
+			}
+			r.ReadStartElement ("AssemblyInfo");
+			while (r.MoveToContent () =3D=3D XmlNodeType.Element) {
+			=09
+				if (r.LocalName =3D=3D "AssemblyName") {
+					assembly =3D r.ReadString ();
+					r.ReadEndElement ();
+				} else {
+					r.Skip ();
+					r.MoveToContent ();
+				}
+			}
+			r.ReadEndElement ();
 		}
+	=09
+	=09
+		void ReadDocs (XmlTextReader r)
+		{
+			if (r.IsEmptyElement) {
+				r.Skip ();
+				return;
+			}
+			r.ReadStartElement ("Docs");
+			while (r.MoveToContent () =3D=3D XmlNodeType.Element) {
+				if (r.LocalName =3D=3D "summary")=20
+					summary =3D r.ReadOuterXml ();
+				else=20
+					r.Skip ();
+					r.MoveToContent ();
+			}
+			r.ReadEndElement ();
+		}
+	=09
+=09
+		void ReadBase (XmlTextReader r)
+		{
+			if (r.IsEmptyElement) {
+				r.Skip ();
+				return;
+			}
+			r.ReadStartElement ("Base");
+			while (r.MoveToContent () =3D=3D XmlNodeType.Element) {
+				if (r.LocalName =3D=3D "BaseTypeName") {
+					baseType =3D r.ReadString ();
+					r.ReadEndElement ();
+				} else {
+					r.Skip ();
+					r.MoveToContent ();
+				}
+			}
+			r.ReadEndElement ();
+		}
+	=09
+		void ReadMembers (XmlTextReader r)
+		{
+			if (r.IsEmptyElement) {
+				r.Skip ();
+				return;
+			}
+			r.ReadStartElement ("Members");
+			=09
+			while (r.MoveToContent () =3D=3D XmlNodeType.Element) {
+				string mName, type, sig, paramsStr;
+			=09
+				mName =3D r.GetAttribute ("MemberName");
+				r.MoveToElement ();
+				r.ReadStartElement ("Member");
+=09
+				while (r.MoveToContent () =3D=3D XmlNodeType.Element) {
+					switch (r.LocalName) {
+
+						case "MemberType":
+							type =3D r.ReadString ();
+							r.ReadEndElement ();
+							break;					=09
+						case "Parameters":
+							if (r.IsEmptyElement) {
+								r.Skip ();
+								r.MoveToContent ();
+							} else {
+								r.ReadStartElement ("Parameters");
+								StringBuilder b =3D new StringBuilder ();
+							=09
+								b.Append ('(');
+							=09
+								bool first =3D true;
+=09
+								while (r.MoveToContent () =3D=3D XmlNodeType.Element) {
+									if (!first) b.Append (',');
+									first =3D false;								=09
+									b.Append (EcmaDoc.ConvertCTSName (r.GetAttribute ("Type")));
+									r.Skip ();
+								}
+							=09
+								b.Append (')');
+								r.ReadEndElement ();
+								paramsStr =3D b.ToString ();
+							}
+							break;
+						/*
+						case "Attributes":
+						case "Docs":
+						case "Excluded":
+						case "ExcludedLibrary":
+						case "MemberSignature":
+						case "MemberValue":
+						case "ReturnValue":
+						*/
+						default:
+							r.Skip ();
+							r.MoveToContent ();
+							break;
+					}
+				}
+			=09
+				r.ReadEndElement ();
+				switch (type) {
+					case "Event":
+						events.Add (mName);
+						break;
+				=09
+					case "Property":
+						properties.Add (mName);
+						break;
+				=09
+					case "Field":
+						fields.Add (mName);
+						break;
+	=09
+					case "Constructor":
+						constructors.Add (name + paramsStr);
+						break;
+	=09
+					case "Method":
+						methods.Add (mName + paramsStr);
+						break;
+				}
+			}
+			r.ReadEndElement ();
+		=09
+			events.Sort ();
+			properties.Sort ();
+			fields.Sort ();
+			constructors.Sort ();
+			methods.Sort ();
+=09
+		}
+
 	}
 =09
+=09
+        struct TypeSummary : IComparable {
+                public string type_assembly;
+                public string type_name;
+                public string type_full;
+                public string type_kind;
+                public string type_doc;
+
+                public TypeSummary (string k, string a, string f, string s=
, string n)
+                {
+                        type_assembly =3D a;
+                        type_name =3D s;
+                        type_doc =3D n;
+                        type_kind =3D k;
+                        type_full =3D f;
+                }
+
+                public int CompareTo (object b)
+                {
+                        TypeSummary na =3D this;
+                        TypeSummary nb =3D (TypeSummary) b;
+
+                        return String.Compare (na.type_full, nb.type_full)=
;
+                }
+        }
 	//
 	// Packs a file with the summary data
 	//
 	public override void CloseTree (HelpSource hs, Tree tree)
 	{
 		foreach (DictionaryEntry de in class_summaries){
-			XmlDocument doc =3D new XmlDocument ();
 			string ns =3D (string) de.Key;
-		=09
 			ArrayList list =3D (ArrayList) de.Value;
-			list.Sort();
-
-			XmlElement elements =3D doc.CreateElement ("elements");
-			doc.AppendChild (elements);
+			list.Sort ();
 		=09
-			string file =3D "xml.summary." + ns;
 			Console.Error.WriteLine ("Have {0} elements in the {1}", list.Count, ns=
);
-			foreach (TypeInfo p in list){
-				XmlElement e =3D null;
-			=09
+		=09
+			XmlTextWriter w =3D hs.PackXmlWriter ("xml.summary." + ns);
+		=09
+			w.WriteStartElement ("elements");
+
+			foreach (TypeSummary p in list){
 				switch (p.type_kind){
 				case "Class":
-					e =3D doc.CreateElement ("class");=20
+					w.WriteStartElement ("class");=20
 					break;
 				=09
 				case "Enumeration":
-					e =3D doc.CreateElement ("enum");
+					w.WriteStartElement ("enum");
 					break;
 				=09
 				case "Structure":
-					e =3D doc.CreateElement ("struct");
+					w.WriteStartElement ("struct");
 					break;
 				=09
 				case "Delegate":
-					e =3D doc.CreateElement ("delegate");
+					w.WriteStartElement ("delegate");
 					break;
 				=09
 				case "Interface":
-					e =3D doc.CreateElement ("interface");
+					w.WriteStartElement ("interface");
 					break;
 				}
-			=09
-				e.SetAttribute ("name", p.type_name);
-				e.SetAttribute ("fullname", p.type_full);
-				e.SetAttribute ("assembly", p.type_assembly);
-				XmlNode copy =3D doc.ImportNode (p.type_doc, true);
-				e.AppendChild (copy);
-				elements.AppendChild (e);
+				w.WriteAttributeString ("name", p.type_name);
+				w.WriteAttributeString ("fullname", p.type_full);
+				w.WriteAttributeString ("assembly", p.type_assembly);
+
+				w.WriteRaw (p.type_doc);
+				w.WriteEndElement ();
 			}
-			hs.PackXml ("xml.summary." + ns, doc);
+		=09
+			w.WriteEndDocument();
+			w.Flush ();
 		}
 	}
 	      =20
 	static Hashtable class_summaries =3D new Hashtable ();
 					    =20
-	XmlDocument doc;
+	XmlNode typeNode;
 =09
 	void PopulateClass (string ns, Node ns_node, string file)
 	{
-		doc =3D new XmlDocument ();
-		doc.Load (file);
-	=09
-		string name =3D EcmaDoc.GetClassName (doc);
-		string assembly =3D EcmaDoc.GetClassAssembly (doc);
-		string kind =3D EcmaDoc.GetTypeKind (doc);
-		string full =3D EcmaDoc.GetFullClassName (doc);
-
-		Node class_node;
+		TypeInfo t =3D TypeInfo.Parse (file);
 		string file_code =3D ns_node.tree.HelpSource.PackFile (file);
-
-		XmlNode class_summary =3D doc.SelectSingleNode ("/Type/Docs/summary");
+		string name =3D t.name;
+		string assembly =3D t.assembly;
+		string kind =3D t.kind;
+		string full =3D t.fullclassname;
+		string class_summary =3D t.summary;
+	=09
 		ArrayList l =3D (ArrayList) class_summaries [ns];
 		if (l =3D=3D null)
 			l =3D class_summaries [ns] =3D new ArrayList ();
-		l.Add (new TypeInfo (kind, assembly, full, name, class_summary));
-	      =20
-		class_node =3D ns_node.LookupNode (String.Format ("{0} {1}", name, kind)=
, "ecma:" + file_code + "#" + name + "/");
+	=09
+		l.Add (new TypeSummary (kind, assembly, full, name, class_summary));
=20
-		if (kind =3D=3D "Enumeration")
-			return;
=20
-		if (kind =3D=3D "Delegate")
+		Node class_node =3D ns_node.LookupNode (String.Format ("{0} {1}", name, =
kind), "ecma:" + file_code + "#" + name + "/");
+
+		if (kind =3D=3D "Enumeration" || kind =3D=3D "Delegate")=20
 			return;
 	=09
 		//
 		// Always add the Members node
 		//
 		class_node.CreateNode ("Members", "*");
+	=09
=20
-		PopulateMember (name, class_node, "Constructor", "Constructors");
-		PopulateMember (name, class_node, "Method", "Methods");
-		PopulateMember (name, class_node, "Property", "Properties");
-		PopulateMember (name, class_node, "Field", "Fields");
-		PopulateMember (name, class_node, "Event", "Events");
+		PopulateMember (t.constructors, class_node, "Constructor", "Constructors=
");
+		PopulateMember (t.methods, class_node, "Method", "Methods");
+		PopulateMember (t.properties, class_node, "Property", "Properties");
+		PopulateMember (t.fields, class_node, "Field", "Fields");
+		PopulateMember (t.events, class_node, "Event", "Events");
 	}
=20
 	class NodeIndex {
@@ -314,59 +521,19 @@
 	// Performs an XPath query on the document to extract the nodes for the v=
arious members
 	// we also use some extra text to pluralize the caption
 	//
-	void PopulateMember (string typename, Node node, string text, string plur=
al_text)
+	void PopulateMember (ArrayList items, Node node, string text, string plur=
al_text)
 	{
-		XmlNodeList list =3D doc.SelectNodes (String.Format ("/Type/Members/Memb=
er[MemberType=3D\"{0}\"]", text));
-		int count =3D list.Count;
-	=09
-		if (count =3D=3D 0)
-			return;
-
 		Node nodes_node;
 		string key =3D text.Substring (0, 1);
-		if (count =3D=3D 1)
-			nodes_node =3D node.CreateNode (text, key);
-		else
-			nodes_node =3D node.CreateNode (plural_text, key);
-
-		NodeIndex [] node_array =3D new NodeIndex [count];
+                if (items.Count =3D=3D 1)
+                        nodes_node =3D node.CreateNode (text, key);
+                else
+                        nodes_node =3D node.CreateNode (plural_text, key);
+	=09
+	=09
 		int i =3D 0;
-		foreach (XmlNode n in list)
-			node_array [i] =3D new NodeIndex (n, i++);
-		=09
-		Array.Sort (node_array, NodeComparer);
-
-		foreach (NodeIndex ni in node_array){
-			string signature;
-
-			switch (text){
-			case "Event":
-			case "Property":
-			case "Field":
-				signature =3D GetMemberName (ni.node);
-				break;
-
-			case "Constructor":
-				signature =3D EcmaHelpSource.MakeSignature(ni.node, typename);
-				break;
-
-			case "Method":
-				signature =3D EcmaHelpSource.MakeSignature(ni.node, null);
-				break;
-			=09
-			default:
-				XmlNode signode =3D ni.node.SelectSingleNode ("MemberSignature[@Langua=
ge=3D'C#']");
-		=09
-				if (signode =3D=3D null)
-					signature =3D GetMemberName (ni.node);
-				else
-					signature =3D signode.Attributes ["Value"].InnerText;
-				break;
-			}
-		=09
-			//signature =3D CleanSignature (ni.node, signature);
-
-			nodes_node.CreateNode (signature, ni.index.ToString ());
+		foreach (string s in items) {
+			nodes_node.CreateNode (s, (i++).ToString ());
 		}
 	}
=20
Index: provider.cs
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvs/public/monodoc/browser/provider.cs,v
retrieving revision 1.28
diff -u -r1.28 provider.cs
--- provider.cs	1 Jun 2003 15:26:45 -0000	1.28
+++ provider.cs	19 Jun 2003 20:14:14 -0000
@@ -470,11 +470,12 @@
=20
 		return entry_name;
 	}
-=09
-	public void PackXml (string fname, XmlDocument doc)
+	=09
+	public System.Xml.XmlTextWriter PackXmlWriter (string entry_name)
 	{
-		doc.Save ("tmp");
-		PackFile ("tmp", fname);
+		ZipEntry entry =3D new ZipEntry (entry_name);
+		zip_output.PutNextEntry (entry);
+		return new System.Xml.XmlTextWriter (zip_output, null);
 	}
 =09
 	public virtual string GetText (string url, out Node n)

--=-GcfogFs7X2qnu6bT/tli--