C# 将分析支持构建到代码中

C# 将分析支持构建到代码中,c#,profiling,C#,Profiling,我希望(我不知道是否可能)在我的代码中构建评测支持,而不是使用一些外部分析器。我听说有一些分析器api被大多数分析器编写者使用。该api可以用于从正在执行的代码中进行概要分析吗?还有其他注意事项吗?如果不想使用常规探查器,可以使用应用程序输出性能计数器 您可能会发现此博客条目对入门很有用:如果您不想使用常规探查器,可以使用应用程序输出性能计数器 您可能会发现这篇博文对入门很有用:NET framework profiler API是一个COM对象,它在.NET处理调用之前拦截调用。我的理解是,它

我希望(我不知道是否可能)在我的代码中构建评测支持,而不是使用一些外部分析器。我听说有一些分析器api被大多数分析器编写者使用。该api可以用于从正在执行的代码中进行概要分析吗?还有其他注意事项吗?

如果不想使用常规探查器,可以使用应用程序输出性能计数器


您可能会发现此博客条目对入门很有用:

如果您不想使用常规探查器,可以使用应用程序输出性能计数器


您可能会发现这篇博文对入门很有用:

NET framework profiler API是一个COM对象,它在.NET处理调用之前拦截调用。我的理解是,它不能托管在托管(C#)代码中


根据您要执行的操作,您可以插入秒表计时器来测量调用的长度,或者向应用程序添加性能计数器,以便从性能监视器监视应用程序的性能。

NET framework profiler API是一个COM对象,它在.NET处理调用之前拦截调用。我的理解是,它不能托管在托管(C#)代码中


根据您想做的事情,您可以插入秒表计时器来测量调用的长度,或者向应用程序添加性能计数器,以便可以从性能监视器监视应用程序的性能。

< P>有一个GeMeDV文章,讨论如何在C++程序中构建概要基础结构。如果在堆栈上创建的对象在退出时被释放,而不是留给垃圾收集器,那么您可以调整这种方法来处理C


即使你不能接受整个技术,也可能有一些有用的想法。

< P>有一个GeMeDo文章,讨论如何在C++程序中构建概要基础结构。如果在堆栈上创建的对象在退出时被释放,而不是留给垃圾收集器,那么您可以调整这种方法来处理C


即使你不能掌握全部技巧,也可能会有一些有用的想法。

当我不能使用我的电脑时,我所做的就是这样。它很笨拙,提供了低分辨率的信息,但它可以工作。首先,有一个字符串的全局堆栈。这是C语言,但您可以将其改编为C语言:

然后,在进入和退出每个有源代码的例程时,按下/弹出例程的名称:

void EveryFunction(){
    int iStack = nStack++; stack[iStack] = "EveryFunction";

    ... code inside function

    nStack = iStack; stack[iStack] = NULL;
}
所以现在stack[0..nStack]保留了一个正在运行的调用堆栈(减去从何处调用函数的行号),所以它不如真正的调用堆栈好,但总比没有好

现在,您需要一种在随机或伪随机时间拍摄快照的方法。使用另一个全局变量和一个例程查看它:

time_t timeToSnap;
void CheckForSnap(){
    time_t now = time(NULL);
    if (now >= timeToSnap){
        if (now - timeToSnap > 10000) timeToSnap = now; // don't take snaps since 1970
        timeToSnap += 1; // setup time for next snapshot
        // print stack to snapshot file
    }
}
现在,在整个代码中,特别是在低级例程中,零星地调用
CheckForSnap
。运行完成后,将有一个堆栈示例文件。你可以看看那些意外的行为。例如,在样本的重要部分上显示的任何函数的包含时间大致等于该部分

就像我说的,这总比什么都没有好。它确实有缺点:

  • 它不会捕获调用来自何处的行号,因此,如果您发现某个函数的时间过长,则需要在其中查找耗时的代码
  • 它本身增加了大量的开销,即对
    time(NULL)
    的所有调用,因此当您消除了所有的大问题后,将很难找到小问题
  • 如果您的程序花费大量时间等待I/O或用户输入,您将看到I/O后堆积了一堆样本。如果是文件I/O,这是有用的信息,但如果是用户输入,您将不得不丢弃这些样本,因为他们说您需要时间
了解以下几点很重要:

  • 与普遍接受的观点相反,时间测量的准确性(以及大量样本)并不重要。重要的是,示例发生在您等待程序执行其工作的过程中
  • 与公认的观点相反,您不需要寻找调用图,不需要关心递归,不需要关心任何例程需要多少毫秒或调用多少次,也不需要关心包含时间和独占时间之间的区别,或者CPU和挂钟时间之间的区别。你需要关心的是,对于任何例行程序,它在堆栈上的时间百分比是多少,因为这就是它所负责的时间,从某种意义上说,如果你能让例行程序不花费时间,那么你的总时间将减少多少

    • 当我不能使用我的电脑时,我所做的就是这样。它很笨拙,提供了低分辨率的信息,但它可以工作。首先,有一个字符串的全局堆栈。这是C语言,但您可以将其改编为C语言:

      然后,在进入和退出每个有源代码的例程时,按下/弹出例程的名称:

      void EveryFunction(){
          int iStack = nStack++; stack[iStack] = "EveryFunction";
      
          ... code inside function
      
          nStack = iStack; stack[iStack] = NULL;
      }
      
      所以现在stack[0..nStack]保留了一个正在运行的调用堆栈(减去从何处调用函数的行号),所以它不如真正的调用堆栈好,但总比没有好

      现在,您需要一种在随机或伪随机时间拍摄快照的方法。使用另一个全局变量和一个例程查看它:

      time_t timeToSnap;
      void CheckForSnap(){
          time_t now = time(NULL);
          if (now >= timeToSnap){
              if (now - timeToSnap > 10000) timeToSnap = now; // don't take snaps since 1970
              timeToSnap += 1; // setup time for next snapshot
              // print stack to snapshot file
          }
      }
      
      现在,在整个代码中,特别是在低级例程中,零星地调用
      CheckForSnap
      。运行完成后,将有一个堆栈示例文件。你可以看看那些意外的行为。例如,在样本的重要部分上显示的任何函数的包含时间大致等于该部分

      就像我说的,这总比什么都没有好。它确实有缺点:

      • 它不捕获行号