[Mono-devel-list] First CIL Regex performance result
Ben Maurer
bmaurer at users.sourceforge.net
Fri Feb 27 15:43:14 EST 2004
Hello,
Are you including compile time? Maybe SRE is slow.
Also, can you try generating a compiled assembly and sending it with a
test case. That would help those of us who dont have the engine set up
get it working.
-- Ben
On Fri, 2004-02-27 at 15:19, Eric Durand Tremblay wrote:
> Hello all,
>
> We have finished compiling some basic regex with our IL Compilator. All
> anchor, character matching, string matching and alternation construct
> are completed.
>
> Before we continue our work, I decided to try some benchmark to see if
> we are in the good way. The result where disastrous !!!
>
> For a simple regex like (a|b), our compiled regex is LESS efficient (
> take 150% more time ) then interpreted regex. Note that the algorythms
> used are exactly the same and that the number of matches is equal in the
> two approach.
>
> After taking some time crying, François decided to try it with the
> .net runtime. Results are as expected : OUR compiled regex are MORE
> efficient ( take 50% less time then the interpreted ones) when running
> on the .net runtime.
>
> So, we taught that maybe, mono dynamic assembly where somehow less
> efficient than .net ones. We tryed to bechmark this with absolutely no
> results.
>
> You will find a copy of the benchmarks we used attached to this mail.
>
> Then, if anybody have any idea on the subject, we will be glad to hear it.
>
> Eric Durand-Tremblay
> TIP-MONO ( a University Laval project)
> Blog : http://aeglos.dyndns.org/tip-mono
>
> ______________________________________________________________________
> using System;
> using System.Text.RegularExpressions;
> using System.IO;
>
> namespace RegexBench
> {
> class RegexBench
> {
> private string m_text;
>
> [STAThread]
> static void Main(string[] args)
> {
> TextReader reader = null;
> try
> {
> reader = File.OpenText("RegexBench.txt");
>
> RegexBench bench = new RegexBench(reader.ReadToEnd());
>
> //***
> //To test any regex, just do :
> //bench.testRegex("", false);
> //with the regex text as first parameter. To view the results of a regex, use true as second parameter.
>
> bench.testRegex("a|b", false);
> //bench.testRegex("(?<left><(?<inter>[a-zA-Z]+)>)[^<>]*</\\k<inter>>", false); //Balanced html tag (not exactly it)
> //bench.testRegex("(\\s[ab]{2,3}\\w+\\s)", false); //Random regex
> //bench.testRegex("\\w{3,5}://([\\.]|\\w|\\\\)*", false); //Simple Internet address
>
> //bench.testRegex("[abC-DefgG-Jklm]{5}", false); //Big character class
> //bench.testRegex("(\\w|(\\w\\.\\w)|(\\w_\\w)|(\\w\\-\\w))+@(\\w|(\\w\\.\\w)|(\\w_\\w)|(\\w\\-\\w))+\\.\\w{2,4}", false); //E-mail
>
>
> //Throw exception on mono
> //bench.testRegex("(?<left><(?<inter>[a-zA-Z]+)>)[^<>]*(?<right-left></\\k<inter>>)", false);//Balanced html tag (not exactly it)
> }
> catch(Exception e)
> {
> Console.WriteLine(e.Message + "\n" + e.StackTrace);
> }
> finally
> {
> try
> {
> if (reader != null)
> reader.Close();
> }
> catch(Exception){};
> }
> }
>
> public RegexBench(string text)
> {
> m_text = text;
> }
>
> //Evaluate execution time to find all results of regex "strRegex" in compiled and uncompiled mode.
> //To view regex results, put showResult to true;
> private void testRegex(string strRegex, bool showResult)
> {
> int begin;
> int end;
> int nbMatch;
> double compCompTime;
> double compInterTime;
> double compTime;
> double interTime;
> MatchCollection matches;
>
> Console.WriteLine("Testing Regex : {0}", new object[] {strRegex});
>
> //Creation
> begin = Environment.TickCount;
> Regex regex = new Regex(strRegex);
> end = Environment.TickCount;
> compInterTime = end - begin;
> Console.WriteLine("Creation of interpreted regex : {0}ms", new object[] {compInterTime});
>
>
> begin = Environment.TickCount;
> Regex regexc = new Regex(strRegex, RegexOptions.Compiled);
> end = Environment.TickCount;
> compCompTime = end - begin;
> Console.WriteLine("Compilation time : {0}ms\n", new object[] {compCompTime});
>
>
> //Interpreted Regex
> begin = Environment.TickCount;
> matches = regex.Matches(m_text);
> nbMatch = matches.Count; //Important, MS do the job here.
> end = Environment.TickCount;
> interTime = end - begin;
>
> Console.WriteLine("Elapsed time (Interpreted): {0}ms", new object[]{interTime});
> Console.WriteLine("Nb Match : {0}\n", new object[]{nbMatch});
>
>
> //Compiled Regex
> begin = Environment.TickCount;
> matches = regexc.Matches(m_text);
> nbMatch = matches.Count; //Important, MS do the job here.
> end = Environment.TickCount;
> compTime = end - begin;
>
> Console.WriteLine("Elapsed time (Compiled): {0}ms", new object[]{compTime});
> Console.WriteLine("Nb Match : {0}", new object[]{nbMatch});
>
>
> Console.WriteLine("\nInterpreted compilation ratio : {0}%", (int)(compInterTime / interTime * 100));
> Console.WriteLine("Compiled compilation ratio : {0}%", (int)(compCompTime / compTime * 100));
> Console.WriteLine("Compiled vs Interpreted (without compile time) : {0}%", (int)(compTime / interTime * 100));
> Console.WriteLine("Compiled vs Interpreted (with compile time) : {0}%", (int)((compTime + compCompTime) / (compInterTime + interTime) * 100));
>
>
> if( showResult)
> {
> for(int i=0; i<nbMatch ;i++)
> {
> Console.WriteLine(matches[i].Captures[0].Value);
> Console.WriteLine("---------------------");
> }
> }
>
> Console.WriteLine("");
> }
> }
> }
>
> ______________________________________________________________________
> // created on 2004-02-26 at 09:24
> using System;
> using System.Reflection;
> using System.Reflection.Emit;
>
> public class MainClass
> {
> public static void Main(string[] args)
> {
> try {
>
>
> int compiledTime = 0;
> int dynTime = 0;
> int begin;
> int end;
> long res1 = 0 ;
> long res2 = 0;
> EmitTestFactory factory = new EmitTestFactory();
>
> EmitTestBase compiled = factory.getEmitTest(false);
> EmitTestBase dynamic = factory.getEmitTest(true);
>
>
>
>
> for ( int i = 0; i<=200; i++)
> {
> begin = Environment.TickCount;
> res1 = compiled.EmitTest();
> end = Environment.TickCount;
> compiledTime += end - begin;
> }
>
> compiledTime = compiledTime / 200;
> Console.WriteLine("Time for the compiled call {0}ms" , compiledTime);
>
> for ( int i = 0; i<=200; i++)
> {
> begin = Environment.TickCount;
> res2 = dynamic.EmitTest();
> end = Environment.TickCount;
> dynTime += end - begin;
> }
>
>
> dynTime = dynTime / 200;
>
> Console.WriteLine("Time for the dynamic call {0}ms ",dynTime);
> Console.WriteLine(res1);
> Console.WriteLine(res2);
>
> Console.WriteLine("Compiled vs Dynamic : {0}%", (int)(dynTime /compiledTime* 100));
> }
> catch (Exception e)
> {
> //System.Diagnostics.Debugger.Break();
> Console.WriteLine(e.Message + "\n" + e.StackTrace);
>
>
>
> }
>
>
>
> }
>
> }
>
> public class EmitTestFactory
> {
> public EmitTestBase getEmitTest(bool dynamic)
> {
> if (dynamic)
> {
> Type t = this.CreateType();
> asmBuilder.Save("Test.dll");
> return (EmitTestBase)Activator.CreateInstance(t);
> //return new EmitTest1();
> }
> else
> {
> return new EmitTest1();
> }
> }
>
> private AssemblyBuilder asmBuilder;
> private Type CreateType()
> {
> // Get the current application domain for the current thread.
> AppDomain currentDomain = AppDomain.CurrentDomain;
>
> AssemblyName asmName = new AssemblyName();
> asmName.Name = "Test.dll";
>
>
> // Define a dynamic assembly in the current application domain.
> asmBuilder = currentDomain.DefineDynamicAssembly (asmName, AssemblyBuilderAccess.RunAndSave);
>
> // Define a dynamic module in this assembly.
> ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("DynModule", asmName.Name);
>
> // Define a runtime class with specified name and attributes.
> TypeBuilder builder = modBuilder.DefineType("EmitTest2" ,
> TypeAttributes.Public ,
> typeof(EmitTestBase),
> new Type[]{typeof(EmitTestInter)});
>
>
> //Define default constructor
> ConstructorBuilder ctorBuilder = builder.DefineConstructor(MethodAttributes.Public,
> CallingConventions.Standard,
> new Type[] {});
> ILGenerator ctorILGen = ctorBuilder.GetILGenerator();
>
>
>
> ctorILGen.Emit(OpCodes.Ldarg_0);
> ctorILGen.Emit(OpCodes.Call,
> typeof(EmitTestBase).GetConstructor(BindingFlags.Instance |
> BindingFlags.NonPublic,
> null,
> new Type[]{},
> null));
> ctorILGen.Emit(OpCodes.Ret);
>
>
>
> MethodBuilder methodBuilder = builder.DefineMethod("EmitTest", MethodAttributes.Public | MethodAttributes.Virtual ,
> typeof(long),
> new Type[]{});
>
> builder.DefineMethodOverride(methodBuilder, typeof(EmitTestInter).GetMethod("EmitTest"));
> ILGenerator iLGen = methodBuilder.GetILGenerator();
>
> Label IL_001c = iLGen.DefineLabel();
> Label IL_0010 = iLGen.DefineLabel();
> Label IL_000c = iLGen.DefineLabel();
> Label IL_0008 = iLGen.DefineLabel();
>
>
>
>
> // .method public hidebysig virtual instance void
> // EmitTest() cil managed
> //{
> // // Code size 40 (0x28)
> // .maxstack 2
>
> // .locals init ([0] int32 i,
> // [1] int64 j)
>
> LocalBuilder i = iLGen.DeclareLocal(typeof(int));
> LocalBuilder j = iLGen.DeclareLocal(typeof(int));
> LocalBuilder e = iLGen.DeclareLocal(typeof(long));
> // IL_0000: ldc.i4 0xffff8000
> // IL_0005: stloc.0
> iLGen.Emit(OpCodes.Ldc_I4, (int)0);
> iLGen.Emit(OpCodes.Stloc_0);
> // IL_0006: br.s IL_001c
> iLGen.Emit(OpCodes.Br_S, IL_001c);
> // IL_0008: ldc.i4.0
> // IL_0009: stloc.1
> iLGen.MarkLabel(IL_0008);
> iLGen.Emit(OpCodes.Ldc_I4, (int)0);
> iLGen.Emit(OpCodes.Stloc_1);
> // IL_000a: br.s IL_0010
> iLGen.Emit(OpCodes.Br_S, IL_0010);
>
>
> // IL_000c: ldloc.1
> // IL_000d: ldc.i4.1
> // IL_000e: add
> // IL_000f: stloc.1
> iLGen.MarkLabel(IL_000c);
>
> iLGen.Emit(OpCodes.Ldloc_2);
> iLGen.Emit(OpCodes.Ldc_I4_1);
> iLGen.Emit(OpCodes.Conv_U8);
>
> iLGen.Emit(OpCodes.Add);
> iLGen.Emit(OpCodes.Stloc_2);
>
> iLGen.Emit(OpCodes.Ldloc_1);
> iLGen.Emit(OpCodes.Ldc_I4_1);
> iLGen.Emit(OpCodes.Add);
> iLGen.Emit(OpCodes.Stloc_1);
> // IL_0010: ldloc.1
> // IL_0011: ldc.i4 0x7fff
> // IL_0016: ble.s IL_000c
> iLGen.MarkLabel(IL_0010);
> iLGen.Emit(OpCodes.Ldloc_1);
> iLGen.Emit(OpCodes.Ldc_I4, (int)200);
> iLGen.Emit(OpCodes.Ble_S, IL_000c);
> // IL_0018: ldloc.0
> // IL_0019: ldc.i4.1
> // IL_001a: add
> // IL_001b: stloc.0
> iLGen.Emit(OpCodes.Ldloc_0);
> iLGen.Emit(OpCodes.Ldc_I4_1);
> iLGen.Emit(OpCodes.Add);
> iLGen.Emit(OpCodes.Stloc_0);
>
> // IL_001c: ldloc.0
> // IL_001d: ldc.i4 0x7fff
> // IL_0022: ble.s IL_0008
> iLGen.MarkLabel(IL_001c);
> iLGen.Emit(OpCodes.Ldloc_0);
> iLGen.Emit(OpCodes.Ldc_I4, (int)Int16.MaxValue);
> iLGen.Emit(OpCodes.Ble_S, IL_0008);
> // IL_0024: ret
>
> // iLGen.EmitWriteLine(e);
> iLGen.Emit(OpCodes.Ldloc_2);
> iLGen.Emit(OpCodes.Ret);
> //} // end of method EmitTest1::EmitTest
>
>
>
> return builder.CreateType();
> }
> }
>
>
> interface EmitTestInter
> {
> long EmitTest();
> }
>
> public abstract class EmitTestBase : EmitTestInter
> {
> abstract public long EmitTest();
> }
>
> public class EmitTest1 : EmitTestBase
> {
> public override long EmitTest()
> {
> int i;
> int j;
> long e = 0;
> for (i = 0; i <= Int16.MaxValue; i++)
> for ( j = 0; j <= 200; j++)
> e++;
> // Console.WriteLine(e);
> return e;
> }
> }
More information about the Mono-devel-list
mailing list