#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. Спасибо, это меня очень просветило