将分析支持构建到代码中

发布于 2024-08-12 05:24:58 字数 104 浏览 1 评论 0原文

我希望(我不知道是否可能)在我的代码中构建分析支持,而不是使用一些外部分析器。我听说大多数探查器编写者都使用一些探查器 API。该 API 可以用于从正在执行的代码中进行分析吗?还有其他考虑吗?

I wish (I dont know if its possible) to build profiling support into my code instead of using some external profiler. I have heard that there is some profiler api that is used by most of the profiler writers. Can that api be used to profile from within the code that is being executed? Are there any other considerations?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

佼人 2024-08-19 05:24:58

如果您不想使用常规分析器,则可以使用应用程序输出性能计数器。

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

If you don't want to use a regular profiler, you could have your application output performance counters.

You may find this blog entry useful to get started: Link

戏剧牡丹亭 2024-08-19 05:24:58

EQATEC 分析器构建应用程序的检测版本,该版本将完全自行运行和收集分析统计信息 - 您不需要附加分析器。默认情况下,您的应用程序只会将统计信息转储到纯文本 xml 文件中。

这意味着您可以构建应用程序的配置文件版本,将其部署在客户的站点上,让他们运行它并将统计报告发送回给您。他们不需要安装任何特殊的东西或运行分析器或任何东西。

此外,如果您可以通过网络连接到达已部署的应用程序的计算机,并且它允许传入连接,那么您甚至可以坐在家里使用分析器自己拍摄正在运行的分析应用程序的快照。您所需要的只是一个套接字连接 - 您自己决定端口号,并且控制协议本身是普通的 http,因此它很可能甚至可以通过内容过滤网关。

The EQATEC Profiler builds an instrumented version of your app that will run and collect profiling statistics entirely by itself - you don't need to attach the profiler. By default your app will simply dump the statistics into plaintext xml-files.

This means that you can build a profiled version of your app, deploy it at your customer's site, and have them run it and send back the statistics-reports to you. No need for them to install anything special or run a profiler or anything.

Also, if you can reach your deployed app's machine via a network-connection and it allows incoming connections then you can even take snapshots of the running profiled app yourself, sitting at home with the profiler. All you need is a socket-connection - you decide the port-number yourself and the control-protocol itself is plain http, so it's pretty likely to make it past even content-filtering gateways.

稳稳的幸福 2024-08-19 05:24:58

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

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

The .NET framework profiler API is a COM object that intercepts calls before .NET handles them. My understanding is that it cannot be hosted in managed (C#) code.

Depending on what you want to do, you can insert Stopwatch timers to measure length of calls, or add Performance Counters to your application so that you can monitor the performance of the application from the Performance Monitor.

挥剑断情 2024-08-19 05:24:58

有一篇 GameDev 文章讨论了如何在 C++ 程序中构建分析基础结构。您可以采用此方法来使用 C#,前提是在退出时释放堆栈上创建的对象,而不是留给垃圾收集器

http://www.gamedev.net/reference/programming/features/enginuity3/

即使您无法掌握整个技术,也可能有一些有用的想法。

There's a GameDev article that discusses how to build profiling infrastructure in a C++ program. You may be able to adapt this approach to work with C# provided objects created on the stack are freed on exit instead of left for the garbage collector

http://www.gamedev.net/reference/programming/features/enginuity3/

Even if you can't take the whole technique, there may be some useful ideas.

少女净妖师 2024-08-19 05:24:58

当我无法使用我的最喜欢的技术是这个。它很笨拙并且提供低分辨率信息,但它确实有效。首先,有一个全局字符串堆栈。这是用 C 编写的,但您可以将其改编为 C#:

int nStack = 0;
char* stack[10000];

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

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时间和挂钟时间之间的区别。对于任何例程,您需要关心的是它在堆栈上的时间百分比,因为这就是它负责的时间,从某种意义上说,如果您可以以某种方式使这个例行公事不需要时间,这就是你的总时间会减少多少。

What I've done when I can't use my favorite technique is this. It's clumsy and gives low-resolution information, but it works. First, have a global stack of strings. This is in C, but you can adapt it to C#:

int nStack = 0;
char* stack[10000];

Then, on entry and exit to each routine you have source code for, push/pop the name of the routine:

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

    ... code inside function

    nStack = iStack; stack[iStack] = NULL;
}

So now stack[0..nStack] keeps a running call stack (minus the line numbers of where functions are called from), so it's not as good as a real call stack, but better than nothing.

Now you need a way to take snapshots of it at random or pseudo-random times. Have another global variable and a routine to look at it:

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
    }
}

Now, sprinkle calls to CheckForSnap throughout your code, especially in the low-level routines. When the run is finished, you have a file of stack samples. You can look at those for unexpected behavior. For example, any function showing up on a significant fraction of samples has inclusive time roughly equal to that fraction.

Like I said, this is better than nothing. It does have shortcomings:

  • It does not capture line-numbers where calls come from, so if you find a function with suspiciously large time, you need to rummage within it for the time-consuming code.
  • It adds significant overhead of it's own, namely all the calls to time(NULL), so when you have removed all your big problems, it will be harder to find the small ones.
  • If your program spends significant time waiting for I/O or for user input, you will see a bunch of samples piled up after that I/O. If it's file I/O, that's useful information, but if it's user input, you will have to discard those samples, because all they say is that you take time.

It is important to understand a few things:

  • Contrary to popular accepted wisdom, accuracy of time measurement (and thus a large number of samples) is not important. What is important is that samples occur during the time when you are waiting for the program to do its work.
  • Also contrary to accepted wisdom, you are not looking for a call graph, you don't need to care about recursion, you don't need to care about how many milliseconds any routine takes or how many times it is called, and you don't need to care about the distinction between inclusive and exclusive time, or the distinction between CPU and wall-clock time. What you do need to care about is, for any routine, what percent of time it is on the stack, because that is how much time it is responsible for, in the sense that if you could somehow make that routine take no time, that is how much your total time would decrease.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文