2012-07-15 3 views
7

Я попытался использовать ограниченные указатели, и я столкнулся с проблемой. Программа, приведенная ниже, просто проста, чтобы представить проблему.Ограничительные указатели и inlining

Функция calc_function использует три указателя, которые ограничены, поэтому они «НЕ ДОЛЖНЫ» не совпадать друг с другом. При компиляции этого кода в visual studio функция будет встроена, поэтому без причины Visual Studio 2010 игнорирует квалификаторы. Если я отключу inlining, код будет выполняться более чем в шесть раз быстрее (с 2200 до 360 мс). Но я не хочу отключать вложение во весь проект или весь файл (потому что тогда это будет накладные расходы на вызов, например, на все геттеры и сеттеры, что было бы ужасно).

(Might единственным решением будет отключить встраивание только этой функции?)

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

Я был бы признателен за помощь в решении этой проблемы с оптимизацией.

Для запуска программы (в realeasemode) не забудьте использовать аргументы 0 1000 2000. Почему использование аргументов userinput/program должно быть уверенным, что компилятор не может знать, есть ли или нет? t сглаживание между указателями a, b и c.

#include <cstdlib> 
#include <cstdio> 
#include <ctime> 

// Data-table where a,b,c will point into, so the compiler cant know if they alias. 
const size_t listSize = 10000; 
int data[listSize]; 

//void calc_function(int * a, int * b, int * c){ 
void calc_function(int *__restrict a, int *__restrict b, int *__restrict c){ 
    for(size_t y=0; y<1000*1000; ++y){ // <- Extra loop to be able to messure the time. 
     for(size_t i=0; i<1000; ++i){ 
      *a += *b; 
      *c += *a; 
     } 
    } 
} 
int main(int argc, char *argv[]){ // argv SHALL be "0 1000 2000" (with no quotes) 
    // init 
    for(size_t i=0; i<listSize; ++i) 
     data[i] = i; 

    // get a, b and c from argv(0,1000,2000) 
    int *a,*b,*c; 
    sscanf(argv[1],"%d",&a); 
    sscanf(argv[2],"%d",&b); 
    sscanf(argv[3],"%d",&c); 
    a = data + int(a); // a, b and c will (after the specified argv) be, 
    b = data + int(b); // a = &data[0], b = &data[1000], c = &data[2000], 
    c = data + int(c); // So they will not alias, and the compiler cant know. 

    // calculate and take time 
    time_t start = clock(); 
     funcResticted(a,b,c); 
    time_t end = clock(); 
    time_t t = (end-start); 
    printf("funcResticted  %u (microSec)\n", t); 

    system("PAUSE"); 
    return EXIT_SUCCESS; 
} 
+1

+1 для хорошей практики профилирования. Я не хочу жаловаться на спецификатор формата. Постскриптум 'clock' возвращает' clock_t', а не 'time_t'. – Hurkyl

+1

Попытайтесь защитить вызов функции с проверкой того, что смещения достаточно велики. Вероятно, вам придется использовать реальные переменные 'int', чтобы хранить смещения, а не используемый вами хак. – Hurkyl

+0

@Hurkyl Я думал, что clock_t и time_t были оба typedefs для одного и того же, но вы правы. (Btw, как мне изменить свой вопрос-сообщение?) – Boll

ответ

3

Если вы объявляете функцию с __declspec(noinline), это заставит его не быть встраиваемое:

http://msdn.microsoft.com/en-us/library/kxybs02x%28v=vs.80%29.aspx

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


Что касается restrict, компилятор волен использовать его только тогда, когда он хочет. Так что возиться с разными версиями одного и того же кода несколько неизбежно при попытке «обмануть» компиляторы для такой оптимизации.

+0

Это решение работает как в тестовом коде в вопросе, так и в моем реальном приложении. Но будут некоторые проблемы, если очень маленькая функция, называемая много раз, нуждается в ограниченных квалифицированных указателях, где __declspec (noinline) заставит довольно большие накладные расходы. Поэтому я буду ждать, приняв это как лучший ответ. – Boll

+0

Да, я знаю, что вы имеете в виду. Я предполагаю, что анализ сглаживания указателей, используемый в VS2010, только на уровне детализации на уровне функций. Таким образом, он не может отличить указатели сглаживания, которые «сгенерированы» в середине функции. Я не уверен, что 'ограничить' можно использовать для локально объявленных указателей. Если да, то может быть что-то попробовать. – Mysticial

+0

Вы совершенно правы, и я попытался использовать локально объявленные указатели с ограничением без везения.Ваш «__declspec (noinline)» является лучшим решением и работает в моем текущем случае (мое приложение), поэтому я принимаю его как ответ. Благодарю. – Boll

Смежные вопросы