Как ускорить выделение большого куска памяти?
От: Mazay Россия  
Дата: 16.11.14 13:37
Оценка: :))) :))
Программа при запуске выделяет большой кусок памяти (512 ГБ) под массив double-ов. Сейчас это делается вот так:
vector <double> vect(N);


Это занимает около 10 минут времени при 100% загрузке одного ядра.

Компилятор — g++ 4.8
OS — CentOS 7

Можно ли как-то ускорить это дело? Распараллелить например. Что там вообще менеджер кучи так долго делает?
Главное гармония ...
Re: Как ускорить выделение большого куска памяти?
От: Pavel Dvorkin Россия  
Дата: 16.11.14 13:45
Оценка:
Здравствуйте, Mazay, Вы писали:

M>Программа при запуске выделяет большой кусок памяти (512 ГБ) под массив double-ов. Сейчас это делается вот так:


Точно Гигабайт ? 512 ? А сколько RAM на машине ?
With best regards
Pavel Dvorkin
Re: Как ускорить выделение большого куска памяти?
От: ononim  
Дата: 16.11.14 13:46
Оценка:
M>Программа при запуске выделяет большой кусок памяти (512 ГБ) под массив double-ов. Сейчас это делается вот так:
M>
M>vector <double> vect(N);
M>

M>Это занимает около 10 минут времени при 100% загрузке одного ядра.
M>Что там вообще менеджер кучи так долго делает?
...свопится, наверное
Как много веселых ребят, и все делают велосипед...
Re[2]: Как ускорить выделение большого куска памяти?
От: Mazay Россия  
Дата: 16.11.14 13:56
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, Mazay, Вы писали:


M>>Программа при запуске выделяет большой кусок памяти (512 ГБ) под массив double-ов. Сейчас это делается вот так:


PD>Точно Гигабайт ? 512 ? А сколько RAM на машине ?


Один террабайт. Там кроме этого мегавектора есть ещё несколько помельче. В пике получается около 85% памяти занято.
Главное гармония ...
Re[2]: Как ускорить выделение большого куска памяти?
От: Mazay Россия  
Дата: 16.11.14 13:57
Оценка:
Здравствуйте, ononim, Вы писали:

M>>Программа при запуске выделяет большой кусок памяти (512 ГБ) под массив double-ов. Сейчас это делается вот так:

M>>
M>>vector <double> vect(N);
M>>

M>>Это занимает около 10 минут времени при 100% загрузке одного ядра.
M>>Что там вообще менеджер кучи так долго делает?
O>...свопится, наверное

Не Там террабайт памяти. В своп точно не уходит.
Главное гармония ...
Re[3]: Как ускорить выделение большого куска памяти?
От: Pavel Dvorkin Россия  
Дата: 16.11.14 14:33
Оценка:
Здравствуйте, Mazay, Вы писали:

PD>>Точно Гигабайт ? 512 ? А сколько RAM на машине ?


M>Один террабайт. Там кроме этого мегавектора есть ещё несколько помельче. В пике получается около 85% памяти занято.


Под Windows решение простое — VirtualAlloc. Под линукс см. здесь

http://linux.die.net/man/3/valloc
With best regards
Pavel Dvorkin
Re: Как ускорить выделение большого куска памяти?
От: cures Россия cures.narod.ru
Дата: 16.11.14 15:58
Оценка: 6 (1) +1
Здравствуйте, Mazay, Вы писали:

M> Что там вообще менеджер кучи так долго делает?


А точно менеджер кучи тупит, а не забивание этой памяти дефолтными нулями? Цапните её стандартным маллоком, он ничем не заполняет. Если не поможет — вручную ммапом.
И общий совет при таких размерах: включите HugeTLB хотя бы двухметровое, а можно попробовать и гигабайтное.
Насчёт не свопится — тоже лучше проверить, оно и профилактически может, отключите все своп-разделы.
В любом случае очень подозрительно, даже если заполнение, скорость меньше гига в секунду — это странно.
Вы точно не под валгриндом пускаетесь? Или у Вас винда?
Re: Как ускорить выделение большого куска памяти?
От: smeeld  
Дата: 16.11.14 16:42
Оценка: 4 (1) +1
Здравствуйте, Mazay, Вы писали:

M>Программа при запуске выделяет большой кусок памяти (512 ГБ) под массив double-ов. Сейчас это делается вот так:

M>vector <double> vect(N);
M>Это занимает около 10 минут времени при 100% загрузке одного ядра.

Когда делаете так vector <double> vect(N); запускается это

template<typename _ForwardIterator, typename _Size, typename _Allocator>
  void
  __uninitialized_default_n_a(_ForwardIterator __first, _Size __n,
  _Allocator& __alloc)
  {
  _ForwardIterator __cur = __first;
  __try
  {
  typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
  for (; __n > 0; --__n, ++__cur)
  __traits::construct(__alloc, std::__addressof(*__cur));
  }
  __catch(...)
  {
  std::_Destroy(__first, __cur, __alloc);
  __throw_exception_again;
  }
 }


что быстро выполнится при больших N не может.

M>Можно ли как-то ускорить это дело? Распараллелить например. Что там вообще менеджер кучи так долго делает?


Да, делайте просто malloc() без этих stl дурковатостей.
Re: Как ускорить выделение большого куска памяти?
От: uzhas Ниоткуда  
Дата: 16.11.14 20:27
Оценка: 4 (1)
Здравствуйте, Mazay, Вы писали:

M>Можно ли как-то ускорить это дело?


гипотеза:
используй new[]
std::vector инициализирует нулями всю эту память в цикле, что и занимает столько времени
Re[2]: Как ускорить выделение большого куска памяти?
От: cures Россия cures.narod.ru
Дата: 16.11.14 20:30
Оценка:
Здравствуйте, smeeld, Вы писали:

S>что быстро выполниться при больших N не может.


Интересно, что этот construct делает, и можно ли его попросить этого не делать?
По крайней мере, new раньше спокойно оставлял примитивные типы неинициализированными, а vector так не умеет?

S>Да, делайте просто malloc() без этих stl дурковатостей.


Можно с придурковатостями, в shared_ptr засунуть, но после malloc
Другой вопрос — нужен ли в программе этот здоровый массив? Если его нулями заливает 10 минут, то какое время займёт его обычное использование? Если 10 минут — ничтожная доля в общем времени, то имеем классическую причину всех зол, по Кнуту. Если доля существенная, то массив как таковой практически не исползуется, только небольшие его участки, и его хорошо бы заменить на подходящую структуру меньшего размера.
А если его таки надо забить изначально нулями, то может быть проще его в .bss завести, система сама инициализирует, если умная — аппаратно. Ну или правда через OpenMP распараллелить, обычно в машине несколько каналов к памяти, может в несколько раз ускориться. Или memset позвать, вдруг он что-то знает
Re[3]: Как ускорить выделение большого куска памяти?
От: uzhas Ниоткуда  
Дата: 16.11.14 20:34
Оценка:
Здравствуйте, cures, Вы писали:

C>По крайней мере, new раньше спокойно оставлял примитивные типы неинициализированными, а vector так не умеет?


вектор не умеет
Re: Как ускорить выделение большого куска памяти?
От: Fagin  
Дата: 16.11.14 20:47
Оценка: :))
Здравствуйте, Mazay, Вы писали:

M>Программа при запуске выделяет большой кусок памяти (512 ГБ) под массив double-ов.


Я тут покурю в сторонке.

M>Можно ли как-то ускорить это дело?


Не совсем по делу просто вспомнилось:

Урок в итальянской школе.
— Джованни, сколько будет дважды два?
— Мне бы Ваши заботы, господин учитель!

Re[3]: Как ускорить выделение большого куска памяти?
От: smeeld  
Дата: 17.11.14 00:21
Оценка:
Здравствуйте, cures, Вы писали:

C>Интересно, что этот construct делает, и можно ли его попросить этого не делать?


Тупо зовёт __alloc.construct() который в std::allocator такой

 template<typename _Up, typename... _Args>
  void
  construct(_Up* __p, _Args&&... __args)
  { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }


Если его заменить пустышкой, то это всё равно не избавит от самого цикла, к тому же, vector станет
кастрированным, вся инициализация элементов в push*, emplace*, insert проводится через __alloc.construct()
Re[2]: Как ускорить выделение большого куска памяти?
От: MTimur  
Дата: 17.11.14 10:24
Оценка:
Здравствуйте, cures, Вы писали:
C>В любом случае очень подозрительно, даже если заполнение, скорость меньше гига в секунду — это странно.
Оно примерно так и работает 512ГБ ~600 секунд
Re[3]: Как ускорить выделение большого куска памяти?
От: MTimur  
Дата: 17.11.14 10:31
Оценка:
Здравствуйте, cures, Вы писали:
C>то имеем классическую причину всех зол, по Кнуту. Если доля существенная, то массив как таковой практически не исползуется, только небольшие его участки, и его хорошо бы заменить на подходящую структуру меньшего размера.

Там по ходу программа запускается 10 минут. А учитывая 1ТБ памяти, оно еще и сервер. А значит программа, скорее всего — служба.
Если все так, то оптимизировать уже пора
Re[4]: Как ускорить выделение большого куска памяти?
От: cures Россия cures.narod.ru
Дата: 17.11.14 10:32
Оценка:
Здравствуйте, smeeld, Вы писали:

S>Если его заменить пустышкой, то это всё равно не избавит от самого цикла,


Пустой цикл выкинется оптимизатором, да и 64 миллиарда итераций не займут 10 минут, от силы — одну

S> к тому же, vector станет кастрированным, вся инициализация элементов в push*, emplace*, insert проводится через __alloc.construct()


Это же чудесно! Можно будет пользоваться как нормальным массивом.
А если не совсем пустышкой, скажем, перекрыть размещающий new для конкретного типа double?
Re[4]: Как ускорить выделение большого куска памяти?
От: cures Россия cures.narod.ru
Дата: 17.11.14 10:37
Оценка:
Здравствуйте, MTimur, Вы писали:

MT>Там по ходу программа запускается 10 минут. А учитывая 1ТБ памяти, оно еще и сервер. А значит программа, скорее всего — служба.

MT>Если все так, то оптимизировать уже пора

Если служба, то работает 24*7, нет смысла оптимизировать запуск
Да и где это виданы самописные службы на терабайт?
"Это служба — так уж служба, тут нужна моя вся дружба!"
Но всё же хотелось бы послушать начальника транспортного цеха.

MT> Оно примерно так и работает 512ГБ ~600 секунд


Обычно скорость работы с памятью не меньше 2 гигов в секунду, даже в один канал. Тут видимо ещё цикл не оптимизировался и мимо ТЛБ всё время ходят.
Отредактировано 17.11.2014 10:41 cures . Предыдущая версия .
Re[5]: Как ускорить выделение большого куска памяти?
От: smeeld  
Дата: 17.11.14 10:56
Оценка:
Здравствуйте, cures, Вы писали:

C>Это же чудесно! Можно будет пользоваться как нормальным массивом.


Зачем тогда vector, когда достаточно просто массива? Или всем отделом смеяться будут? Типа modern C++ не осилил.
И цикл будет не пустой, Вы ведь не реализацию std::vector будете корректировать, а просто назначите свой allocator,
вместо дефолтного, с пустым методом construct, который и будет вызываться в цикле, и пустота которого предотвратит
выделение реальных страничных фреймов в ядре в момент создания vector.

C>А если не совсем пустышкой, скажем, перекрыть размещающий new для конкретного типа double?


Это и есть пустышка, если не будет производиться запись любого значения по адресу std::__addressof(*__cur).
Re[5]: Как ускорить выделение большого куска памяти?
От: uzhas Ниоткуда  
Дата: 17.11.14 11:26
Оценка:
Здравствуйте, cures, Вы писали:

C>А если не совсем пустышкой, скажем, перекрыть размещающий new для конкретного типа double?

научите перекрывать
Re: Как ускорить выделение большого куска памяти?
От: push  
Дата: 17.11.14 12:46
Оценка: -1
Так вы кроме выделения ещё и инициализацию делаете. Используйте reserve() — это как раз и есть просто выделение памяти.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.