【问题标题】:Measure Compilation Time For Each Method On C#在 C# 上测量每个方法的编译时间
【发布时间】:2015-02-11 13:09:41
【问题描述】:

我们将创建一个性能对我们非常重要的 Web 服务。因此我们决定了测量每种方法的编译时间。

我们要拦截每个方法并记录编译时间。但是我们不想更改发布的代码。那么如何才能让这个拦截器只在调试模式下运行呢?

【问题讨论】:

  • 你为什么不pre-JIT一切?
  • @Sriram 因为它不需要像 NGen 那样的安装后步骤。您可以更轻松地进行部署。但我同意 NGen 是更好的选择,如果您可以接受维护费用。
  • CLR 中的 JIT 编译每个方法只发生一次(与 Java HotSpot 不同)。而且由于您有一个 Web 服务,它实际上只启动一次。由于这些原因,我认为 JIT 编译开销在这种情况下并不重要,但我可能错了。
  • 我非常怀疑测量任何东西的编译时间是否会以任何方式帮助你。
  • 如果你想测量,你可以使用内置的 PerformanceCounter,它有 JIT 时间的计数器

标签: c# performance interceptor


【解决方案1】:

这是计算类中每个方法的拦截器。 (它使用 log4net)

internal class DurationCalculatorAspect : IMessageSink
{
   public bool ExceptionHandlingEnabled { get; set; }

    internal DurationCalculatorAspect(IMessageSink next,bool exceptionHandlingEnabled)
    {
        m_next = next;
        ExceptionHandlingEnabled = exceptionHandlingEnabled;
    }

    private IMessageSink m_next;
    #region IMessageSink implementation
    public IMessageSink NextSink
    {

        get { return m_next; }
    }

    public IMessage SyncProcessMessage(IMessage msg)
    {
        var typeResolver = ((System.Type[])(((System.Collections.ArrayList)msg.Properties.Values)[2]));
        var typeName = "void";
        if(typeResolver.Count()!=0)
        {
            typeName = typeResolver[0].FullName;
        }

        var argsString = "";
        var argArray =(object[])((System.Collections.ArrayList)msg.Properties.Values)[4];
        for (int i = 0;i<argArray.Length;i++)
        {
            argsString+=(i+1).ToString() + ". Object : " +argArray[i];
        }
        Logger.GetLogger().Debug("MethodName : "+((System.Collections.ArrayList)msg.Properties.Values)[1]+"\r\n"+
            "TypeName: " + typeName + "\r\n" + "Args : " + argsString
            );
        var date1 = DateTime.Now;


      var  returnMethod =
        m_next.SyncProcessMessage(msg);

        var returnMessage = ((IMethodReturnMessage)returnMethod);

        var date2 = DateTime.Now;
        Logger.GetLogger().Debug("MethodName : " + returnMessage.MethodName + "Duration : " + date2.Subtract(date1).TotalMilliseconds + " .ms"+"\r\n"+
            "TypeName: " + typeName + "\r\nReturned : " +returnMessage.ReturnValue);

        if (returnMessage.Exception != null)
        {
            Logger.GetLogger().Fatal("Exception : " + returnMessage.Exception.Data + " InnerException : " + returnMessage.Exception.InnerException);
            if (ExceptionHandlingEnabled)
            {
                return new ReturnMessage(null, null);
            }
        }


        return returnMethod;
    }

    public IMessageCtrl AsyncProcessMessage(IMessage msg,
    IMessageSink replySink)
    {
        throw new InvalidOperationException();
    }

    #endregion //IMessageSink implementation

}

public class DurationCalculatorInterceptorProperty : IContextProperty,
IContributeObjectSink
{
    public bool ExceptionHandlingEnabled { get; set; }

    public DurationCalculatorInterceptorProperty(bool exceptionHandlingEnabled)
    {
        ExceptionHandlingEnabled = exceptionHandlingEnabled;
    }

    #region IContributeObjectSink implementation
    public IMessageSink GetObjectSink(MarshalByRefObject o,
    IMessageSink next)
    {
        return new DurationCalculatorAspect(next,ExceptionHandlingEnabled);
    }
    #endregion // IContributeObjectSink implementation

    #region IContextProperty implementation
    // Implement Name, Freeze, IsNewContextOK
    #endregion //IContextProperty implementation


    public void Freeze(Context newContext)
    {
    }

    public bool IsNewContextOK(Context newCtx)
    {
        return true;
    }

    public string Name
    {
        get { return ""; }
    }
}

[AttributeUsage(AttributeTargets.Class)]
public class DurationCalculatorInterceptorAttribute : ContextAttribute
{
    public bool ExceptionHandlingEnabled { get; set; }

    public DurationCalculatorInterceptorAttribute(bool exceptionHandlingEnabled) : base("Security")
    {
        ExceptionHandlingEnabled = exceptionHandlingEnabled;
    }

    public override void GetPropertiesForNewContext(
    IConstructionCallMessage ccm)
    {
        ccm.ContextProperties.Add(new DurationCalculatorInterceptorProperty(ExceptionHandlingEnabled));

    }
}

下面给出了两个使用拦截来记录持续时间的类和一个用于处理异常的类。奇怪的是,使用这个拦截器处理异常的速度快了 28 倍。但它仅对仅记录异常有用。也不要忘记你的类要继承 ContextBoundObject。

[DurationCalculatorInterceptor(false)]
public class WithoutExceptionHandling : ContextBoundObject
{
    public void DivideYeahWithoutExceptionHandling()
    {

        for (int i = 0; i < 1000000; i++)
        {
            try
            {
                var x = 2;
                var y = 1;

                var z = x / (y - 1);
            }
            catch (Exception)
            {


            }
        }

    }
}
[DurationCalculatorInterceptor(true)]
public class WithExceptionHandling : ContextBoundObject
{
    public void DivideYeahWithExceptionHandling()
    {
        for (int i = 0; i < 1000000; i++)
        {
            var x = 2;
            var y = 1;
            var z = x / (y - 1);
        }
    }
}

【讨论】:

    猜你喜欢
    • 2019-06-20
    • 1970-01-01
    • 2017-09-28
    • 2011-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-10
    相关资源
    最近更新 更多