Scope Guard в C - PullRequest
       15

Scope Guard в C

4 голосов
/ 19 января 2010

Я хотел бы использовать охрану области видимости в C для выполнения профилирования.

Я хотел бы знать, сколько времени я провожу в функции. Вот что я делаю:

int function() {

  tic();

  ... do stuff ...
  if (something)
  {
    toc();
    return 0;
   }

  toc();
  return 1;
}

Мне нужно помещать оператор toc каждый раз, когда я выхожу из функции. Я хотел бы сделать это без необходимости копировать вставить ток везде. Есть ли общий способ сделать это, используя макрос или что-то? Также я не хочу менять способ вызова функции, так как мне нужно профилировать множество функций.

Спасибо

Ответы [ 7 ]

5 голосов
/ 19 января 2010

Это не меняет способ вызова функции.Вероятно, не очень полезно, если вы хотите иметь возможность профилировать каждую функцию.

static inline int real_function() {
    // previous contents of function(), with no tic or toc
}

int function() {
    tic();
    int r = real_function();
    toc();
    return r;
}

Как и все остальные говорят: используйте профилировщик, это сэкономит вам много усилий в долгосрочной перспективе.Как они не говорят: если у вашей платформы есть такая.

Если ее нет, то проще всего было бы сказать (как правило кодирования), что функции должны иметь только одну точку выхода, и этот выходточка должна быть через ваш макрос.Затем вы можете вручную оборудовать все свои функции кодом при входе и выходе.Устаревшие функции с множественными возвратами можно свернуть, как указано выше.

Также имейте в виду, что когда вы делаете что-то подобное, ваш компилятор может вас испортить.Вы могли бы написать это:

tic();
do_something();
int i = something_else();
toc();
return i;

Если компилятор определит, чтоthing_else не имеет побочных эффектов, то даже несмотря на то, что somebody_else занимает значительное время, он может превратить код в это:

tic();
do_something();
toc();
return something_else();

А данные вашего профиля будут недооценивать время, потраченное на вашу функцию.Еще одна причина, по которой так хорошо иметь настоящий профилировщик - он может взаимодействовать с компилятором.

4 голосов
/ 19 января 2010

Почему бы не использовать реальный инструмент профилирования, такой как gprof ?

4 голосов
/ 19 января 2010

Вы можете определить макрос как:

#define TOC_RETURN(x) \
    do { \
    toc(); \
    return x; \
    } while(0)

, который должен работать везде, где вы положили. Затем вы можете автоматизировать замену return *; на TOC_RETURN(*).

2 голосов
/ 19 января 2010

Вы можете просто " переопределить " возврат через макрос: (см. Отказ от ответственности)

#include <stdio.h>

void tic() { printf("tic\n"); }
void toc() { printf("toc\n"; }

#define return toc(); return
int foo() {
    tic();

    return 0;
}
#undef return

int main() {
    foo();
    return 0;
}

Отказ от ответственности: Это можно считать уродливым и смешным, потому что:

  • Это не будет работать для пустых функций, если вы не используете return; -statements.
  • Он может быть не переносимым / стандартным, даже если он работает на MSVC8.
  • Не следует определять ключевые слова.
1 голос
/ 19 января 2010

Настоящему профилировщику не нужно, чтобы вы модифицировали код, просто чтобы скомпилировать его с включенным профилированием.

1 голос
/ 19 января 2010

Я бы не рекомендовал макрос для этого. Вы профилируете код только время от времени, и замена return на какой-то специальный макрос только для этой цели делает код менее читабельным.

Не лучше ли сделать следующее?

tic();
call_function();
toc();

Это автоматически обрабатывает «все точки выхода» из функции.

P.S. Почему вы не используете профилировщик?

0 голосов
/ 19 января 2010

Хм, может быть обернуть вызов функции в макрос (семейство макросов, правда)? Вот тот, который не принимает аргументов и возвращает Retval:

// define the wrapper for name
#define DEFTIMECALL0(Retval,name) \
    Retval timed##name() \
    { \
        Retval ret;
        tic(); \
        ret = name(); \
        toc(); \
        return ret; \
    }

Вам понадобятся макросы для каждого набора вызовов функций, с версией Retval и void, возвращающей.

Редактировать Возможно, нет даже смысла в определении функции-оболочки, и лучше просто иметь семейство макросов (опять же, для каждой версии arity и возвращаемого типа / void), которые переносят функцию Звоните в тик / ток прямо на места вызова

Не бойтесь инструментов профилировщиков, которые по сути делают это для вас.

...