4

How can you measure the amount of time a function will take to execute?

This is a relatively short function and the execution time would probably be in the millisecond range.

This particular question relates to an embedded system, programmed in C or C++.

4

12 に答える 12

10

組み込みシステムでこれを行う最良の方法は、関数に入るときに外部ハードウェアピンを設定し、関数を出るときにそれをクリアすることです。これは、結果をあまり歪めないように、できれば少しのアセンブリ命令で実行されます。

編集:利点の1つは、実際のアプリケーションで実行でき、特別なテストコードが不要なことです。そのような外部デバッグピンは、すべての組み込みシステムの標準的な方法です(そうあるべきです!)。

于 2008-09-16T02:36:25.263 に答える
9

There are three potential solutions:

Hardware Solution:

Use a free output pin on the processor and hook an oscilloscope or logic analyzer to the pin. Initialize the pin to a low state, just before calling the function you want to measure, assert the pin to a high state and just after returning from the function, deassert the pin.


    *io_pin = 1;
    myfunc();
    *io_pin = 0;

Bookworm solution:

If the function is fairly small, and you can manage the disassembled code, you can crack open the processor architecture databook and count the cycles it will take the processor to execute every instructions. This will give you the number of cycles required.
Time = # cycles * Processor Clock Rate / Clock ticks per instructions

This is easier to do for smaller functions, or code written in assembler (for a PIC microcontroller for example)

Timestamp counter solution:

Some processors have a timestamp counter which increments at a rapid rate (every few processor clock ticks). Simply read the timestamp before and after the function. This will give you the elapsed time, but beware that you might have to deal with the counter rollover.

于 2008-09-16T02:44:45.180 に答える
4

大量の呼び出しを含むループで呼び出してから、呼び出しの数で割って平均時間を取得します。

それで:

// begin timing
for (int i = 0; i < 10000; i++) {
    invokeFunction();
}
// end time
// divide by 10000 to get actual time.
于 2008-09-16T02:33:51.197 に答える
4

if you're using linux, you can time a program's runtime by typing in the command line:

time [funtion_name]

if you run only the function in main() (assuming C++), the rest of the app's time should be negligible.

于 2008-09-16T02:42:11.067 に答える
3

関数呼び出しを何回も (何百万回も) 繰り返しますが、次の方法を使用してループのオーバーヘッドを減らします。

start = getTicks();

repeat n times {
    myFunction();
    myFunction();
}

lap = getTicks();

repeat n times {
    myFunction();
}

finish = getTicks();

// overhead + function + function
elapsed1 = lap - start;

// overhead + function
elapsed2 = finish - lap;

// overhead + function + function - overhead - function = function
ntimes = elapsed1 - elapsed2;

once = ntimes / n; // Average time it took for one function call, sans loop overhead

function() を最初のループで 2 回呼び出し、2 番目のループで 1 回呼び出す代わりに、最初のループで 1 回だけ呼び出し、2 番目のループではまったく呼び出さない (つまり、空のループ) こともできますが、空のループはコンパイラによって最適化され、負のタイミング結果が得られます:)

于 2008-10-01T15:47:57.430 に答える
2
start_time = timer
function()
exec_time = timer - start_time
于 2008-09-16T02:32:30.373 に答える
2

Windows XP/NT Embedded or Windows CE/Mobile

You an use the QueryPerformanceCounter() to get the value of a VERY FAST counter before and after your function. Then you substract those 64-bits values and get a delta "ticks". Using QueryPerformanceCounterFrequency() you can convert the "delta ticks" to an actual time unit. You can refer to MSDN documentation about those WIN32 calls.

Other embedded systems

Without operating systems or with only basic OSes you will have to:

  • program one of the internal CPU timers to run and count freely.
  • configure it to generate an interrupt when the timer overflows, and in this interrupt routine increment a "carry" variable (this is so you can actually measure time longer than the resolution of the timer chosen).
  • before your function you save BOTH the "carry" value and the value of the CPU register holding the running ticks for the counting timer you configured.
  • same after your function
  • substract them to get a delta counter tick.
  • from there it is just a matter of knowing how long a tick means on your CPU/Hardware given the external clock and the de-multiplication you configured while setting up your timer. You multiply that "tick length" by the "delta ticks" you just got.

VERY IMPORTANT Do not forget to disable before and restore interrupts after getting those timer values (bot the carry and the register value) otherwise you risk saving incorrect values.

NOTES

  • This is very fast because it is only a few assembly instructions to disable interrupts, save two integer values and re-enable interrupts. The actual substraction and conversion to real time units occurs OUTSIDE the zone of time measurement, that is AFTER your function.
  • You may wish to put that code into a function to reuse that code all around but it may slow things a bit because of the function call and the pushing of all the registers to the stack, plus the parameters, then popping them again. In an embedded system this may be significant. It may be better then in C to use MACROS instead or write your own assembly routine saving/restoring only relevant registers.
于 2008-09-16T03:01:05.827 に答える
2

組み込みプラットフォームと、探しているタイミングのタイプによって異なります。組み込み Linux の場合、実現できる方法がいくつかあります。関数が使用する CPU 時間を測定する場合は、次のようにします。

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

#define SEC_TO_NSEC(s) ((s) * 1000 * 1000 * 1000)

int work_function(int c) {
    // do some work here
    int i, j;
    int foo = 0;
    for (i = 0; i < 1000; i++) {
        for (j = 0; j < 1000; j++) {
            for ^= i + j;
        }
    }
}

int main(int argc, char *argv[]) {
    struct timespec pre;
    struct timespec post;
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &pre);
    work_function(0);
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &post);

    printf("time %d\n",
        (SEC_TO_NSEC(post.tv_sec) + post.tv_nsec) -
        (SEC_TO_NSEC(pre.tv_sec) + pre.tv_nsec));
    return 0;
}

これをリアルタイム ライブラリとリンクする必要があります。以下を使用してコードをコンパイルします。

gcc -o test test.c -lrt

clock_gettimeSMP ベースのシステムでこのコードを実行すると、テストが無効になる可能性があるいくつかの問題があるため、man ページを読むこともできます。sched_setaffinity()またはコマンドラインのようなものを使用cpusetして、コードを 1 つのコアのみに強制することができます。

ユーザー時間とシステム時間を測定する場合はtimes(NULL)、 jiffies のような値を返す を使用できます。または、 のパラメーターをclock_gettime()からCLOCK_THREAD_CPUTIME_IDに変更することもできますCLOCK_MONOTONICが、 でのラップ アラウンドに注意してCLOCK_MONOTONICください。

他のプラットフォームについては、ご自身で行ってください。

ドリュー

于 2008-09-16T03:27:17.433 に答える
2

私は常に割り込み駆動のティッカー ルーチンを実装しています。これにより、起動後のミリ秒数をカウントするカウンターが更新されます。次に、GetTickCount() 関数を使用してこのカウンターにアクセスします。

例:

#define TICK_INTERVAL 1    // milliseconds between ticker interrupts
static unsigned long tickCounter;

interrupt ticker (void)  
{
    tickCounter += TICK_INTERVAL;
    ...
}

unsigned in GetTickCount(void)
{
    return tickCounter;
}

コードでは、次のようにコードの時間を計ります。

int function(void)
{
    unsigned long time = GetTickCount();

    do something ...

    printf("Time is %ld", GetTickCount() - ticks);
}
于 2008-10-01T15:28:38.240 に答える
1

サブミリ秒の解像度を探している場合は、これらのタイミング方法のいずれかを試してください。それらはすべて、少なくとも数十または数百マイクロ秒で解像度を取得します。

Linuxが組み込まれている場合は、Linuxタイマーを確認してください。

http://linux.die.net/man/3/clock_gettime

エンベデッドJava、nanoTime()を見てください。ただし、これがエンベデッドエディションにあるかどうかはわかりません。

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/System.html#nanoTime()

ハードウェアカウンターを取得したい場合は、PAPIを試してください。

http://icl.cs.utk.edu/papi/

それ以外の場合は、いつでもアセンブラに移動できます。これについてサポートが必要な場合は、アーキテクチャのPAPIソースを確認できます。

于 2008-09-16T02:36:43.700 に答える
1

OS Xターミナル(そしておそらくUnixも)では、「時間」を使用します。

time python function.py
于 2008-09-16T02:37:23.527 に答える
1

コードが.Netの場合は、DateTime.Nowではなくストップウォッチクラス(.net 2.0以降)を使用します。DateTime.Nowは十分に正確に更新されておらず、クレイジーな結果が得られます

于 2008-09-16T02:39:15.630 に答える