2014-01-28 3 views
1

У меня есть алгоритм, который требует построения матрицы NxN внутри функции, которая вернет произведение этой матрицы с вектором Nx1, который также построен на лету. (N обычно 8 или 9, но его необходимо обобщать для значений, больших этого).Операции с собственной матрицей C++ и производительность распределения памяти

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

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

Таким образом, Eigen либо предлагает обходное решение, потому что я не вижу возможности передать распределитель в качестве аргумента шаблона для этих объектов, ИЛИ есть ли более очевидная вещь?

+0

ли 'изменение N' между вызовами? Если да, то как вы подготовили этот «глобальный объект», когда не знаете, что такое «N»? – luk32

+0

N не изменяется между вызовами. Он зависит от модели входных данных, из которой создается обработанный объект. – teodron

+0

Тогда, возможно, вы можете сделать свой «менеджер ресурсов» «статичным» в своей функции. В противном случае глобальное сложно избежать ИМО. Думаю, это не должно быть очень сложно. Вам нужно уйти с чем-то простым, то есть с сборкой мусора или любыми чистыми взлетами. – luk32

ответ

3

Вы можете управлять своей собственной памятью в соответствии с вашими потребностями и использовать Eigen::Map вместо Eigen::Matrix для выполнения расчетов с ней. Просто убедитесь, что данные правильно выровнены или уведомить Eigen, если это не так.

Подробнее см. Ссылку Eigen::Map.

Вот небольшой пример:

#include <iostream> 
#include <Eigen/Core> 


int main() { 
    int mydata[3 * 4]; // Manage your own memory as you see fit 
    int* data_ptr = mydata; 

    Eigen::Map<Eigen::MatrixXi, Eigen::Unaligned> mymatrix(data_ptr, 3, 4); 

    // use mymatrix like you would any another matrix 
    mymatrix = Eigen::MatrixXi::Zero(3, 4); 
    std::cout << mymatrix << '\n'; 

    // This line will trigger a failed assertion in debug mode 
    // To change it see 
    // http://eigen.tuxfamily.org/dox-devel/TopicAssertions.html 
    mymatrix = Eigen::MatrixXi::Ones(3, 6); 


    std::cout << mymatrix << '\n'; 
} 
0

Вы могли бы выделить память для некоторой общей матрицы размером перед тем вызовом этой функции с operator new или operator new[], хранить void* указатели где-то и пусть сама функция извлечения блока памяти с правильным размером. После этого вы можете использовать новое размещение для построения матрицы. Подробности приведены в Более эффективный C++, п. 8.

+2

Возможно, это не так просто, если применимо вообще. Поскольку 'eigen' использует свои внутренние распределители, чтобы позаботиться о выравнивании памяти. Я также не думаю, что есть функция, чтобы получить объем памяти, занимаемый собственным «объектом». – luk32

2

Чтобы собрать мои комментарии в полной идее. Вот как я попытаюсь это сделать.

Поскольку распределение памяти в собственном состоянии - довольно продвинутый материал IMO, и они не раскрывают много мест, чтобы использовать его. Лучше всего обернуть собственные объекты в какой-то менеджер ресурсов, например, OP.

Я бы сделал это простой контейнер, который содержит Matrix< Scalar, Dynamic, Dynamic> объектов. Таким образом, вы создаете шаблон Scalar и имеете менеджера для обобщенных матриц размеров.

Всякий раз, когда вы вызываете объект, вы проверяете, есть ли у вас свободный объект желаемого размера, вы возвращаете ссылку на него. Если нет, вы назначаете новый. Просто. когда вы хотите освободить объект, тогда вы помечаете его бесплатно в диспетчере ресурсов. Я не думаю, что нужно что-то более сложное, но, конечно, можно реализовать еще более сложную логику.

Для обеспечения безопасности потоков я бы поставил замок в менеджере. При необходимости инициализируйте его в конструкторе. Конечно, потребуется блокировка на free и allocate.

Однако в зависимости от графика работы. Если потоки работают на своих собственных массивах, я бы подумал сделать один экземпляр диспетчера ресурсов для каждого потока, поэтому они не синхронизируют друг друга. Дело в том, что глобальная блокировка или глобальный менеджер, возможно, исчерпаются, если у вас есть 12 ядер, которые тяжело работают на распределения/освобождения, и эффективно сериализуют ваше приложение, блокируя эту блокировку.

1

Вы можете попробовать заменить распределитель памяти по умолчанию на jemalloc или tcmalloc. Это довольно легко попробовать благодаря механизму LD_PRELOAD.

Я думаю, что это работает для большинства проектов C++, а также.

+0

Ничего себе, спасибо, рассмотрим эти альтернативы. – teodron

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