Функции C, используемые в python через ctypes, замедляются при добавлении условия if

#python #c #ctypes #compiler-optimization #dot-product

#python #c #ctypes #оптимизация компилятора #точка-произведение

Вопрос:

Я пытаюсь реализовать функцию C, которая перебирает набор данных (случайно сгенерированный 1 миллион векторов объектов) и обрабатывает операцию точечного произведения с заданным вектором объектов на каждой итерации. Он завершает цикл очень быстро (за ~ 0,05 мс).

c-код:

 void dotProduct(double *parameters, double *feature, double *dataset)
    {
        const int FEATURE_COUNT = parameters[0];
        const int DATASET_COUNT = parameters[1];
        const double THRESHOLD = parameters[2];
        double dotProductResu<

        for (int i = 0; i < DATASET_COUNT; i  )
        {
            dotProductResult = 0.0;
            for (int j = 0; j < FEATURE_COUNT; j  )
            {
                dotProductResult  = dataset[i*FEATURE_COUNT j] * feature[j];
            }

            // if (dotProductResult > THRESHOLD)
            // {
            //     parameters[3] = i;
            // }
        }    
    }
 

код python:

 ND_POINTER_PARAMETERS = np.ctypeslib.ndpointer(dtype=np.float64, 
                                      ndim=1,
                                      flags="C")
ND_POINTER_FEATURE = np.ctypeslib.ndpointer(dtype=np.float64, 
                                      ndim=1,
                                      flags="C")
ND_POINTER_DATASET = np.ctypeslib.ndpointer(dtype=np.float64, 
                                      ndim=2,
                                      flags="C")
dotProductLib.dotProduct.argtypes = [ND_POINTER_PARAMETERS, ND_POINTER_FEATURE, ND_POINTER_DATASET]
    
feature = np.random.rand(512,)
dataset = np.random.rand(1000000,512)
parameters = np.array([len(feature), len(dataset), 200, -1], dtype=np.float64)

t = time()
dotProductLib.dotProduct(parameters, feature, dataset)
print("---time taken C: ",1000*(time()-t), "ms")
 

Однако, когда я добавляю if условие, которое проверяет, превышает ли результат скалярного произведения заданный порог, и присваивает индекс вектора заданному адресу, скорость резко падает (~ 500 мс), хотя она никогда не входит в условие if.

Кроме того, то же самое происходит, когда я добавляю std::cout вместо присваивания переменной.

 if (dotProductResult > THRESHOLD)
{
    std::cout << dotProductResult << "n";
}
 

Более того, если я добавляю else условие и записываю тот же оператор if абсурдно или если я присваиваю любое число, это не ускоряется.

 if (dotProductResult > THRESHOLD)
{
    parameters[3] = i;
}
else
{
    parameters[3] = i;
}
 

или

 if (dotProductResult > THRESHOLD)
{
    parameters[3] = 123;
}
 

Я использую -O3 флаг.
Что я делаю не так? Есть какие-либо предложения по быстрому выполнению такой операции?

Заранее спасибо

Ответ №1:

Ваш исходный код работает быстро только потому, что он на самом деле ничего не делает! Компилятор распознает, что вы на самом деле не используете dotProductResult , поэтому функция оптимизируется буквально до нуля. Когда вы раскомментируете свое условие, теперь dotProductResult используется значение, поэтому оно должно фактически выполнять работу по вычислению точечного произведения. Если вы «добавляете else условие и записываете тот же оператор в if «, то это снова быстро, потому что компилятор понимает, что это эквивалентно этому:

 void dotProduct(double *parameters, double *feature, double *dataset)
    {
        const int DATASET_COUNT = parameters[1];

        if (DATASET_COUNT > 0)
        {
            parameters[3] = DATASET_COUNT - 1;
        }
    }
 

Поэтому он может снова перестать выполнять работу.

Комментарии:

1. Спасибо, это меня очень просветило