Ограничение указателей и встраивания

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

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

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

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

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

Чтобы запустить программу (в реальном режиме), не забудьте использовать аргументы 0 1000 2000. Почему использование аргументов пользовательского ввода/программы должно быть уверенным, что компилятор не может знать, есть или нет псевдонимы между указателями а, б и в.

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

person Boll    schedule 15.07.2012    source источник
comment
+1 за хорошие методы профилирования. Я предпочитаю не жаловаться на спецификатор формата. P.S. clock возвращает clock_t, а не time_t.   -  person    schedule 16.07.2012
comment
Попробуйте защитить вызов функции, проверив, что смещения достаточно велики. Вам, вероятно, придется использовать настоящие int переменные для хранения смещений, а не хак, который вы использовали.   -  person    schedule 16.07.2012
comment
@Hurkyl Я думал, что clock_t и time_t — это определения типов для одного и того же, но вы правы. (Кстати, как мне отредактировать свой вопрос-пост?)   -  person Boll    schedule 16.07.2012
comment
Я пытался защитить его как с операторами if, так и с __assume, но безуспешно. Но __declspec(noinline), на который указал Mystical, работает.   -  person Boll    schedule 16.07.2012


Ответы (1)


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

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

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


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

person Mysticial    schedule 15.07.2012
comment
Это решение работает как в тестовом коде в вопросе, так и в моем реальном приложении. Но будут некоторые проблемы, если очень маленькая функция, которая вызывается много раз, нуждается в ограниченных квалифицированных указателях, где __declspec(noinline) вызовет довольно большие накладные расходы на вызов. Поэтому я подожду, приняв это как лучший ответ. - person Boll; 16.07.2012
comment
Да, я знаю, что ты имеешь в виду. Я предполагаю, что анализ псевдонимов указателей, используемый в VS2010, осуществляется только на уровне функций. Таким образом, он не может отличить указатели без псевдонимов, которые генерируются в середине функции. Я не уверен, что restrict можно использовать для локально объявленных указателей. Если это так, это может быть что-то попробовать. - person Mysticial; 16.07.2012
comment
Вы совершенно правы, и я безуспешно пытался использовать локально объявленные указатели с ограничением. Ваш __declspec(noinline) является лучшим решением и работает в моем текущем случае (моем приложении), поэтому я принимаю его как ответ. Спасибо. - person Boll; 16.07.2012